* minibuf.texi (Basic Completion): Clarify list form of completion table.
[emacs.git] / src / nsterm.m
blob2df0e1a1ad5ca97e7baeae881e49c246dfa7d851
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 "termopts.h"
59 #include "termchar.h"
61 #include "window.h"
62 #include "keyboard.h"
63 #include "buffer.h"
64 #include "font.h"
66 /* call tracing */
67 #if 0
68 int term_trace_num = 0;
69 #define NSTRACE(x)        fprintf (stderr, "%s:%d: [%d] " #x "\n",         \
70                                 __FILE__, __LINE__, ++term_trace_num)
71 #else
72 #define NSTRACE(x)
73 #endif
75 #if defined (NS_IMPL_COCOA) && \
76   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
77 #define NEW_STYLE_FS
78 #endif
80 extern NSString *NSMenuDidBeginTrackingNotification;
82 /* ==========================================================================
84     Local declarations
86    ========================================================================== */
88 /* Convert a symbol indexed with an NSxxx value to a value as defined
89    in keyboard.c (lispy_function_key). I hope this is a correct way
90    of doing things... */
91 static unsigned convert_ns_to_X_keysym[] =
93   NSHomeFunctionKey,            0x50,
94   NSLeftArrowFunctionKey,       0x51,
95   NSUpArrowFunctionKey,         0x52,
96   NSRightArrowFunctionKey,      0x53,
97   NSDownArrowFunctionKey,       0x54,
98   NSPageUpFunctionKey,          0x55,
99   NSPageDownFunctionKey,        0x56,
100   NSEndFunctionKey,             0x57,
101   NSBeginFunctionKey,           0x58,
102   NSSelectFunctionKey,          0x60,
103   NSPrintFunctionKey,           0x61,
104   NSExecuteFunctionKey,         0x62,
105   NSInsertFunctionKey,          0x63,
106   NSUndoFunctionKey,            0x65,
107   NSRedoFunctionKey,            0x66,
108   NSMenuFunctionKey,            0x67,
109   NSFindFunctionKey,            0x68,
110   NSHelpFunctionKey,            0x6A,
111   NSBreakFunctionKey,           0x6B,
113   NSF1FunctionKey,              0xBE,
114   NSF2FunctionKey,              0xBF,
115   NSF3FunctionKey,              0xC0,
116   NSF4FunctionKey,              0xC1,
117   NSF5FunctionKey,              0xC2,
118   NSF6FunctionKey,              0xC3,
119   NSF7FunctionKey,              0xC4,
120   NSF8FunctionKey,              0xC5,
121   NSF9FunctionKey,              0xC6,
122   NSF10FunctionKey,             0xC7,
123   NSF11FunctionKey,             0xC8,
124   NSF12FunctionKey,             0xC9,
125   NSF13FunctionKey,             0xCA,
126   NSF14FunctionKey,             0xCB,
127   NSF15FunctionKey,             0xCC,
128   NSF16FunctionKey,             0xCD,
129   NSF17FunctionKey,             0xCE,
130   NSF18FunctionKey,             0xCF,
131   NSF19FunctionKey,             0xD0,
132   NSF20FunctionKey,             0xD1,
133   NSF21FunctionKey,             0xD2,
134   NSF22FunctionKey,             0xD3,
135   NSF23FunctionKey,             0xD4,
136   NSF24FunctionKey,             0xD5,
138   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
139   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
140   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
142   NSTabCharacter,               0x09,
143   0x19,                         0x09,  /* left tab->regular since pass shift */
144   NSCarriageReturnCharacter,    0x0D,
145   NSNewlineCharacter,           0x0D,
146   NSEnterCharacter,             0x8D,
148   0x1B,                         0x1B   /* escape */
151 static Lisp_Object Qmodifier_value;
152 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper;
153 extern Lisp_Object Qcursor_color, Qcursor_type, Qns, Qleft;
155 static Lisp_Object QUTF8_STRING;
157 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
158    the maximum font size to NOT antialias.  On GNUstep there is currently
159    no way to control this behavior. */
160 float ns_antialias_threshold;
162 /* Used to pick up AppleHighlightColor on OS X */
163 NSString *ns_selection_color;
165 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
166 NSString *ns_app_name = @"Emacs";  /* default changed later */
168 /* Display variables */
169 struct ns_display_info *x_display_list; /* Chain of existing displays */
170 Lisp_Object ns_display_name_list;
171 long context_menu_value = 0;
173 /* display update */
174 NSPoint last_mouse_motion_position;
175 static NSRect last_mouse_glyph;
176 static Time last_mouse_movement_time = 0;
177 static Lisp_Object last_mouse_motion_frame;
178 static EmacsScroller *last_mouse_scroll_bar = nil;
179 static struct frame *ns_updating_frame;
180 static NSView *focus_view = NULL;
181 static int ns_window_num = 0;
182 #ifdef NS_IMPL_GNUSTEP
183 static NSRect uRect;
184 #endif
185 static BOOL gsaved = NO;
186 BOOL ns_in_resize = NO;
187 static BOOL ns_fake_keydown = NO;
188 int ns_tmp_flags; /* FIXME */
189 struct nsfont_info *ns_tmp_font; /* FIXME */
190 static BOOL ns_menu_bar_is_hidden = NO;
191 /*static int debug_lock = 0; */
193 /* event loop */
194 static BOOL send_appdefined = YES;
195 static NSEvent *last_appdefined_event = 0;
196 static NSTimer *timed_entry = 0;
197 static NSTimer *scroll_repeat_entry = nil;
198 static fd_set select_readfds, select_writefds;
199 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
200 static int select_nfds = 0, select_valid = 0;
201 static EMACS_TIME select_timeout = { 0, 0 };
202 static int selfds[2] = { -1, -1 };
203 static pthread_mutex_t select_mutex;
204 static int apploopnr = 0;
205 static NSAutoreleasePool *outerpool;
206 static struct input_event *emacs_event = NULL;
207 static struct input_event *q_event_ptr = NULL;
208 static int n_emacs_events_pending = 0;
209 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
210   *ns_pending_service_args;
211 static BOOL ns_do_open_file = NO;
213 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
214 #define NS_FUNCTION_KEY_MASK 0x800000
215 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
216 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
217 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
218 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
219 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
220 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
221 #define EV_MODIFIERS(e)                               \
222     ((([e modifierFlags] & NSHelpKeyMask) ?           \
223            hyper_modifier : 0)                        \
224      | (!EQ (ns_right_alternate_modifier, Qleft) && \
225         (([e modifierFlags] & NSRightAlternateKeyMask) \
226          == NSRightAlternateKeyMask) ? \
227            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
228      | (([e modifierFlags] & NSAlternateKeyMask) ?                 \
229            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
230      | (([e modifierFlags] & NSShiftKeyMask) ?     \
231            shift_modifier : 0)                        \
232      | (!EQ (ns_right_control_modifier, Qleft) && \
233         (([e modifierFlags] & NSRightControlKeyMask) \
234          == NSRightControlKeyMask) ? \
235            parse_solitary_modifier (ns_right_control_modifier) : 0) \
236      | (([e modifierFlags] & NSControlKeyMask) ?      \
237            parse_solitary_modifier (ns_control_modifier) : 0)     \
238      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
239            parse_solitary_modifier (ns_function_modifier) : 0)    \
240      | (!EQ (ns_right_command_modifier, Qleft) && \
241         (([e modifierFlags] & NSRightCommandKeyMask) \
242          == NSRightCommandKeyMask) ? \
243            parse_solitary_modifier (ns_right_command_modifier) : 0) \
244      | (([e modifierFlags] & NSCommandKeyMask) ?      \
245            parse_solitary_modifier (ns_command_modifier):0))
247 #define EV_UDMODIFIERS(e)                                      \
248     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
249      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
250      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
251      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
252      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
253      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
254      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
255      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
256      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
258 #define EV_BUTTON(e)                                                         \
259     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
260       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
261      [e buttonNumber] - 1)
263 /* Convert the time field to a timestamp in milliseconds. */
264 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
266 /* This is a piece of code which is common to all the event handling
267    methods.  Maybe it should even be a function.  */
268 #define EV_TRAILER(e)                                                   \
269     {                                                                   \
270       XSETFRAME (emacs_event->frame_or_window, emacsframe);             \
271       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
272       if (q_event_ptr)                                                  \
273         {                                                               \
274           n_emacs_events_pending++;                                     \
275           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
276         }                                                               \
277       else                                                              \
278         kbd_buffer_store_event (emacs_event);                           \
279       EVENT_INIT (*emacs_event);                                        \
280       ns_send_appdefined (-1);                                          \
281     }
283 void x_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
285 /* TODO: get rid of need for these forward declarations */
286 static void ns_condemn_scroll_bars (struct frame *f);
287 static void ns_judge_scroll_bars (struct frame *f);
288 void x_set_frame_alpha (struct frame *f);
291 /* ==========================================================================
293     Utilities
295    ========================================================================== */
298 static Lisp_Object
299 append2 (Lisp_Object list, Lisp_Object item)
300 /* --------------------------------------------------------------------------
301    Utility to append to a list
302    -------------------------------------------------------------------------- */
304   Lisp_Object array[2];
305   array[0] = list;
306   array[1] = Fcons (item, Qnil);
307   return Fnconc (2, &array[0]);
311 const char *
312 ns_etc_directory (void)
313 /* If running as a self-contained app bundle, return as a string the
314    filename of the etc directory, if present; else nil.  */
316   NSBundle *bundle = [NSBundle mainBundle];
317   NSString *resourceDir = [bundle resourcePath];
318   NSString *resourcePath;
319   NSFileManager *fileManager = [NSFileManager defaultManager];
320   BOOL isDir;
322   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
323   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
324     {
325       if (isDir) return [resourcePath UTF8String];
326     }
327   return NULL;
331 const char *
332 ns_exec_path (void)
333 /* If running as a self-contained app bundle, return as a path string
334    the filenames of the libexec and bin directories, ie libexec:bin.
335    Otherwise, return nil.
336    Normally, Emacs does not add its own bin/ directory to the PATH.
337    However, a self-contained NS build has a different layout, with
338    bin/ and libexec/ subdirectories in the directory that contains
339    Emacs.app itself.
340    We put libexec first, because init_callproc_1 uses the first
341    element to initialize exec-directory.  An alternative would be
342    for init_callproc to check for invocation-directory/libexec.
345   NSBundle *bundle = [NSBundle mainBundle];
346   NSString *resourceDir = [bundle resourcePath];
347   NSString *binDir = [bundle bundlePath];
348   NSString *resourcePath, *resourcePaths;
349   NSRange range;
350   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
351   NSFileManager *fileManager = [NSFileManager defaultManager];
352   NSArray *paths;
353   NSEnumerator *pathEnum;
354   BOOL isDir;
356   range = [resourceDir rangeOfString: @"Contents"];
357   if (range.location != NSNotFound)
358     {
359       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
360 #ifdef NS_IMPL_COCOA
361       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
362 #endif
363     }
365   paths = [binDir stringsByAppendingPaths:
366                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
367   pathEnum = [paths objectEnumerator];
368   resourcePaths = @"";
370   while ((resourcePath = [pathEnum nextObject]))
371     {
372       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
373         if (isDir)
374           {
375             if ([resourcePaths length] > 0)
376               resourcePaths
377                 = [resourcePaths stringByAppendingString: pathSeparator];
378             resourcePaths
379               = [resourcePaths stringByAppendingString: resourcePath];
380           }
381     }
382   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
384   return NULL;
388 const char *
389 ns_load_path (void)
390 /* If running as a self-contained app bundle, return as a path string
391    the filenames of the site-lisp, lisp and leim directories.
392    Ie, site-lisp:lisp:leim.  Otherwise, return nil.  */
394   NSBundle *bundle = [NSBundle mainBundle];
395   NSString *resourceDir = [bundle resourcePath];
396   NSString *resourcePath, *resourcePaths;
397   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
398   NSFileManager *fileManager = [NSFileManager defaultManager];
399   BOOL isDir;
400   NSArray *paths = [resourceDir stringsByAppendingPaths:
401                               [NSArray arrayWithObjects:
402                                          @"site-lisp", @"lisp", @"leim", nil]];
403   NSEnumerator *pathEnum = [paths objectEnumerator];
404   resourcePaths = @"";
406   /* Hack to skip site-lisp.  */
407   if (no_site_lisp) resourcePath = [pathEnum nextObject];
409   while ((resourcePath = [pathEnum nextObject]))
410     {
411       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
412         if (isDir)
413           {
414             if ([resourcePaths length] > 0)
415               resourcePaths
416                 = [resourcePaths stringByAppendingString: pathSeparator];
417             resourcePaths
418               = [resourcePaths stringByAppendingString: resourcePath];
419           }
420     }
421   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
423   return NULL;
426 static void
427 ns_timeout (int usecs)
428 /* --------------------------------------------------------------------------
429      Blocking timer utility used by ns_ring_bell
430    -------------------------------------------------------------------------- */
432   EMACS_TIME wakeup = add_emacs_time (current_emacs_time (),
433                                       make_emacs_time (0, usecs * 1000));
435   /* Keep waiting until past the time wakeup.  */
436   while (1)
437     {
438       EMACS_TIME timeout, now = current_emacs_time ();
439       if (EMACS_TIME_LE (wakeup, now))
440         break;
441       timeout = sub_emacs_time (wakeup, now);
443       /* Try to wait that long--but we might wake up sooner.  */
444       pselect (0, NULL, NULL, NULL, &timeout, NULL);
445     }
449 void
450 ns_release_object (void *obj)
451 /* --------------------------------------------------------------------------
452     Release an object (callable from C)
453    -------------------------------------------------------------------------- */
455     [(id)obj release];
459 void
460 ns_retain_object (void *obj)
461 /* --------------------------------------------------------------------------
462     Retain an object (callable from C)
463    -------------------------------------------------------------------------- */
465     [(id)obj retain];
469 void *
470 ns_alloc_autorelease_pool (void)
471 /* --------------------------------------------------------------------------
472      Allocate a pool for temporary objects (callable from C)
473    -------------------------------------------------------------------------- */
475   return [[NSAutoreleasePool alloc] init];
479 void
480 ns_release_autorelease_pool (void *pool)
481 /* --------------------------------------------------------------------------
482      Free a pool and temporary objects it refers to (callable from C)
483    -------------------------------------------------------------------------- */
485   ns_release_object (pool);
490 /* ==========================================================================
492     Focus (clipping) and screen update
494    ========================================================================== */
496 static NSRect
497 ns_resize_handle_rect (NSWindow *window)
499   NSRect r = [window frame];
500   r.origin.x = r.size.width - RESIZE_HANDLE_SIZE;
501   r.origin.y = 0;
502   r.size.width = r.size.height = RESIZE_HANDLE_SIZE;
503   return r;
508 // Window constraining
509 // -------------------
511 // To ensure that the windows are not placed under the menu bar, they
512 // are typically moved by the call-back constrainFrameRect. However,
513 // by overriding it, it's possible to inhibit this, leaving the window
514 // in it's original position.
516 // It's possible to hide the menu bar. However, technically, it's only
517 // possible to hide it when the application is active. To ensure that
518 // this work properly, the menu bar and window constraining are
519 // deferred until the application becomes active.
521 // Even though it's not possible to manually move a window above the
522 // top of the screen, it is allowed if it's done programmatically,
523 // when the menu is hidden. This allows the editable area to cover the
524 // full screen height.
526 // Test cases
527 // ----------
529 // Use the following extra files:
531 //    init.el:
532 //       ;; Hide menu and place frame slightly above the top of the screen.
533 //       (setq ns-auto-hide-menu-bar t)
534 //       (set-frame-position (selected-frame) 0 -20)
536 // Test 1:
538 //    emacs -Q -l init.el
540 //    Result: No menu bar, and the title bar should be above the screen.
542 // Test 2:
544 //    emacs -Q
546 //    Result: Menu bar visible, frame placed immediately below the menu.
549 static void
550 ns_constrain_all_frames (void)
552   Lisp_Object tail, frame;
554   FOR_EACH_FRAME (tail, frame)
555     {
556       struct frame *f = XFRAME (frame);
557       if (FRAME_NS_P (f))
558         {
559           NSView *view = FRAME_NS_VIEW (f);
560           /* This no-op will trigger the default window placing
561            * constraint system. */
562           f->output_data.ns->dont_constrain = 0;
563           [[view window] setFrameOrigin:[[view window] frame].origin];
564         }
565     }
569 /* True, if the menu bar should be hidden.  */
571 static BOOL
572 ns_menu_bar_should_be_hidden (void)
574   return !NILP (ns_auto_hide_menu_bar)
575     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
579 /* Show or hide the menu bar, based on user setting.  */
581 static void
582 ns_update_auto_hide_menu_bar (void)
584 #ifndef MAC_OS_X_VERSION_10_6
585 #define MAC_OS_X_VERSION_10_6 1060
586 #endif
587 #ifdef NS_IMPL_COCOA
588 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
589   block_input ();
591   NSTRACE (ns_update_auto_hide_menu_bar);
593   if (NSApp != nil
594       && [NSApp isActive]
595       && [NSApp respondsToSelector:@selector(setPresentationOptions:)])
596     {
597       // Note, "setPresentationOptions" triggers an error unless the
598       // application is active.
599       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
601       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
602         {
603           NSApplicationPresentationOptions options
604             = NSApplicationPresentationAutoHideDock;
606           if (menu_bar_should_be_hidden)
607             options |= NSApplicationPresentationAutoHideMenuBar;
609           [NSApp setPresentationOptions: options];
611           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
613           if (!ns_menu_bar_is_hidden)
614             {
615               ns_constrain_all_frames ();
616             }
617         }
618     }
620   unblock_input ();
621 #endif
622 #endif
626 static void
627 ns_update_begin (struct frame *f)
628 /* --------------------------------------------------------------------------
629    Prepare for a grouped sequence of drawing calls
630    external (RIF) call; whole frame, called before update_window_begin
631    -------------------------------------------------------------------------- */
633   NSView *view = FRAME_NS_VIEW (f);
634   NSRect r = [view frame];
635   NSBezierPath *bp;
636   NSTRACE (ns_update_begin);
638   ns_update_auto_hide_menu_bar ();
640   ns_updating_frame = f;
641   [view lockFocus];
643   /* drawRect may have been called for say the minibuffer, and then clip path
644      is for the minibuffer.  But the display engine may draw more because
645      we have set the frame as garbaged.  So reset clip path to the whole
646      view.  */
647   bp = [[NSBezierPath bezierPathWithRect: r] retain];
648   [bp setClip];
649   [bp release];
651 #ifdef NS_IMPL_GNUSTEP
652   uRect = NSMakeRect (0, 0, 0, 0);
653 #endif
657 static void
658 ns_update_window_begin (struct window *w)
659 /* --------------------------------------------------------------------------
660    Prepare for a grouped sequence of drawing calls
661    external (RIF) call; for one window, called after update_begin
662    -------------------------------------------------------------------------- */
664   struct frame *f = XFRAME (WINDOW_FRAME (w));
665  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
666   NSTRACE (ns_update_window_begin);
667   updated_window = w;
668   set_output_cursor (&w->cursor);
670   block_input ();
672   if (f == hlinfo->mouse_face_mouse_frame)
673     {
674       /* Don't do highlighting for mouse motion during the update.  */
675       hlinfo->mouse_face_defer = 1;
677         /* If the frame needs to be redrawn,
678            simply forget about any prior mouse highlighting.  */
679       if (FRAME_GARBAGED_P (f))
680         hlinfo->mouse_face_window = Qnil;
682       /* (further code for mouse faces ifdef'd out in other terms elided) */
683     }
685   unblock_input ();
689 static void
690 ns_update_window_end (struct window *w, int cursor_on_p,
691                       int mouse_face_overwritten_p)
692 /* --------------------------------------------------------------------------
693    Finished a grouped sequence of drawing calls
694    external (RIF) call; for one window called before update_end
695    -------------------------------------------------------------------------- */
697   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
699   /* note: this fn is nearly identical in all terms */
700   if (!w->pseudo_window_p)
701     {
702       block_input ();
704       if (cursor_on_p)
705         display_and_set_cursor (w, 1,
706                                 output_cursor.hpos, output_cursor.vpos,
707                                 output_cursor.x, output_cursor.y);
709       if (draw_window_fringes (w, 1))
710         x_draw_vertical_border (w);
712       unblock_input ();
713     }
715   /* If a row with mouse-face was overwritten, arrange for
716      frame_up_to_date to redisplay the mouse highlight.  */
717   if (mouse_face_overwritten_p)
718     {
719       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
720       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
721       hlinfo->mouse_face_window = Qnil;
722     }
724   updated_window = NULL;
725   NSTRACE (update_window_end);
729 static void
730 ns_update_end (struct frame *f)
731 /* --------------------------------------------------------------------------
732    Finished a grouped sequence of drawing calls
733    external (RIF) call; for whole frame, called after update_window_end
734    -------------------------------------------------------------------------- */
736   NSView *view = FRAME_NS_VIEW (f);
738 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
739     MOUSE_HL_INFO (f)->mouse_face_defer = 0;
741     block_input ();
743 #ifdef NS_IMPL_GNUSTEP
744   /* trigger flush only in the rectangle we tracked as being drawn */
745   [view unlockFocusNeedsFlush: NO];
746 /*fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", uRect.origin.x, uRect.origin.y, uRect.size.width, uRect.size.height); */
747   [view lockFocusInRect: uRect];
748 #endif
750   [view unlockFocus];
751   [[view window] flushWindow];
753   unblock_input ();
754   ns_updating_frame = NULL;
755   NSTRACE (ns_update_end);
759 static void
760 ns_flush (struct frame *f)
761 /* --------------------------------------------------------------------------
762    external (RIF) call
763    NS impl is no-op since currently we flush in ns_update_end and elsewhere
764    -------------------------------------------------------------------------- */
766     NSTRACE (ns_flush);
770 static void
771 ns_focus (struct frame *f, NSRect *r, int n)
772 /* --------------------------------------------------------------------------
773    Internal: Focus on given frame.  During small local updates this is used to
774      draw, however during large updates, ns_update_begin and ns_update_end are
775      called to wrap the whole thing, in which case these calls are stubbed out.
776      Except, on GNUstep, we accumulate the rectangle being drawn into, because
777      the back end won't do this automatically, and will just end up flushing
778      the entire window.
779    -------------------------------------------------------------------------- */
781 //  NSTRACE (ns_focus);
782 #ifdef NS_IMPL_GNUSTEP
783   NSRect u;
784     if (n == 2)
785       u = NSUnionRect (r[0], r[1]);
786     else if (r)
787       u = *r;
788 #endif
789 /* static int c =0;
790    fprintf (stderr, "focus: %d", c++);
791    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
792    fprintf (stderr, "\n"); */
794   if (f != ns_updating_frame)
795     {
796       NSView *view = FRAME_NS_VIEW (f);
797       if (view != focus_view)
798         {
799           if (focus_view != NULL)
800             {
801               [focus_view unlockFocus];
802               [[focus_view window] flushWindow];
803 /*debug_lock--; */
804             }
806           if (view)
807 #ifdef NS_IMPL_GNUSTEP
808             r ? [view lockFocusInRect: u] : [view lockFocus];
809 #else
810             [view lockFocus];
811 #endif
812           focus_view = view;
813 /*if (view) debug_lock++; */
814         }
815 #ifdef NS_IMPL_GNUSTEP
816       else
817         {
818           /* more than one rect being drawn into */
819           if (view && r)
820             {
821               [view unlockFocus]; /* add prev rect to redraw list */
822               [view lockFocusInRect: u]; /* focus for draw in new rect */
823             }
824         }
825 #endif
826     }
827 #ifdef NS_IMPL_GNUSTEP
828   else
829     {
830       /* in batch mode, but in GNUstep must still track rectangles explicitly */
831       uRect = (r ? NSUnionRect (uRect, u) : [FRAME_NS_VIEW (f) visibleRect]);
832     }
833 #endif
835   /* clipping */
836   if (r)
837     {
838       [[NSGraphicsContext currentContext] saveGraphicsState];
839       if (n == 2)
840         NSRectClipList (r, 2);
841       else
842         NSRectClip (*r);
843       gsaved = YES;
844     }
848 static void
849 ns_unfocus (struct frame *f)
850 /* --------------------------------------------------------------------------
851      Internal: Remove focus on given frame
852    -------------------------------------------------------------------------- */
854 //  NSTRACE (ns_unfocus);
856   if (gsaved)
857     {
858       [[NSGraphicsContext currentContext] restoreGraphicsState];
859       gsaved = NO;
860     }
862   if (f != ns_updating_frame)
863     {
864       if (focus_view != NULL)
865         {
866           [focus_view unlockFocus];
867           [[focus_view window] flushWindow];
868           focus_view = NULL;
869 /*debug_lock--; */
870         }
871     }
875 static void
876 ns_clip_to_row (struct window *w, struct glyph_row *row, int area, BOOL gc)
877 /* --------------------------------------------------------------------------
878      Internal (but parallels other terms): Focus drawing on given row
879    -------------------------------------------------------------------------- */
881   struct frame *f = XFRAME (WINDOW_FRAME (w));
882   NSRect clip_rect;
883   int window_x, window_y, window_width;
885   window_box (w, area, &window_x, &window_y, &window_width, 0);
887   clip_rect.origin.x = window_x;
888   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
889   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
890   clip_rect.size.width = window_width;
891   clip_rect.size.height = row->visible_height;
893   ns_focus (f, &clip_rect, 1);
897 static void
898 ns_ring_bell (struct frame *f)
899 /* --------------------------------------------------------------------------
900      "Beep" routine
901    -------------------------------------------------------------------------- */
903   NSTRACE (ns_ring_bell);
904   if (visible_bell)
905     {
906       NSAutoreleasePool *pool;
907       struct frame *frame = SELECTED_FRAME ();
908       NSView *view;
910       block_input ();
911       pool = [[NSAutoreleasePool alloc] init];
913       view = FRAME_NS_VIEW (frame);
914       if (view != nil)
915         {
916           NSRect r, surr;
917           NSPoint dim = NSMakePoint (128, 128);
919           r = [view bounds];
920           r.origin.x += (r.size.width - dim.x) / 2;
921           r.origin.y += (r.size.height - dim.y) / 2;
922           r.size.width = dim.x;
923           r.size.height = dim.y;
924           surr = NSInsetRect (r, -2, -2);
925           ns_focus (frame, &surr, 1);
926           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
927           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
928                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
929           NSRectFill (r);
930           [[view window] flushWindow];
931           ns_timeout (150000);
932           [[view window] restoreCachedImage];
933           [[view window] flushWindow];
934           ns_unfocus (frame);
935         }
936       [pool release];
937       unblock_input ();
938     }
939   else
940     {
941       NSBeep ();
942     }
946 static void
947 ns_reset_terminal_modes (struct terminal *terminal)
948 /*  Externally called as hook */
950   NSTRACE (ns_reset_terminal_modes);
954 static void
955 ns_set_terminal_modes (struct terminal *terminal)
956 /*  Externally called as hook */
958   NSTRACE (ns_set_terminal_modes);
963 /* ==========================================================================
965     Frame / window manager related functions
967    ========================================================================== */
970 static void
971 ns_raise_frame (struct frame *f)
972 /* --------------------------------------------------------------------------
973      Bring window to foreground and make it active
974    -------------------------------------------------------------------------- */
976   NSView *view = FRAME_NS_VIEW (f);
977   check_ns ();
978   block_input ();
979   FRAME_SAMPLE_VISIBILITY (f);
980   if (FRAME_VISIBLE_P (f))
981     {
982       [[view window] makeKeyAndOrderFront: NSApp];
983     }
984   unblock_input ();
988 static void
989 ns_lower_frame (struct frame *f)
990 /* --------------------------------------------------------------------------
991      Send window to back
992    -------------------------------------------------------------------------- */
994   NSView *view = FRAME_NS_VIEW (f);
995   check_ns ();
996   block_input ();
997   [[view window] orderBack: NSApp];
998   unblock_input ();
1002 static void
1003 ns_frame_raise_lower (struct frame *f, int raise)
1004 /* --------------------------------------------------------------------------
1005      External (hook)
1006    -------------------------------------------------------------------------- */
1008   NSTRACE (ns_frame_raise_lower);
1010   if (raise)
1011     ns_raise_frame (f);
1012   else
1013     ns_lower_frame (f);
1017 static void
1018 ns_frame_rehighlight (struct frame *frame)
1019 /* --------------------------------------------------------------------------
1020      External (hook): called on things like window switching within frame
1021    -------------------------------------------------------------------------- */
1023   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
1024   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1026   NSTRACE (ns_frame_rehighlight);
1027   if (dpyinfo->x_focus_frame)
1028     {
1029       dpyinfo->x_highlight_frame
1030         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1031            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1032            : dpyinfo->x_focus_frame);
1033       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1034         {
1035           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1036           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1037         }
1038     }
1039   else
1040       dpyinfo->x_highlight_frame = 0;
1042   if (dpyinfo->x_highlight_frame &&
1043          dpyinfo->x_highlight_frame != old_highlight)
1044     {
1045       if (old_highlight)
1046         {
1047           x_update_cursor (old_highlight, 1);
1048           x_set_frame_alpha (old_highlight);
1049         }
1050       if (dpyinfo->x_highlight_frame)
1051         {
1052           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1053           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1054         }
1055     }
1059 void
1060 x_make_frame_visible (struct frame *f)
1061 /* --------------------------------------------------------------------------
1062      External: Show the window (X11 semantics)
1063    -------------------------------------------------------------------------- */
1065   NSTRACE (x_make_frame_visible);
1066   /* XXX: at some points in past this was not needed, as the only place that
1067      called this (frame.c:Fraise_frame ()) also called raise_lower;
1068      if this ends up the case again, comment this out again. */
1069   if (!FRAME_VISIBLE_P (f))
1070     {
1071       f->async_visible = 1;
1072       ns_raise_frame (f);
1073     }
1077 void
1078 x_make_frame_invisible (struct frame *f)
1079 /* --------------------------------------------------------------------------
1080      External: Hide the window (X11 semantics)
1081    -------------------------------------------------------------------------- */
1083   NSView * view = FRAME_NS_VIEW (f);
1084   NSTRACE (x_make_frame_invisible);
1085   check_ns ();
1086   [[view window] orderOut: NSApp];
1087   f->async_visible = 0;
1088   f->async_iconified = 0;
1092 void
1093 x_iconify_frame (struct frame *f)
1094 /* --------------------------------------------------------------------------
1095      External: Iconify window
1096    -------------------------------------------------------------------------- */
1098   NSView * view = FRAME_NS_VIEW (f);
1099   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1100   NSTRACE (x_iconify_frame);
1101   check_ns ();
1103   if (dpyinfo->x_highlight_frame == f)
1104     dpyinfo->x_highlight_frame = 0;
1106   if ([[view window] windowNumber] <= 0)
1107     {
1108       /* the window is still deferred.  Make it very small, bring it
1109          on screen and order it out. */
1110       NSRect s = { { 100, 100}, {0, 0} };
1111       NSRect t;
1112       t = [[view window] frame];
1113       [[view window] setFrame: s display: NO];
1114       [[view window] orderBack: NSApp];
1115       [[view window] orderOut: NSApp];
1116       [[view window] setFrame: t display: NO];
1117     }
1118   [[view window] miniaturize: NSApp];
1121 /* Free X resources of frame F.  */
1123 void
1124 x_free_frame_resources (struct frame *f)
1126   NSView *view = FRAME_NS_VIEW (f);
1127   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1128   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1129   NSTRACE (x_free_frame_resources);
1130   check_ns ();
1132   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1134   block_input ();
1136   free_frame_menubar (f);
1138   if (FRAME_FACE_CACHE (f))
1139     free_frame_faces (f);
1141   if (f == dpyinfo->x_focus_frame)
1142     dpyinfo->x_focus_frame = 0;
1143   if (f == dpyinfo->x_highlight_frame)
1144     dpyinfo->x_highlight_frame = 0;
1145   if (f == hlinfo->mouse_face_mouse_frame)
1146     {
1147       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
1148       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
1149       hlinfo->mouse_face_window = Qnil;
1150       hlinfo->mouse_face_deferred_gc = 0;
1151       hlinfo->mouse_face_mouse_frame = 0;
1152     }
1154   if (f->output_data.ns->miniimage != nil)
1155     [f->output_data.ns->miniimage release];
1157   [[view window] close];
1158   [view release];
1160   xfree (f->output_data.ns);
1162   unblock_input ();
1165 void
1166 x_destroy_window (struct frame *f)
1167 /* --------------------------------------------------------------------------
1168      External: Delete the window
1169    -------------------------------------------------------------------------- */
1171   NSTRACE (x_destroy_window);
1172   check_ns ();
1173   x_free_frame_resources (f);
1174   ns_window_num--;
1178 void
1179 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1180 /* --------------------------------------------------------------------------
1181      External: Position the window
1182    -------------------------------------------------------------------------- */
1184   NSView *view = FRAME_NS_VIEW (f);
1185   NSArray *screens = [NSScreen screens];
1186   NSScreen *fscreen = [screens objectAtIndex: 0];
1187   NSScreen *screen = [[view window] screen];
1189   NSTRACE (x_set_offset);
1191   block_input ();
1193   f->left_pos = xoff;
1194   f->top_pos = yoff;
1196   if (view != nil && screen && fscreen)
1197     {
1198       f->left_pos = f->size_hint_flags & XNegative
1199         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1200         : f->left_pos;
1201       /* We use visibleFrame here to take menu bar into account.
1202          Ideally we should also adjust left/top with visibleFrame.origin.  */
1204       f->top_pos = f->size_hint_flags & YNegative
1205         ? ([screen visibleFrame].size.height + f->top_pos
1206            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1207            - FRAME_TOOLBAR_HEIGHT (f))
1208         : f->top_pos;
1209 #ifdef NS_IMPL_GNUSTEP
1210       if (f->left_pos < 100)
1211         f->left_pos = 100;  /* don't overlap menu */
1212 #endif
1213       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1214          menu bar.  */
1215       f->output_data.ns->dont_constrain = 0;
1216       [[view window] setFrameTopLeftPoint:
1217                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1218                                     SCREENMAXBOUND ([fscreen frame].size.height
1219                                                     - NS_TOP_POS (f)))];
1220       f->size_hint_flags &= ~(XNegative|YNegative);
1221     }
1223   unblock_input ();
1227 void
1228 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1229 /* --------------------------------------------------------------------------
1230      Adjust window pixel size based on given character grid size
1231      Impl is a bit more complex than other terms, need to do some
1232      internal clipping.
1233    -------------------------------------------------------------------------- */
1235   EmacsView *view = FRAME_NS_VIEW (f);
1236   NSWindow *window = [view window];
1237   NSRect wr = [window frame];
1238   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1239   int pixelwidth, pixelheight;
1241   NSTRACE (x_set_window_size);
1243   if (view == nil)
1244     return;
1246 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1248   block_input ();
1250   check_frame_size (f, &rows, &cols);
1252   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1253   compute_fringe_widths (f, 0);
1255   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1256   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1258   /* If we have a toolbar, take its height into account. */
1259   if (tb)
1260     /* NOTE: previously this would generate wrong result if toolbar not
1261              yet displayed and fixing toolbar_height=32 helped, but
1262              now (200903) seems no longer needed */
1263     FRAME_TOOLBAR_HEIGHT (f) =
1264       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1265         - FRAME_NS_TITLEBAR_HEIGHT (f);
1266   else
1267     FRAME_TOOLBAR_HEIGHT (f) = 0;
1269   wr.size.width = pixelwidth + f->border_width;
1270   wr.size.height = pixelheight + FRAME_NS_TITLEBAR_HEIGHT (f)
1271                   + FRAME_TOOLBAR_HEIGHT (f);
1273   /* Do not try to constrain to this screen.  We may have multiple
1274      screens, and want Emacs to span those.  Constraining to screen
1275      prevents that, and that is not nice to the user.  */
1276  if (f->output_data.ns->zooming)
1277    f->output_data.ns->zooming = 0;
1278  else
1279    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1281   [view setRows: rows andColumns: cols];
1282   [window setFrame: wr display: YES];
1284 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1286   /* This is a trick to compensate for Emacs' managing the scrollbar area
1287      as a fixed number of standard character columns.  Instead of leaving
1288      blank space for the extra, we chopped it off above.  Now for
1289      left-hand scrollbars, we shift all rendering to the left by the
1290      difference between the real width and Emacs' imagined one.  For
1291      right-hand bars, don't worry about it since the extra is never used.
1292      (Obviously doesn't work for vertically split windows tho..) */
1293   {
1294     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1295       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1296                      - NS_SCROLL_BAR_WIDTH (f), 0)
1297       : NSMakePoint (0, 0);
1298     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1299     [view setBoundsOrigin: origin];
1300   }
1302   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1303   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1304   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1305 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1307   mark_window_cursors_off (XWINDOW (f->root_window));
1308   cancel_mouse_face (f);
1310   unblock_input ();
1314 static void
1315 ns_fullscreen_hook (FRAME_PTR f)
1317   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1318   
1319   if (! f->async_visible) return;
1321   block_input ();
1322   [view handleFS];
1323   unblock_input ();
1326 /* ==========================================================================
1328     Color management
1330    ========================================================================== */
1333 NSColor *
1334 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1336   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1337   if (idx < 1 || idx >= color_table->avail)
1338     return nil;
1339   return color_table->colors[idx];
1343 unsigned long
1344 ns_index_color (NSColor *color, struct frame *f)
1346   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1347   ptrdiff_t idx;
1348   ptrdiff_t i;
1350   if (!color_table->colors)
1351     {
1352       color_table->size = NS_COLOR_CAPACITY;
1353       color_table->avail = 1; /* skip idx=0 as marker */
1354       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1355       color_table->colors[0] = nil;
1356       color_table->empty_indices = [[NSMutableSet alloc] init];
1357     }
1359   /* do we already have this color ? */
1360   for (i = 1; i < color_table->avail; i++)
1361     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1362       return i;
1364   if ([color_table->empty_indices count] > 0)
1365     {
1366       NSNumber *index = [color_table->empty_indices anyObject];
1367       [color_table->empty_indices removeObject: index];
1368       idx = [index unsignedLongValue];
1369     }
1370   else
1371     {
1372       if (color_table->avail == color_table->size)
1373         color_table->colors =
1374           xpalloc (color_table->colors, &color_table->size, 1,
1375                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1376       idx = color_table->avail++;
1377     }
1379   color_table->colors[idx] = color;
1380   [color retain];
1381 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1382   return idx;
1386 void
1387 ns_free_indexed_color (unsigned long idx, struct frame *f)
1389   struct ns_color_table *color_table;
1390   NSColor *color;
1391   NSNumber *index;
1393   if (!f)
1394     return;
1396   color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1398   if (idx <= 0 || idx >= color_table->size) {
1399     message1 ("ns_free_indexed_color: Color index out of range.\n");
1400     return;
1401   }
1403   index = [NSNumber numberWithUnsignedInt: idx];
1404   if ([color_table->empty_indices containsObject: index]) {
1405     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1406     return;
1407   }
1409   color = color_table->colors[idx];
1410   [color release];
1411   color_table->colors[idx] = nil;
1412   [color_table->empty_indices addObject: index];
1413 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1417 static int
1418 ns_get_color (const char *name, NSColor **col)
1419 /* --------------------------------------------------------------------------
1420      Parse a color name
1421    -------------------------------------------------------------------------- */
1422 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1423    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1424    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1426   NSColor *new = nil;
1427   static char hex[20];
1428   int scaling;
1429   float r = -1.0, g, b;
1430   NSString *nsname = [NSString stringWithUTF8String: name];
1432 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1433   block_input ();
1435   if ([nsname isEqualToString: @"ns_selection_color"])
1436     {
1437       nsname = ns_selection_color;
1438       name = [ns_selection_color UTF8String];
1439     }
1441   /* First, check for some sort of numeric specification. */
1442   hex[0] = '\0';
1444   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1445     {
1446       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1447       [scanner scanFloat: &r];
1448       [scanner scanFloat: &g];
1449       [scanner scanFloat: &b];
1450     }
1451   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1452     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1453   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1454     {
1455       int len = (strlen(name) - 1);
1456       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1457       int i;
1458       scaling = strlen(name+start) / 3;
1459       for (i = 0; i < 3; i++)
1460         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1461                  name + start + i * scaling);
1462       hex[3 * (scaling + 1) - 1] = '\0';
1463     }
1465   if (hex[0])
1466     {
1467       int rr, gg, bb;
1468       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1469       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1470         {
1471           r = rr / fscale;
1472           g = gg / fscale;
1473           b = bb / fscale;
1474         }
1475     }
1477   if (r >= 0.0)
1478     {
1479       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1480       unblock_input ();
1481       return 0;
1482     }
1484   /* Otherwise, color is expected to be from a list */
1485   {
1486     NSEnumerator *lenum, *cenum;
1487     NSString *name;
1488     NSColorList *clist;
1490 #ifdef NS_IMPL_GNUSTEP
1491     /* XXX: who is wrong, the requestor or the implementation? */
1492     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1493         == NSOrderedSame)
1494       nsname = @"highlightColor";
1495 #endif
1497     lenum = [[NSColorList availableColorLists] objectEnumerator];
1498     while ( (clist = [lenum nextObject]) && new == nil)
1499       {
1500         cenum = [[clist allKeys] objectEnumerator];
1501         while ( (name = [cenum nextObject]) && new == nil )
1502           {
1503             if ([name compare: nsname
1504                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1505               new = [clist colorWithKey: name];
1506           }
1507       }
1508   }
1510   if (new)
1511     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1512   unblock_input ();
1513   return new ? 0 : 1;
1518 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1519 /* --------------------------------------------------------------------------
1520      Convert a Lisp string object to a NS color
1521    -------------------------------------------------------------------------- */
1523   NSTRACE (ns_lisp_to_color);
1524   if (STRINGP (color))
1525     return ns_get_color (SSDATA (color), col);
1526   else if (SYMBOLP (color))
1527     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1528   return 1;
1532 Lisp_Object
1533 ns_color_to_lisp (NSColor *col)
1534 /* --------------------------------------------------------------------------
1535      Convert a color to a lisp string with the RGB equivalent
1536    -------------------------------------------------------------------------- */
1538   CGFloat red, green, blue, alpha, gray;
1539   char buf[1024];
1540   const char *str;
1541   NSTRACE (ns_color_to_lisp);
1543   block_input ();
1544   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1546       if ((str =[[col colorNameComponent] UTF8String]))
1547         {
1548           unblock_input ();
1549           return build_string ((char *)str);
1550         }
1552     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1553         getRed: &red green: &green blue: &blue alpha: &alpha];
1554   if (red ==green && red ==blue)
1555     {
1556       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1557             getWhite: &gray alpha: &alpha];
1558       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1559                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1560       unblock_input ();
1561       return build_string (buf);
1562     }
1564   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1565             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1567   unblock_input ();
1568   return build_string (buf);
1572 void
1573 ns_query_color(void *col, XColor *color_def, int setPixel)
1574 /* --------------------------------------------------------------------------
1575          Get ARGB values out of NSColor col and put them into color_def.
1576          If setPixel, set the pixel to a concatenated version.
1577          and set color_def pixel to the resulting index.
1578    -------------------------------------------------------------------------- */
1580   CGFloat r, g, b, a;
1582   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1583   color_def->red   = r * 65535;
1584   color_def->green = g * 65535;
1585   color_def->blue  = b * 65535;
1587   if (setPixel == YES)
1588     color_def->pixel
1589       = ARGB_TO_ULONG((int)(a*255),
1590                       (int)(r*255), (int)(g*255), (int)(b*255));
1594 bool
1595 ns_defined_color (struct frame *f,
1596                   const char *name,
1597                   XColor *color_def,
1598                   bool alloc,
1599                   bool makeIndex)
1600 /* --------------------------------------------------------------------------
1601          Return true if named color found, and set color_def rgb accordingly.
1602          If makeIndex and alloc are nonzero put the color in the color_table,
1603          and set color_def pixel to the resulting index.
1604          If makeIndex is zero, set color_def pixel to ARGB.
1605          Return false if not found
1606    -------------------------------------------------------------------------- */
1608   NSColor *col;
1609   NSTRACE (ns_defined_color);
1611   block_input ();
1612   if (ns_get_color (name, &col) != 0) /* Color not found  */
1613     {
1614       unblock_input ();
1615       return 0;
1616     }
1617   if (makeIndex && alloc)
1618     color_def->pixel = ns_index_color (col, f);
1619   ns_query_color (col, color_def, !makeIndex);
1620   unblock_input ();
1621   return 1;
1625 unsigned long
1626 ns_get_rgb_color (struct frame *f, float r, float g, float b, float a)
1627 /* --------------------------------------------------------------------------
1628     return an autoreleased RGB color
1629    -------------------------------------------------------------------------- */
1631 /*static int c = 1; fprintf (stderr, "color request %d\n", c++); */
1632   if (r < 0.0) r = 0.0;
1633   else if (r > 1.0) r = 1.0;
1634   if (g < 0.0) g = 0.0;
1635   else if (g > 1.0) g = 1.0;
1636   if (b < 0.0) b = 0.0;
1637   else if (b > 1.0) b = 1.0;
1638   if (a < 0.0) a = 0.0;
1639   else if (a > 1.0) a = 1.0;
1640   return (unsigned long) ns_index_color(
1641     [NSColor colorWithCalibratedRed: r green: g blue: b alpha: a], f);
1645 void
1646 x_set_frame_alpha (struct frame *f)
1647 /* --------------------------------------------------------------------------
1648      change the entire-frame transparency
1649    -------------------------------------------------------------------------- */
1651   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1652   EmacsView *view = FRAME_NS_VIEW (f);
1653   double alpha = 1.0;
1654   double alpha_min = 1.0;
1656   if (dpyinfo->x_highlight_frame == f)
1657     alpha = f->alpha[0];
1658   else
1659     alpha = f->alpha[1];
1661   if (FLOATP (Vframe_alpha_lower_limit))
1662     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1663   else if (INTEGERP (Vframe_alpha_lower_limit))
1664     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1666   if (alpha < 0.0)
1667     return;
1668   else if (1.0 < alpha)
1669     alpha = 1.0;
1670   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1671     alpha = alpha_min;
1673 #ifdef NS_IMPL_COCOA
1674   [[view window] setAlphaValue: alpha];
1675 #endif
1679 /* ==========================================================================
1681     Mouse handling
1683    ========================================================================== */
1686 void
1687 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1688 /* --------------------------------------------------------------------------
1689      Programmatically reposition mouse pointer in pixel coordinates
1690    -------------------------------------------------------------------------- */
1692   NSTRACE (x_set_mouse_pixel_position);
1693   ns_raise_frame (f);
1694 #if 0
1695   /* FIXME: this does not work, and what about GNUstep? */
1696 #ifdef NS_IMPL_COCOA
1697   [FRAME_NS_VIEW (f) lockFocus];
1698   PSsetmouse ((float)pix_x, (float)pix_y);
1699   [FRAME_NS_VIEW (f) unlockFocus];
1700 #endif
1701 #endif
1705 void
1706 x_set_mouse_position (struct frame *f, int h, int v)
1707 /* --------------------------------------------------------------------------
1708      Programmatically reposition mouse pointer in character coordinates
1709    -------------------------------------------------------------------------- */
1711   int pix_x, pix_y;
1713   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1714   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1716   if (pix_x < 0) pix_x = 0;
1717   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1719   if (pix_y < 0) pix_y = 0;
1720   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1722   x_set_mouse_pixel_position (f, pix_x, pix_y);
1726 static int
1727 note_mouse_movement (struct frame *frame, float x, float y)
1728 /*   ------------------------------------------------------------------------
1729      Called by EmacsView on mouseMovement events.  Passes on
1730      to emacs mainstream code if we moved off of a rect of interest
1731      known as last_mouse_glyph.
1732      ------------------------------------------------------------------------ */
1734 //  NSTRACE (note_mouse_movement);
1736   XSETFRAME (last_mouse_motion_frame, frame);
1738   /* Note, this doesn't get called for enter/leave, since we don't have a
1739      position.  Those are taken care of in the corresponding NSView methods. */
1741   /* has movement gone beyond last rect we were tracking? */
1742   if (x < last_mouse_glyph.origin.x ||
1743       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1744       y < last_mouse_glyph.origin.y ||
1745       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1746     {
1747       ns_update_begin(frame);
1748       frame->mouse_moved = 1;
1749       note_mouse_highlight (frame, x, y);
1750       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1751       ns_update_end(frame);
1752       return 1;
1753     }
1755   return 0;
1759 static void
1760 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1761                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1762                    Time *time)
1763 /* --------------------------------------------------------------------------
1764     External (hook): inform emacs about mouse position and hit parts.
1765     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1766     x & y should be position in the scrollbar (the whole bar, not the handle)
1767     and length of scrollbar respectively
1768    -------------------------------------------------------------------------- */
1770   id view;
1771   NSPoint position;
1772   Lisp_Object frame, tail;
1773   struct frame *f;
1774   struct ns_display_info *dpyinfo;
1776   NSTRACE (ns_mouse_position);
1778   if (*fp == NULL)
1779     {
1780       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1781       return;
1782     }
1784   dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1786   block_input ();
1788   if (last_mouse_scroll_bar != nil && insist == 0)
1789     {
1790       /* TODO: we do not use this path at the moment because drag events will
1791            go directly to the EmacsScroller.  Leaving code in for now. */
1792       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1793                                               x: x y: y];
1794       if (time) *time = last_mouse_movement_time;
1795       last_mouse_scroll_bar = nil;
1796     }
1797   else
1798     {
1799       /* Clear the mouse-moved flag for every frame on this display.  */
1800       FOR_EACH_FRAME (tail, frame)
1801         if (FRAME_NS_P (XFRAME (frame))
1802             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1803           XFRAME (frame)->mouse_moved = 0;
1805       last_mouse_scroll_bar = nil;
1806       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1807         f = last_mouse_frame;
1808       else
1809         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1810                                     : SELECTED_FRAME ();
1812       if (f && f->output_data.ns)  /* TODO: 2nd check no longer needed? */
1813         {
1814           view = FRAME_NS_VIEW (*fp);
1816           position = [[view window] mouseLocationOutsideOfEventStream];
1817           position = [view convertPoint: position fromView: nil];
1818           remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1819 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1821           if (bar_window) *bar_window = Qnil;
1822           if (part) *part = 0; /*scroll_bar_handle; */
1824           if (x) XSETINT (*x, lrint (position.x));
1825           if (y) XSETINT (*y, lrint (position.y));
1826           if (time) *time = last_mouse_movement_time;
1827           *fp = f;
1828         }
1829     }
1831   unblock_input ();
1835 static void
1836 ns_frame_up_to_date (struct frame *f)
1837 /* --------------------------------------------------------------------------
1838     External (hook): Fix up mouse highlighting right after a full update.
1839     Some highlighting was deferred if GC was happening during
1840     note_mouse_highlight (), while other highlighting was deferred for update.
1841    -------------------------------------------------------------------------- */
1843   NSTRACE (ns_frame_up_to_date);
1845   if (FRAME_NS_P (f))
1846     {
1847       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1848       if ((hlinfo->mouse_face_deferred_gc || f ==hlinfo->mouse_face_mouse_frame)
1849       /*&& hlinfo->mouse_face_mouse_frame*/)
1850         {
1851           block_input ();
1852           ns_update_begin(f);
1853           if (hlinfo->mouse_face_mouse_frame)
1854             note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1855                                   hlinfo->mouse_face_mouse_x,
1856                                   hlinfo->mouse_face_mouse_y);
1857           hlinfo->mouse_face_deferred_gc = 0;
1858           ns_update_end(f);
1859           unblock_input ();
1860         }
1861     }
1865 static void
1866 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1867 /* --------------------------------------------------------------------------
1868     External (RIF): set frame mouse pointer type.
1869    -------------------------------------------------------------------------- */
1871   NSTRACE (ns_define_frame_cursor);
1872   if (FRAME_POINTER_TYPE (f) != cursor)
1873     {
1874       EmacsView *view = FRAME_NS_VIEW (f);
1875       FRAME_POINTER_TYPE (f) = cursor;
1876       [[view window] invalidateCursorRectsForView: view];
1877       /* Redisplay assumes this function also draws the changed frame
1878          cursor, but this function doesn't, so do it explicitly.  */
1879       x_update_cursor (f, 1);
1880     }
1885 /* ==========================================================================
1887     Keyboard handling
1889    ========================================================================== */
1892 static unsigned
1893 ns_convert_key (unsigned code)
1894 /* --------------------------------------------------------------------------
1895     Internal call used by NSView-keyDown.
1896    -------------------------------------------------------------------------- */
1898   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1899                                 / sizeof (convert_ns_to_X_keysym[0]));
1900   unsigned keysym;
1901   /* An array would be faster, but less easy to read. */
1902   for (keysym = 0; keysym < last_keysym; keysym += 2)
1903     if (code == convert_ns_to_X_keysym[keysym])
1904       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1905   return 0;
1906 /* if decide to use keyCode and Carbon table, use this line:
1907      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1911 char *
1912 x_get_keysym_name (int keysym)
1913 /* --------------------------------------------------------------------------
1914     Called by keyboard.c.  Not sure if the return val is important, except
1915     that it be unique.
1916    -------------------------------------------------------------------------- */
1918   static char value[16];
1919   NSTRACE (x_get_keysym_name);
1920   sprintf (value, "%d", keysym);
1921   return value;
1926 /* ==========================================================================
1928     Block drawing operations
1930    ========================================================================== */
1933 static void
1934 ns_redraw_scroll_bars (struct frame *f)
1936   int i;
1937   id view;
1938   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1939   NSTRACE (ns_redraw_scroll_bars);
1940   for (i =[subviews count]-1; i >= 0; i--)
1941     {
1942       view = [subviews objectAtIndex: i];
1943       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1944       [view display];
1945     }
1949 void
1950 ns_clear_frame (struct frame *f)
1951 /* --------------------------------------------------------------------------
1952       External (hook): Erase the entire frame
1953    -------------------------------------------------------------------------- */
1955   NSView *view = FRAME_NS_VIEW (f);
1956   NSRect r;
1958   NSTRACE (ns_clear_frame);
1959   if (ns_in_resize)
1960     return;
1962  /* comes on initial frame because we have
1963     after-make-frame-functions = select-frame */
1964  if (!FRAME_DEFAULT_FACE (f))
1965    return;
1967   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
1969   output_cursor.hpos = output_cursor.vpos = 0;
1970   output_cursor.x = -1;
1972   r = [view bounds];
1974   block_input ();
1975   ns_focus (f, &r, 1);
1976   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
1977   NSRectFill (r);
1978   ns_unfocus (f);
1980 #ifdef NS_IMPL_COCOA
1981   [[view window] display];  /* redraw resize handle */
1982 #endif
1984   /* as of 2006/11 or so this is now needed */
1985   ns_redraw_scroll_bars (f);
1986   unblock_input ();
1990 static void
1991 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
1992 /* --------------------------------------------------------------------------
1993     External (RIF):  Clear section of frame
1994    -------------------------------------------------------------------------- */
1996   NSRect r = NSMakeRect (x, y, width, height);
1997   NSView *view = FRAME_NS_VIEW (f);
1998   struct face *face = FRAME_DEFAULT_FACE (f);
2000   if (!view || !face)
2001     return;
2003   NSTRACE (ns_clear_frame_area);
2005   r = NSIntersectionRect (r, [view frame]);
2006   ns_focus (f, &r, 1);
2007   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2009 #ifdef NS_IMPL_COCOA
2010   {
2011     /* clip out the resize handle */
2012     NSWindow *window = [FRAME_NS_VIEW (f) window];
2013     NSRect ir
2014       = [view convertRect: ns_resize_handle_rect (window) fromView: nil];
2016     ir = NSIntersectionRect (r, ir);
2017     if (NSIsEmptyRect (ir))
2018       {
2019 #endif
2021   NSRectFill (r);
2023 #ifdef NS_IMPL_COCOA
2024       }
2025     else
2026       {
2027         NSRect r1 = r, r2 = r; /* upper and lower non-intersecting */
2028         r1.size.height -= ir.size.height;
2029         r2.origin.y += r1.size.height;
2030         r2.size.width -= ir.size.width;
2031         r2.size.height = ir.size.height;
2032         NSRectFill (r1);
2033         NSRectFill (r2);
2034       }
2035   }
2036 #endif
2038   ns_unfocus (f);
2039   return;
2043 static void
2044 ns_scroll_run (struct window *w, struct run *run)
2045 /* --------------------------------------------------------------------------
2046     External (RIF):  Insert or delete n lines at line vpos
2047    -------------------------------------------------------------------------- */
2049   struct frame *f = XFRAME (w->frame);
2050   int x, y, width, height, from_y, to_y, bottom_y;
2052   NSTRACE (ns_scroll_run);
2054   /* begin copy from other terms */
2055   /* Get frame-relative bounding box of the text display area of W,
2056      without mode lines.  Include in this box the left and right
2057      fringe of W.  */
2058   window_box (w, -1, &x, &y, &width, &height);
2060   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2061   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2062   bottom_y = y + height;
2064   if (to_y < from_y)
2065     {
2066       /* Scrolling up.  Make sure we don't copy part of the mode
2067          line at the bottom.  */
2068       if (from_y + run->height > bottom_y)
2069         height = bottom_y - from_y;
2070       else
2071         height = run->height;
2072     }
2073   else
2074     {
2075       /* Scrolling down.  Make sure we don't copy over the mode line.
2076          at the bottom.  */
2077       if (to_y + run->height > bottom_y)
2078         height = bottom_y - to_y;
2079       else
2080         height = run->height;
2081     }
2082   /* end copy from other terms */
2084   if (height == 0)
2085       return;
2087   block_input ();
2089   updated_window = w;
2090   x_clear_cursor (w);
2092   {
2093     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2094     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2095     NSPoint dstOrigin = NSMakePoint (x, to_y);
2097     ns_focus (f, &dstRect, 1);
2098     NSCopyBits (0, srcRect , dstOrigin);
2099     ns_unfocus (f);
2100   }
2102   unblock_input ();
2106 static void
2107 ns_after_update_window_line (struct glyph_row *desired_row)
2108 /* --------------------------------------------------------------------------
2109     External (RIF): preparatory to fringe update after text was updated
2110    -------------------------------------------------------------------------- */
2112   struct window *w = updated_window;
2113   struct frame *f;
2114   int width, height;
2116   NSTRACE (ns_after_update_window_line);
2118   /* begin copy from other terms */
2119   eassert (w);
2121   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2122     desired_row->redraw_fringe_bitmaps_p = 1;
2124   /* When a window has disappeared, make sure that no rest of
2125      full-width rows stays visible in the internal border.  */
2126   if (windows_or_buffers_changed
2127       && desired_row->full_width_p
2128       && (f = XFRAME (w->frame),
2129           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2130           width != 0)
2131       && (height = desired_row->visible_height,
2132           height > 0))
2133     {
2134       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2136       block_input ();
2137       ns_clear_frame_area (f, 0, y, width, height);
2138       ns_clear_frame_area (f,
2139                            FRAME_PIXEL_WIDTH (f) - width,
2140                            y, width, height);
2141       unblock_input ();
2142     }
2146 static void
2147 ns_shift_glyphs_for_insert (struct frame *f,
2148                            int x, int y, int width, int height,
2149                            int shift_by)
2150 /* --------------------------------------------------------------------------
2151     External (RIF): copy an area horizontally, don't worry about clearing src
2152    -------------------------------------------------------------------------- */
2154   NSRect srcRect = NSMakeRect (x, y, width, height);
2155   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2156   NSPoint dstOrigin = dstRect.origin;
2158   NSTRACE (ns_shift_glyphs_for_insert);
2160   ns_focus (f, &dstRect, 1);
2161   NSCopyBits (0, srcRect, dstOrigin);
2162   ns_unfocus (f);
2167 /* ==========================================================================
2169     Character encoding and metrics
2171    ========================================================================== */
2174 static void
2175 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2176 /* --------------------------------------------------------------------------
2177      External (RIF); compute left/right overhang of whole string and set in s
2178    -------------------------------------------------------------------------- */
2180   struct font *font = s->font;
2182   if (s->char2b)
2183     {
2184       struct font_metrics metrics;
2185       unsigned int codes[2];
2186       codes[0] = *(s->char2b);
2187       codes[1] = *(s->char2b + s->nchars - 1);
2189       font->driver->text_extents (font, codes, 2, &metrics);
2190       s->left_overhang = -metrics.lbearing;
2191       s->right_overhang
2192         = metrics.rbearing > metrics.width
2193         ? metrics.rbearing - metrics.width : 0;
2194     }
2195   else
2196     {
2197       s->left_overhang = 0;
2198       s->right_overhang = ((struct nsfont_info *)font)->ital ?
2199         FONT_HEIGHT (font) * 0.2 : 0;
2200     }
2205 /* ==========================================================================
2207     Fringe and cursor drawing
2209    ========================================================================== */
2212 extern int max_used_fringe_bitmap;
2213 static void
2214 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2215                       struct draw_fringe_bitmap_params *p)
2216 /* --------------------------------------------------------------------------
2217     External (RIF); fringe-related
2218    -------------------------------------------------------------------------- */
2220   struct frame *f = XFRAME (WINDOW_FRAME (w));
2221   struct face *face = p->face;
2222   int rowY;
2223   static EmacsImage **bimgs = NULL;
2224   static int nBimgs = 0;
2226   /* grow bimgs if needed */
2227   if (nBimgs < max_used_fringe_bitmap)
2228     {
2229       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2230       memset (bimgs + nBimgs, 0,
2231               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2232       nBimgs = max_used_fringe_bitmap;
2233     }
2235   /* Must clip because of partially visible lines.  */
2236   rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2237   ns_clip_to_row (w, row, -1, YES);
2239   if (!p->overlay_p)
2240     {
2241       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2243       /* If the fringe is adjacent to the left (right) scroll bar of a
2244          leftmost (rightmost, respectively) window, then extend its
2245          background to the gap between the fringe and the bar.  */
2246       if ((WINDOW_LEFTMOST_P (w)
2247            && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2248           || (WINDOW_RIGHTMOST_P (w)
2249               && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2250         {
2251           int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2253           if (sb_width > 0)
2254             {
2255               int bar_area_x = WINDOW_SCROLL_BAR_AREA_X (w);
2256               int bar_area_width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2257                                     * FRAME_COLUMN_WIDTH (f));
2259               if (bx < 0)
2260                 {
2261                   /* Bitmap fills the fringe.  */
2262                   if (bar_area_x + bar_area_width == p->x)
2263                     bx = bar_area_x + sb_width;
2264                   else if (p->x + p->wd == bar_area_x)
2265                     bx = bar_area_x;
2266                   if (bx >= 0)
2267                     {
2268                       int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2270                       nx = bar_area_width - sb_width;
2271                       by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2272                                                             row->y));
2273                       ny = row->visible_height;
2274                     }
2275                 }
2276               else
2277                 {
2278                   if (bar_area_x + bar_area_width == bx)
2279                     {
2280                       bx = bar_area_x + sb_width;
2281                       nx += bar_area_width - sb_width;
2282                     }
2283                   else if (bx + nx == bar_area_x)
2284                     nx += bar_area_width - sb_width;
2285                 }
2286             }
2287         }
2289       if (bx >= 0 && nx > 0)
2290         {
2291           NSRect r = NSMakeRect (bx, by, nx, ny);
2292           NSRectClip (r);
2293           [ns_lookup_indexed_color (face->background, f) set];
2294           NSRectFill (r);
2295         }
2296     }
2298   if (p->which)
2299     {
2300       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2301       EmacsImage *img = bimgs[p->which - 1];
2303       if (!img)
2304         {
2305           unsigned short *bits = p->bits + p->dh;
2306           int len = p->h;
2307           int i;
2308           unsigned char *cbits = xmalloc (len);
2310           for (i = 0; i < len; i++)
2311             cbits[i] = ~(bits[i] & 0xff);
2312           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2313                                            flip: NO];
2314           bimgs[p->which - 1] = img;
2315           xfree (cbits);
2316         }
2318       NSRectClip (r);
2319       /* Since we composite the bitmap instead of just blitting it, we need
2320          to erase the whole background. */
2321       [ns_lookup_indexed_color(face->background, f) set];
2322       NSRectFill (r);
2323       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2324 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2325       [img drawInRect: r
2326               fromRect: NSZeroRect
2327              operation: NSCompositeSourceOver
2328               fraction: 1.0
2329            respectFlipped: YES
2330                 hints: nil];
2331 #else
2332       {
2333         NSPoint pt = r.origin;
2334         pt.y += p->h;
2335         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2336       }
2337 #endif
2338     }
2339   ns_unfocus (f);
2343 static void
2344 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2345                        int x, int y, int cursor_type, int cursor_width,
2346                        int on_p, int active_p)
2347 /* --------------------------------------------------------------------------
2348      External call (RIF): draw cursor.
2349      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2350    -------------------------------------------------------------------------- */
2352   NSRect r, s;
2353   int fx, fy, h, cursor_height;
2354   struct frame *f = WINDOW_XFRAME (w);
2355   struct glyph *phys_cursor_glyph;
2356   int overspill;
2357   struct glyph *cursor_glyph;
2358   struct face *face;
2359   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2361   /* If cursor is out of bounds, don't draw garbage.  This can happen
2362      in mini-buffer windows when switching between echo area glyphs
2363      and mini-buffer.  */
2365   NSTRACE (dumpcursor);
2367   if (!on_p)
2368     return;
2370   w->phys_cursor_type = cursor_type;
2371   w->phys_cursor_on_p = on_p;
2373   if (cursor_type == NO_CURSOR)
2374     {
2375       w->phys_cursor_width = 0;
2376       return;
2377     }
2379   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2380     {
2381       if (glyph_row->exact_window_width_line_p
2382           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2383         {
2384           glyph_row->cursor_in_fringe_p = 1;
2385           draw_fringe_bitmap (w, glyph_row, 0);
2386         }
2387       return;
2388     }
2390   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2391      (other terminals do it the other way round).  We must set
2392      w->phys_cursor_width to the cursor width.  For bar cursors, that
2393      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2394   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2396   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2397      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2398   if (cursor_type == BAR_CURSOR)
2399     {
2400       if (cursor_width < 1)
2401         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2402       w->phys_cursor_width = cursor_width;
2403     }
2404   /* If we have an HBAR, "cursor_width" MAY specify height. */
2405   else if (cursor_type == HBAR_CURSOR)
2406     {
2407       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2408       fy += h - cursor_height;
2409       h = cursor_height;
2410     }
2412   r.origin.x = fx, r.origin.y = fy;
2413   r.size.height = h;
2414   r.size.width = w->phys_cursor_width;
2416   /* TODO: only needed in rare cases with last-resort font in HELLO..
2417      should we do this more efficiently? */
2418   ns_clip_to_row (w, glyph_row, -1, NO); /* do ns_focus(f, &r, 1); if remove */
2421   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2422   if (face && NS_FACE_BACKGROUND (face)
2423       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2424     {
2425       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2426       hollow_color = FRAME_CURSOR_COLOR (f);
2427     }
2428   else
2429     [FRAME_CURSOR_COLOR (f) set];
2431 #ifdef NS_IMPL_COCOA
2432   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2433            atomic.  Cleaner ways of doing this should be investigated.
2434            One way would be to set a global variable DRAWING_CURSOR
2435            when making the call to draw_phys..(), don't focus in that
2436            case, then move the ns_unfocus() here after that call. */
2437   NSDisableScreenUpdates ();
2438 #endif
2440   switch (cursor_type)
2441     {
2442     case NO_CURSOR:
2443       break;
2444     case FILLED_BOX_CURSOR:
2445       NSRectFill (r);
2446       break;
2447     case HOLLOW_BOX_CURSOR:
2448       NSRectFill (r);
2449       [hollow_color set];
2450       NSRectFill (NSInsetRect (r, 1, 1));
2451       [FRAME_CURSOR_COLOR (f) set];
2452       break;
2453     case HBAR_CURSOR:
2454       NSRectFill (r);
2455       break;
2456     case BAR_CURSOR:
2457       s = r;
2458       /* If the character under cursor is R2L, draw the bar cursor
2459          on the right of its glyph, rather than on the left.  */
2460       cursor_glyph = get_phys_cursor_glyph (w);
2461       if ((cursor_glyph->resolved_level & 1) != 0)
2462         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2464       NSRectFill (s);
2465       break;
2466     }
2467   ns_unfocus (f);
2469   /* draw the character under the cursor */
2470   if (cursor_type != NO_CURSOR)
2471     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2473 #ifdef NS_IMPL_COCOA
2474   NSEnableScreenUpdates ();
2475 #endif
2480 static void
2481 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2482 /* --------------------------------------------------------------------------
2483      External (RIF): Draw a vertical line.
2484    -------------------------------------------------------------------------- */
2486   struct frame *f = XFRAME (WINDOW_FRAME (w));
2487   struct face *face;
2488   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2490   NSTRACE (ns_draw_vertical_window_border);
2492   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2493   if (face)
2494       [ns_lookup_indexed_color(face->foreground, f) set];
2496   ns_focus (f, &r, 1);
2497   NSRectFill(r);
2498   ns_unfocus (f);
2502 void
2503 show_hourglass (struct atimer *timer)
2505   if (hourglass_shown_p)
2506     return;
2508   block_input ();
2510   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2512   hourglass_shown_p = 1;
2513   unblock_input ();
2517 void
2518 hide_hourglass (void)
2520   if (!hourglass_shown_p)
2521     return;
2523   block_input ();
2525   /* TODO: remove NSProgressIndicator from all frames */
2527   hourglass_shown_p = 0;
2528   unblock_input ();
2533 /* ==========================================================================
2535     Glyph drawing operations
2537    ========================================================================== */
2539 static int
2540 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2541 /* --------------------------------------------------------------------------
2542     Wrapper utility to account for internal border width on full-width lines,
2543     and allow top full-width rows to hit the frame top.  nr should be pointer
2544     to two successive NSRects.  Number of rects actually used is returned.
2545    -------------------------------------------------------------------------- */
2547   int n = get_glyph_string_clip_rects (s, nr, 2);
2548   return n;
2551 /* --------------------------------------------------------------------
2552    Draw a wavy line under glyph string s. The wave fills wave_height
2553    pixels from y.
2555                     x          wave_length = 3
2556                                  --
2557                 y    *   *   *   *   *
2558                      |* * * * * * * * *
2559     wave_height = 3  | *   *   *   *
2560   --------------------------------------------------------------------- */
2562 static void
2563 ns_draw_underwave (struct glyph_string *s, CGFloat width, CGFloat x)
2565   int wave_height = 3, wave_length = 3;
2566   int y, dx, dy, odd, xmax;
2567   NSPoint a, b;
2568   NSRect waveClip;
2570   dx = wave_length;
2571   dy = wave_height - 1;
2572   y =  s->ybase + 1;
2573   xmax = x + width;
2575   /* Find and set clipping rectangle */
2576   waveClip = NSMakeRect (x, y, width, wave_height);
2577   [[NSGraphicsContext currentContext] saveGraphicsState];
2578   NSRectClip (waveClip);
2580   /* Draw the waves */
2581   a.x = x - ((int)(x) % dx);
2582   b.x = a.x + dx;
2583   odd = (int)(a.x/dx) % 2;
2584   a.y = b.y = y;
2586   if (odd)
2587     a.y += dy;
2588   else
2589     b.y += dy;
2591   while (a.x <= xmax)
2592     {
2593       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2594       a.x = b.x, a.y = b.y;
2595       b.x += dx, b.y = y + odd*dy;
2596       odd = !odd;
2597     }
2599   /* Restore previous clipping rectangle(s) */
2600   [[NSGraphicsContext currentContext] restoreGraphicsState];
2605 void
2606 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2607                          NSColor *defaultCol, CGFloat width, CGFloat x)
2608 /* --------------------------------------------------------------------------
2609    Draw underline, overline, and strike-through on glyph string s.
2610    -------------------------------------------------------------------------- */
2612   if (s->for_overlaps)
2613     return;
2615   /* Do underline. */
2616   if (face->underline_p)
2617     {
2618       if (s->face->underline_type == FACE_UNDER_WAVE)
2619         {
2620           if (face->underline_defaulted_p)
2621             [defaultCol set];
2622           else
2623             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2625           ns_draw_underwave (s, width, x);
2626         }
2627       else if (s->face->underline_type == FACE_UNDER_LINE)
2628         {
2630           NSRect r;
2631           unsigned long thickness, position;
2633           /* If the prev was underlined, match its appearance. */
2634           if (s->prev && s->prev->face->underline_p
2635               && s->prev->underline_thickness > 0)
2636             {
2637               thickness = s->prev->underline_thickness;
2638               position = s->prev->underline_position;
2639             }
2640           else
2641             {
2642               struct font *font;
2643               unsigned long descent;
2645               font=s->font;
2646               descent = s->y + s->height - s->ybase;
2648               /* Use underline thickness of font, defaulting to 1. */
2649               thickness = (font && font->underline_thickness > 0)
2650                 ? font->underline_thickness : 1;
2652               /* Determine the offset of underlining from the baseline. */
2653               if (x_underline_at_descent_line)
2654                 position = descent - thickness;
2655               else if (x_use_underline_position_properties
2656                        && font && font->underline_position >= 0)
2657                 position = font->underline_position;
2658               else if (font)
2659                 position = lround (font->descent / 2);
2660               else
2661                 position = underline_minimum_offset;
2663               position = max (position, underline_minimum_offset);
2665               /* Ensure underlining is not cropped. */
2666               if (descent <= position)
2667                 {
2668                   position = descent - 1;
2669                   thickness = 1;
2670                 }
2671               else if (descent < position + thickness)
2672                 thickness = 1;
2673             }
2675           s->underline_thickness = thickness;
2676           s->underline_position = position;
2678           r = NSMakeRect (x, s->ybase + position, width, thickness);
2680           if (face->underline_defaulted_p)
2681             [defaultCol set];
2682           else
2683             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2684           NSRectFill (r);
2685         }
2686     }
2687   /* Do overline. We follow other terms in using a thickness of 1
2688      and ignoring overline_margin. */
2689   if (face->overline_p)
2690     {
2691       NSRect r;
2692       r = NSMakeRect (x, s->y, width, 1);
2694       if (face->overline_color_defaulted_p)
2695         [defaultCol set];
2696       else
2697         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2698       NSRectFill (r);
2699     }
2701   /* Do strike-through.  We follow other terms for thickness and
2702      vertical position.*/
2703   if (face->strike_through_p)
2704     {
2705       NSRect r;
2706       unsigned long dy;
2708       dy = lrint ((s->height - 1) / 2);
2709       r = NSMakeRect (x, s->y + dy, width, 1);
2711       if (face->strike_through_color_defaulted_p)
2712         [defaultCol set];
2713       else
2714         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2715       NSRectFill (r);
2716     }
2719 static void
2720 ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char right_p)
2721 /* --------------------------------------------------------------------------
2722     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2723     Note we can't just use an NSDrawRect command, because of the possibility
2724     of some sides not being drawn, and because the rect will be filled.
2725    -------------------------------------------------------------------------- */
2727   NSRect s = r;
2728   [col set];
2730   /* top, bottom */
2731   s.size.height = thickness;
2732   NSRectFill (s);
2733   s.origin.y += r.size.height - thickness;
2734   NSRectFill (s);
2736   s.size.height = r.size.height;
2737   s.origin.y = r.origin.y;
2739   /* left, right (optional) */
2740   s.size.width = thickness;
2741   if (left_p)
2742     NSRectFill (s);
2743   if (right_p)
2744     {
2745       s.origin.x += r.size.width - thickness;
2746       NSRectFill (s);
2747     }
2751 static void
2752 ns_draw_relief (NSRect r, int thickness, char raised_p,
2753                char top_p, char bottom_p, char left_p, char right_p,
2754                struct glyph_string *s)
2755 /* --------------------------------------------------------------------------
2756     Draw a relief rect inside r, optionally leaving some sides open.
2757     Note we can't just use an NSDrawBezel command, because of the possibility
2758     of some sides not being drawn, and because the rect will be filled.
2759    -------------------------------------------------------------------------- */
2761   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2762   NSColor *newBaseCol = nil;
2763   NSRect sr = r;
2765   NSTRACE (ns_draw_relief);
2767   /* set up colors */
2769   if (s->face->use_box_color_for_shadows_p)
2770     {
2771       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2772     }
2773 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2774            && s->img->pixmap
2775            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2776        {
2777          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2778        } */
2779   else
2780     {
2781       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2782     }
2784   if (newBaseCol == nil)
2785     newBaseCol = [NSColor grayColor];
2787   if (newBaseCol != baseCol)  /* TODO: better check */
2788     {
2789       [baseCol release];
2790       baseCol = [newBaseCol retain];
2791       [lightCol release];
2792       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2793       [darkCol release];
2794       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2795     }
2797   [(raised_p ? lightCol : darkCol) set];
2799   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2801   /* top */
2802   sr.size.height = thickness;
2803   if (top_p) NSRectFill (sr);
2805   /* left */
2806   sr.size.height = r.size.height;
2807   sr.size.width = thickness;
2808   if (left_p) NSRectFill (sr);
2810   [(raised_p ? darkCol : lightCol) set];
2812   /* bottom */
2813   sr.size.width = r.size.width;
2814   sr.size.height = thickness;
2815   sr.origin.y += r.size.height - thickness;
2816   if (bottom_p) NSRectFill (sr);
2818   /* right */
2819   sr.size.height = r.size.height;
2820   sr.origin.y = r.origin.y;
2821   sr.size.width = thickness;
2822   sr.origin.x += r.size.width - thickness;
2823   if (right_p) NSRectFill (sr);
2827 static void
2828 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2829 /* --------------------------------------------------------------------------
2830       Function modeled after x_draw_glyph_string_box ().
2831       Sets up parameters for drawing.
2832    -------------------------------------------------------------------------- */
2834   int right_x, last_x;
2835   char left_p, right_p;
2836   struct glyph *last_glyph;
2837   NSRect r;
2838   int thickness;
2839   struct face *face;
2841   if (s->hl == DRAW_MOUSE_FACE)
2842     {
2843       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2844       if (!face)
2845         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2846     }
2847   else
2848     face = s->face;
2850   thickness = face->box_line_width;
2852   NSTRACE (ns_dumpglyphs_box_or_relief);
2854   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2855             ? WINDOW_RIGHT_EDGE_X (s->w)
2856             : window_box_right (s->w, s->area));
2857   last_glyph = (s->cmp || s->img
2858                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2860   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2861               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2863   left_p = (s->first_glyph->left_box_line_p
2864             || (s->hl == DRAW_MOUSE_FACE
2865                 && (s->prev == NULL || s->prev->hl != s->hl)));
2866   right_p = (last_glyph->right_box_line_p
2867              || (s->hl == DRAW_MOUSE_FACE
2868                  && (s->next == NULL || s->next->hl != s->hl)));
2870   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2872   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2873   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2874     {
2875       ns_draw_box (r, abs (thickness),
2876                    ns_lookup_indexed_color (face->box_color, s->f),
2877                   left_p, right_p);
2878     }
2879   else
2880     {
2881       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2882                      1, 1, left_p, right_p, s);
2883     }
2887 static void
2888 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2889 /* --------------------------------------------------------------------------
2890       Modeled after x_draw_glyph_string_background, which draws BG in
2891       certain cases.  Others are left to the text rendering routine.
2892    -------------------------------------------------------------------------- */
2894   NSTRACE (ns_maybe_dumpglyphs_background);
2896   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2897     {
2898       int box_line_width = max (s->face->box_line_width, 0);
2899       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2900           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2901         {
2902           struct face *face;
2903           if (s->hl == DRAW_MOUSE_FACE)
2904             {
2905               face = FACE_FROM_ID (s->f,
2906                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2907               if (!face)
2908                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2909             }
2910           else
2911             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2912           if (!face->stipple)
2913             [(NS_FACE_BACKGROUND (face) != 0
2914               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2915               : FRAME_BACKGROUND_COLOR (s->f)) set];
2916           else
2917             {
2918               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2919               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2920             }
2922           if (s->hl != DRAW_CURSOR)
2923             {
2924               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2925                                     s->background_width,
2926                                     s->height-2*box_line_width);
2927               NSRectFill (r);
2928             }
2930           s->background_filled_p = 1;
2931         }
2932     }
2936 static void
2937 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2938 /* --------------------------------------------------------------------------
2939       Renders an image and associated borders.
2940    -------------------------------------------------------------------------- */
2942   EmacsImage *img = s->img->pixmap;
2943   int box_line_vwidth = max (s->face->box_line_width, 0);
2944   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2945   int bg_x, bg_y, bg_height;
2946   int th;
2947   char raised_p;
2948   NSRect br;
2949   struct face *face;
2950   NSColor *tdCol;
2952   NSTRACE (ns_dumpglyphs_image);
2954   if (s->face->box != FACE_NO_BOX
2955       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2956     x += abs (s->face->box_line_width);
2958   bg_x = x;
2959   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2960   bg_height = s->height;
2961   /* other terms have this, but was causing problems w/tabbar mode */
2962   /* - 2 * box_line_vwidth; */
2964   if (s->slice.x == 0) x += s->img->hmargin;
2965   if (s->slice.y == 0) y += s->img->vmargin;
2967   /* Draw BG: if we need larger area than image itself cleared, do that,
2968      otherwise, since we composite the image under NS (instead of mucking
2969      with its background color), we must clear just the image area. */
2970   if (s->hl == DRAW_MOUSE_FACE)
2971     {
2972       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2973       if (!face)
2974        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2975     }
2976   else
2977     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2979   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2981   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2982       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2983     {
2984       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
2985       s->background_filled_p = 1;
2986     }
2987   else
2988     {
2989       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
2990     }
2992   NSRectFill (br);
2994   /* Draw the image.. do we need to draw placeholder if img ==nil? */
2995   if (img != nil)
2996     {
2997 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2998       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
2999       [img drawInRect: dr
3000              fromRect: NSZeroRect
3001              operation: NSCompositeSourceOver
3002               fraction: 1.0
3003            respectFlipped: YES
3004                 hints: nil];
3005 #else
3006       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3007                   operation: NSCompositeSourceOver];
3008 #endif
3009     }
3011   if (s->hl == DRAW_CURSOR)
3012     {
3013     [FRAME_CURSOR_COLOR (s->f) set];
3014     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3015       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3016     else
3017       /* Currently on NS img->mask is always 0. Since
3018          get_window_cursor_type specifies a hollow box cursor when on
3019          a non-masked image we never reach this clause. But we put it
3020          in in anticipation of better support for image masks on
3021          NS. */
3022       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3023     }
3024   else
3025     {
3026       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3027     }
3029   /* Draw underline, overline, strike-through. */
3030   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3032   /* Draw relief, if requested */
3033   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3034     {
3035       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3036         {
3037           th = tool_bar_button_relief >= 0 ?
3038             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3039           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3040         }
3041       else
3042         {
3043           th = abs (s->img->relief);
3044           raised_p = (s->img->relief > 0);
3045         }
3047       r.origin.x = x - th;
3048       r.origin.y = y - th;
3049       r.size.width = s->slice.width + 2*th-1;
3050       r.size.height = s->slice.height + 2*th-1;
3051       ns_draw_relief (r, th, raised_p,
3052                       s->slice.y == 0,
3053                       s->slice.y + s->slice.height == s->img->height,
3054                       s->slice.x == 0,
3055                       s->slice.x + s->slice.width == s->img->width, s);
3056     }
3058   /* If there is no mask, the background won't be seen,
3059      so draw a rectangle on the image for the cursor.
3060      Do this for all images, getting transparency right is not reliable.  */
3061   if (s->hl == DRAW_CURSOR)
3062     {
3063       int thickness = abs (s->img->relief);
3064       if (thickness == 0) thickness = 1;
3065       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3066     }
3070 static void
3071 ns_dumpglyphs_stretch (struct glyph_string *s)
3073   NSRect r[2];
3074   int n, i;
3075   struct face *face;
3076   NSColor *fgCol, *bgCol;
3078   if (!s->background_filled_p)
3079     {
3080       n = ns_get_glyph_string_clip_rect (s, r);
3081       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3083       ns_focus (s->f, r, n);
3085       if (s->hl == DRAW_MOUSE_FACE)
3086        {
3087          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3088          if (!face)
3089            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3090        }
3091       else
3092        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3094       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3095       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3097       for (i = 0; i < n; ++i)
3098         {
3099           if (!s->row->full_width_p)
3100             {
3101               int overrun, leftoverrun;
3103               /* truncate to avoid overwriting fringe and/or scrollbar */
3104               overrun = max (0, (s->x + s->background_width)
3105                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3106                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3107               r[i].size.width -= overrun;
3109               /* truncate to avoid overwriting to left of the window box */
3110               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3111                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3113               if (leftoverrun > 0)
3114                 {
3115                   r[i].origin.x += leftoverrun;
3116                   r[i].size.width -= leftoverrun;
3117                 }
3119               /* XXX: Try to work between problem where a stretch glyph on
3120                  a partially-visible bottom row will clear part of the
3121                  modeline, and another where list-buffers headers and similar
3122                  rows erroneously have visible_height set to 0.  Not sure
3123                  where this is coming from as other terms seem not to show. */
3124               r[i].size.height = min (s->height, s->row->visible_height);
3125             }
3127           [bgCol set];
3129           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3130              overwriting cursor (usually when cursor on a tab) */
3131           if (s->hl == DRAW_CURSOR)
3132             {
3133               CGFloat x, width;
3135               x = r[i].origin.x;
3136               width = s->w->phys_cursor_width;
3137               r[i].size.width -= width;
3138               r[i].origin.x += width;
3140               NSRectFill (r[i]);
3142               /* Draw overlining, etc. on the cursor. */
3143               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3144                 ns_draw_text_decoration (s, face, bgCol, width, x);
3145               else
3146                 ns_draw_text_decoration (s, face, fgCol, width, x);
3147             }
3148           else
3149             {
3150               NSRectFill (r[i]);
3151             }
3153           /* Draw overlining, etc. on the stretch glyph (or the part
3154              of the stretch glyph after the cursor). */
3155           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3156                                    r[i].origin.x);
3157         }
3158       ns_unfocus (s->f);
3159       s->background_filled_p = 1;
3160     }
3164 static void
3165 ns_draw_glyph_string (struct glyph_string *s)
3166 /* --------------------------------------------------------------------------
3167       External (RIF): Main draw-text call.
3168    -------------------------------------------------------------------------- */
3170   /* TODO (optimize): focus for box and contents draw */
3171   NSRect r[2];
3172   int n;
3173   char box_drawn_p = 0;
3175   NSTRACE (ns_draw_glyph_string);
3177   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3178     {
3179       int width;
3180       struct glyph_string *next;
3182       for (width = 0, next = s->next;
3183            next && width < s->right_overhang;
3184            width += next->width, next = next->next)
3185         if (next->first_glyph->type != IMAGE_GLYPH)
3186           {
3187             if (next->first_glyph->type != STRETCH_GLYPH)
3188               {
3189                 n = ns_get_glyph_string_clip_rect (s->next, r);
3190                 ns_focus (s->f, r, n);
3191                 ns_maybe_dumpglyphs_background (s->next, 1);
3192                 ns_unfocus (s->f);
3193               }
3194             else
3195               {
3196                 ns_dumpglyphs_stretch (s->next);
3197               }
3198             next->num_clips = 0;
3199           }
3200     }
3202   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3203         && (s->first_glyph->type == CHAR_GLYPH
3204             || s->first_glyph->type == COMPOSITE_GLYPH))
3205     {
3206       n = ns_get_glyph_string_clip_rect (s, r);
3207       ns_focus (s->f, r, n);
3208       ns_maybe_dumpglyphs_background (s, 1);
3209       ns_dumpglyphs_box_or_relief (s);
3210       ns_unfocus (s->f);
3211       box_drawn_p = 1;
3212     }
3214   switch (s->first_glyph->type)
3215     {
3217     case IMAGE_GLYPH:
3218       n = ns_get_glyph_string_clip_rect (s, r);
3219       ns_focus (s->f, r, n);
3220       ns_dumpglyphs_image (s, r[0]);
3221       ns_unfocus (s->f);
3222       break;
3224     case STRETCH_GLYPH:
3225       ns_dumpglyphs_stretch (s);
3226       break;
3228     case CHAR_GLYPH:
3229     case COMPOSITE_GLYPH:
3230       n = ns_get_glyph_string_clip_rect (s, r);
3231       ns_focus (s->f, r, n);
3233       if (s->for_overlaps || (s->cmp_from > 0
3234                               && ! s->first_glyph->u.cmp.automatic))
3235         s->background_filled_p = 1;
3236       else
3237         ns_maybe_dumpglyphs_background
3238           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3240       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3241                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3242                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3243                       NS_DUMPGLYPH_NORMAL));
3244       ns_tmp_font = (struct nsfont_info *)s->face->font;
3245       if (ns_tmp_font == NULL)
3246           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
3248       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3249         {
3250           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3251           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3252           NS_FACE_FOREGROUND (s->face) = tmp;
3253         }
3255       ns_tmp_font->font.driver->draw
3256         (s, 0, s->nchars, s->x, s->y,
3257          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3258          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
3260       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3261         {
3262           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3263           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3264           NS_FACE_FOREGROUND (s->face) = tmp;
3265         }
3267       ns_unfocus (s->f);
3268       break;
3270     case GLYPHLESS_GLYPH:
3271       n = ns_get_glyph_string_clip_rect (s, r);
3272       ns_focus (s->f, r, n);
3274       if (s->for_overlaps || (s->cmp_from > 0
3275                               && ! s->first_glyph->u.cmp.automatic))
3276         s->background_filled_p = 1;
3277       else
3278         ns_maybe_dumpglyphs_background
3279           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3280       /* ... */
3281       /* Not yet implemented.  */
3282       /* ... */
3283       ns_unfocus (s->f);
3284       break;
3286     default:
3287       emacs_abort ();
3288     }
3290   /* Draw box if not done already. */
3291   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3292     {
3293       n = ns_get_glyph_string_clip_rect (s, r);
3294       ns_focus (s->f, r, n);
3295       ns_dumpglyphs_box_or_relief (s);
3296       ns_unfocus (s->f);
3297     }
3299   s->num_clips = 0;
3304 /* ==========================================================================
3306     Event loop
3308    ========================================================================== */
3311 static void
3312 ns_send_appdefined (int value)
3313 /* --------------------------------------------------------------------------
3314     Internal: post an appdefined event which EmacsApp-sendEvent will
3315               recognize and take as a command to halt the event loop.
3316    -------------------------------------------------------------------------- */
3318   /*NSTRACE (ns_send_appdefined); */
3320   /* Only post this event if we haven't already posted one.  This will end
3321        the [NXApp run] main loop after having processed all events queued at
3322        this moment.  */
3323   if (send_appdefined)
3324     {
3325       NSEvent *nxev;
3327       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3328       send_appdefined = NO;
3330       /* Don't need wakeup timer any more */
3331       if (timed_entry)
3332         {
3333           [timed_entry invalidate];
3334           [timed_entry release];
3335           timed_entry = nil;
3336         }
3338       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3339                                 location: NSMakePoint (0, 0)
3340                            modifierFlags: 0
3341                                timestamp: 0
3342                             windowNumber: [[NSApp mainWindow] windowNumber]
3343                                  context: [NSApp context]
3344                                  subtype: 0
3345                                    data1: value
3346                                    data2: 0];
3348       /* Post an application defined event on the event queue.  When this is
3349          received the [NXApp run] will return, thus having processed all
3350          events which are currently queued.  */
3351       [NSApp postEvent: nxev atStart: NO];
3352     }
3355 static int
3356 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3357 /* --------------------------------------------------------------------------
3358      External (hook): Post an event to ourself and keep reading events until
3359      we read it back again.  In effect process all events which were waiting.
3360      From 21+ we have to manage the event buffer ourselves.
3361    -------------------------------------------------------------------------- */
3363   struct input_event ev;
3364   int nevents;
3366 /* NSTRACE (ns_read_socket); */
3368   if ([NSApp modalWindow] != nil)
3369     return -1;
3371   block_input ();
3372   n_emacs_events_pending = 0;
3373   EVENT_INIT (ev);
3374   emacs_event = &ev;
3375   q_event_ptr = hold_quit;
3377   /* we manage autorelease pools by allocate/reallocate each time around
3378      the loop; strict nesting is occasionally violated but seems not to
3379      matter.. earlier methods using full nesting caused major memory leaks */
3380   [outerpool release];
3381   outerpool = [[NSAutoreleasePool alloc] init];
3383   /* If have pending open-file requests, attend to the next one of those. */
3384   if (ns_pending_files && [ns_pending_files count] != 0
3385       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3386     {
3387       [ns_pending_files removeObjectAtIndex: 0];
3388     }
3389   /* Deal with pending service requests. */
3390   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3391     && [(EmacsApp *)
3392          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3393                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3394     {
3395       [ns_pending_service_names removeObjectAtIndex: 0];
3396       [ns_pending_service_args removeObjectAtIndex: 0];
3397     }
3398   else
3399     {
3400       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3401          to ourself, otherwise [NXApp run] will never exit.  */
3402       send_appdefined = YES;
3403       ns_send_appdefined (-1);
3405       if (++apploopnr != 1)
3406         {
3407           emacs_abort ();
3408         }
3409       [NSApp run];
3410       --apploopnr;
3411     }
3413   nevents = n_emacs_events_pending;
3414   n_emacs_events_pending = 0;
3415   emacs_event = q_event_ptr = NULL;
3416   unblock_input ();
3418   return nevents;
3423 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3424            fd_set *exceptfds, EMACS_TIME *timeout, sigset_t *sigmask)
3425 /* --------------------------------------------------------------------------
3426      Replacement for select, checking for events
3427    -------------------------------------------------------------------------- */
3429   int result;
3430   NSEvent *ev;
3431   int k, nr = 0;
3432   struct input_event event;
3433   char c;
3435 /*  NSTRACE (ns_select); */
3437   for (k = 0; readfds && k < nfds+1; k++)
3438     if (FD_ISSET(k, readfds)) ++nr;
3440   if (NSApp == nil
3441       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3442     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3444   [outerpool release];
3445   outerpool = [[NSAutoreleasePool alloc] init];
3448   send_appdefined = YES;
3449   if (nr > 0)
3450     {
3451       pthread_mutex_lock (&select_mutex);
3452       select_nfds = nfds;
3453       select_valid = 0;
3454       if (readfds)
3455         {
3456           select_readfds = *readfds;
3457           select_valid += SELECT_HAVE_READ;
3458         }
3459       if (writefds)
3460         {
3461           select_writefds = *writefds;
3462           select_valid += SELECT_HAVE_WRITE;
3463         }
3465       if (timeout)
3466         {
3467           select_timeout = *timeout;
3468           select_valid += SELECT_HAVE_TMO;
3469         }
3471       pthread_mutex_unlock (&select_mutex);
3473       /* Inform fd_handler that select should be called */
3474       c = 'g';
3475       write (selfds[1], &c, 1);
3476     }
3477   else if (nr == 0 && timeout)
3478     {
3479       /* No file descriptor, just a timeout, no need to wake fd_handler  */
3480       double time = EMACS_TIME_TO_DOUBLE (*timeout);
3481       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3482                                                       target: NSApp
3483                                                     selector:
3484                                   @selector (timeout_handler:)
3485                                                     userInfo: 0
3486                                                      repeats: NO]
3487                       retain];
3488     }
3489   else /* No timeout and no file descriptors, can this happen?  */
3490     {
3491       /* Send appdefined so we exit from the loop */
3492       ns_send_appdefined (-1);
3493     }
3495   EVENT_INIT (event);
3496   block_input ();
3497   emacs_event = &event;
3498   if (++apploopnr != 1)
3499     {
3500       emacs_abort ();
3501     }
3502   [NSApp run];
3503   --apploopnr;
3504   emacs_event = NULL;
3505   if (nr > 0 && readfds)
3506     {
3507       c = 's';
3508       write (selfds[1], &c, 1);
3509     }
3510   unblock_input ();
3512   ev = last_appdefined_event;
3514   if (ev)
3515     {
3516       int t;
3517       if ([ev type] != NSApplicationDefined)
3518         emacs_abort ();
3520       t = [ev data1];
3521       last_appdefined_event = 0;
3523       if (t == -2)
3524         {
3525           /* The NX_APPDEFINED event we received was a timeout. */
3526           result = 0;
3527         }
3528       else if (t == -1)
3529         {
3530           /* The NX_APPDEFINED event we received was the result of
3531              at least one real input event arriving.  */
3532           errno = EINTR;
3533           result = -1;
3534         }
3535       else
3536         {
3537           /* Received back from select () in fd_handler; copy the results */
3538           pthread_mutex_lock (&select_mutex);
3539           if (readfds) *readfds = select_readfds;
3540           if (writefds) *writefds = select_writefds;
3541           if (timeout) *timeout = select_timeout;
3542           pthread_mutex_unlock (&select_mutex);
3543           result = t;
3544         }
3545     }
3547   return result;
3552 /* ==========================================================================
3554     Scrollbar handling
3556    ========================================================================== */
3559 static void
3560 ns_set_vertical_scroll_bar (struct window *window,
3561                            int portion, int whole, int position)
3562 /* --------------------------------------------------------------------------
3563       External (hook): Update or add scrollbar
3564    -------------------------------------------------------------------------- */
3566   Lisp_Object win;
3567   NSRect r, v;
3568   struct frame *f = XFRAME (WINDOW_FRAME (window));
3569   EmacsView *view = FRAME_NS_VIEW (f);
3570   int window_y, window_height;
3571   int top, left, height, width, sb_width, sb_left;
3572   EmacsScroller *bar;
3573   BOOL fringe_extended_p;
3575   /* optimization; display engine sends WAY too many of these.. */
3576   if (!NILP (window->vertical_scroll_bar))
3577     {
3578       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3579       if ([bar checkSamePosition: position portion: portion whole: whole])
3580         {
3581           if (view->scrollbarsNeedingUpdate == 0)
3582             {
3583               if (!windows_or_buffers_changed)
3584                   return;
3585             }
3586           else
3587             view->scrollbarsNeedingUpdate--;
3588         }
3589     }
3591   NSTRACE (ns_set_vertical_scroll_bar);
3593   /* Get dimensions.  */
3594   window_box (window, -1, 0, &window_y, 0, &window_height);
3595   top = window_y;
3596   height = window_height;
3597   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3598   left = WINDOW_SCROLL_BAR_AREA_X (window);
3600   /* allow for displaying a skinnier scrollbar than char area allotted */
3601   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3602     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3603   sb_left = left;
3605   r = NSMakeRect (sb_left, top, sb_width, height);
3606   /* the parent view is flipped, so we need to flip y value */
3607   v = [view frame];
3608   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3610   if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (window))
3611     fringe_extended_p = (WINDOW_LEFTMOST_P (window)
3612                          && WINDOW_LEFT_FRINGE_WIDTH (window)
3613                          && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (window)
3614                              || WINDOW_LEFT_MARGIN_COLS (window) == 0));
3615   else
3616     fringe_extended_p = (WINDOW_RIGHTMOST_P (window)
3617                          && WINDOW_RIGHT_FRINGE_WIDTH (window)
3618                          && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (window)
3619                              || WINDOW_RIGHT_MARGIN_COLS (window) == 0));
3621   XSETWINDOW (win, window);
3622   block_input ();
3624   /* we want at least 5 lines to display a scrollbar */
3625   if (WINDOW_TOTAL_LINES (window) < 5)
3626     {
3627       if (!NILP (window->vertical_scroll_bar))
3628         {
3629           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3630           [bar removeFromSuperview];
3631           wset_vertical_scroll_bar (window, Qnil);
3632         }
3633       ns_clear_frame_area (f, sb_left, top, width, height);
3634       unblock_input ();
3635       return;
3636     }
3638   if (NILP (window->vertical_scroll_bar))
3639     {
3640       if (width > 0 && height > 0)
3641         {
3642           if (fringe_extended_p)
3643             ns_clear_frame_area (f, sb_left, top, sb_width, height);
3644           else
3645             ns_clear_frame_area (f, left, top, width, height);
3646         }
3648       bar = [[EmacsScroller alloc] initFrame: r window: win];
3649       wset_vertical_scroll_bar (window, make_save_value (bar, 0));
3650     }
3651   else
3652     {
3653       NSRect oldRect;
3654       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3655       oldRect = [bar frame];
3656       r.size.width = oldRect.size.width;
3657       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3658         {
3659           if (oldRect.origin.x != r.origin.x)
3660               ns_clear_frame_area (f, sb_left, top, width, height);
3661           [bar setFrame: r];
3662         }
3663     }
3665   [bar setPosition: position portion: portion whole: whole];
3666   unblock_input ();
3670 static void
3671 ns_condemn_scroll_bars (struct frame *f)
3672 /* --------------------------------------------------------------------------
3673      External (hook): arrange for all frame's scrollbars to be removed
3674      at next call to judge_scroll_bars, except for those redeemed.
3675    -------------------------------------------------------------------------- */
3677   int i;
3678   id view;
3679   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3681   NSTRACE (ns_condemn_scroll_bars);
3683   for (i =[subviews count]-1; i >= 0; i--)
3684     {
3685       view = [subviews objectAtIndex: i];
3686       if ([view isKindOfClass: [EmacsScroller class]])
3687         [view condemn];
3688     }
3692 static void
3693 ns_redeem_scroll_bar (struct window *window)
3694 /* --------------------------------------------------------------------------
3695      External (hook): arrange to spare this window's scrollbar
3696      at next call to judge_scroll_bars.
3697    -------------------------------------------------------------------------- */
3699   id bar;
3700   NSTRACE (ns_redeem_scroll_bar);
3701   if (!NILP (window->vertical_scroll_bar))
3702     {
3703       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3704       [bar reprieve];
3705     }
3709 static void
3710 ns_judge_scroll_bars (struct frame *f)
3711 /* --------------------------------------------------------------------------
3712      External (hook): destroy all scrollbars on frame that weren't
3713      redeemed after call to condemn_scroll_bars.
3714    -------------------------------------------------------------------------- */
3716   int i;
3717   id view;
3718   EmacsView *eview = FRAME_NS_VIEW (f);
3719   NSArray *subviews = [[eview superview] subviews];
3720   BOOL removed = NO;
3722   NSTRACE (ns_judge_scroll_bars);
3723   for (i = [subviews count]-1; i >= 0; --i)
3724     {
3725       view = [subviews objectAtIndex: i];
3726       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3727       [view judge];
3728       removed = YES;
3729     }
3731   if (removed)
3732     [eview updateFrameSize: NO];
3736 void
3737 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
3739   /* XXX irrelevant under NS */
3744 /* ==========================================================================
3746     Initialization
3748    ========================================================================== */
3751 x_display_pixel_height (struct ns_display_info *dpyinfo)
3753   NSScreen *screen = [NSScreen mainScreen];
3754   return [screen frame].size.height;
3758 x_display_pixel_width (struct ns_display_info *dpyinfo)
3760   NSScreen *screen = [NSScreen mainScreen];
3761   return [screen frame].size.width;
3765 static Lisp_Object ns_string_to_lispmod (const char *s)
3766 /* --------------------------------------------------------------------------
3767      Convert modifier name to lisp symbol
3768    -------------------------------------------------------------------------- */
3770   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
3771     return Qmeta;
3772   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
3773     return Qsuper;
3774   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3775     return Qcontrol;
3776   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
3777     return Qalt;
3778   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
3779     return Qhyper;
3780   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
3781     return Qnone;
3782   else
3783     return Qnil;
3787 static void
3788 ns_default (const char *parameter, Lisp_Object *result,
3789            Lisp_Object yesval, Lisp_Object noval,
3790            BOOL is_float, BOOL is_modstring)
3791 /* --------------------------------------------------------------------------
3792       Check a parameter value in user's preferences
3793    -------------------------------------------------------------------------- */
3795   const char *value = ns_get_defaults_value (parameter);
3797   if (value)
3798     {
3799       double f;
3800       char *pos;
3801       if (c_strcasecmp (value, "YES") == 0)
3802         *result = yesval;
3803       else if (c_strcasecmp (value, "NO") == 0)
3804         *result = noval;
3805       else if (is_float && (f = strtod (value, &pos), pos != value))
3806         *result = make_float (f);
3807       else if (is_modstring && value)
3808         *result = ns_string_to_lispmod (value);
3809       else fprintf (stderr,
3810                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3811     }
3815 static void
3816 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3817 /* --------------------------------------------------------------------------
3818       Initialize global info and storage for display.
3819    -------------------------------------------------------------------------- */
3821     NSScreen *screen = [NSScreen mainScreen];
3822     NSWindowDepth depth = [screen depth];
3823     Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
3825     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3826     dpyinfo->resy = 72.27;
3827     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3828                                                   NSColorSpaceFromDepth (depth)]
3829                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3830                                                  NSColorSpaceFromDepth (depth)];
3831     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3832     dpyinfo->image_cache = make_image_cache ();
3833     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
3834     dpyinfo->color_table->colors = NULL;
3835     dpyinfo->root_window = 42; /* a placeholder.. */
3837     hlinfo->mouse_face_mouse_frame = NULL;
3838     hlinfo->mouse_face_deferred_gc = 0;
3839     hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
3840     hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
3841     hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
3842     hlinfo->mouse_face_window = hlinfo->mouse_face_overlay = Qnil;
3843     hlinfo->mouse_face_hidden = 0;
3845     hlinfo->mouse_face_mouse_x = hlinfo->mouse_face_mouse_y = 0;
3846     hlinfo->mouse_face_defer = 0;
3848     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3850     dpyinfo->n_fonts = 0;
3851     dpyinfo->smallest_font_height = 1;
3852     dpyinfo->smallest_char_width = 1;
3856 /* This and next define (many of the) public functions in this file. */
3857 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3858          with using despite presence in the "system dependent" redisplay
3859          interface.  In addition, many of the ns_ methods have code that is
3860          shared with all terms, indicating need for further refactoring. */
3861 extern frame_parm_handler ns_frame_parm_handlers[];
3862 static struct redisplay_interface ns_redisplay_interface =
3864   ns_frame_parm_handlers,
3865   x_produce_glyphs,
3866   x_write_glyphs,
3867   x_insert_glyphs,
3868   x_clear_end_of_line,
3869   ns_scroll_run,
3870   ns_after_update_window_line,
3871   ns_update_window_begin,
3872   ns_update_window_end,
3873   x_cursor_to,
3874   ns_flush,
3875   0, /* flush_display_optional */
3876   x_clear_window_mouse_face,
3877   x_get_glyph_overhangs,
3878   x_fix_overlapping_area,
3879   ns_draw_fringe_bitmap,
3880   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3881   0, /* destroy_fringe_bitmap */
3882   ns_compute_glyph_string_overhangs,
3883   ns_draw_glyph_string, /* interface to nsfont.m */
3884   ns_define_frame_cursor,
3885   ns_clear_frame_area,
3886   ns_draw_window_cursor,
3887   ns_draw_vertical_window_border,
3888   ns_shift_glyphs_for_insert
3892 static void
3893 ns_delete_display (struct ns_display_info *dpyinfo)
3895   /* TODO... */
3899 /* This function is called when the last frame on a display is deleted. */
3900 static void
3901 ns_delete_terminal (struct terminal *terminal)
3903   struct ns_display_info *dpyinfo = terminal->display_info.ns;
3905   /* Protect against recursive calls.  delete_frame in
3906      delete_terminal calls us back when it deletes our last frame.  */
3907   if (!terminal->name)
3908     return;
3910   block_input ();
3912   x_destroy_all_bitmaps (dpyinfo);
3913   ns_delete_display (dpyinfo);
3914   unblock_input ();
3918 static struct terminal *
3919 ns_create_terminal (struct ns_display_info *dpyinfo)
3920 /* --------------------------------------------------------------------------
3921       Set up use of NS before we make the first connection.
3922    -------------------------------------------------------------------------- */
3924   struct terminal *terminal;
3926   NSTRACE (ns_create_terminal);
3928   terminal = create_terminal ();
3930   terminal->type = output_ns;
3931   terminal->display_info.ns = dpyinfo;
3932   dpyinfo->terminal = terminal;
3934   terminal->rif = &ns_redisplay_interface;
3936   terminal->clear_frame_hook = ns_clear_frame;
3937   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
3938   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
3939   terminal->ring_bell_hook = ns_ring_bell;
3940   terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
3941   terminal->set_terminal_modes_hook = ns_set_terminal_modes;
3942   terminal->update_begin_hook = ns_update_begin;
3943   terminal->update_end_hook = ns_update_end;
3944   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
3945   terminal->read_socket_hook = ns_read_socket;
3946   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
3947   terminal->mouse_position_hook = ns_mouse_position;
3948   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
3949   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
3951   terminal->fullscreen_hook = ns_fullscreen_hook;
3953   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
3954   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
3955   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
3956   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
3958   terminal->delete_frame_hook = x_destroy_window;
3959   terminal->delete_terminal_hook = ns_delete_terminal;
3961   terminal->scroll_region_ok = 1;
3962   terminal->char_ins_del_ok = 1;
3963   terminal->line_ins_del_ok = 1;
3964   terminal->fast_clear_end_of_line = 1;
3965   terminal->memory_below_frame = 0;
3967   return terminal;
3971 struct ns_display_info *
3972 ns_term_init (Lisp_Object display_name)
3973 /* --------------------------------------------------------------------------
3974      Start the Application and get things rolling.
3975    -------------------------------------------------------------------------- */
3977   struct terminal *terminal;
3978   struct ns_display_info *dpyinfo;
3979   static int ns_initialized = 0;
3980   Lisp_Object tmp;
3982   if (ns_initialized) return x_display_list;
3983   ns_initialized = 1;
3985   NSTRACE (ns_term_init);
3987   [outerpool release];
3988   outerpool = [[NSAutoreleasePool alloc] init];
3990   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
3991   /*GSDebugAllocationActive (YES); */
3992   block_input ();
3994   baud_rate = 38400;
3995   Fset_input_interrupt_mode (Qnil);
3997   if (selfds[0] == -1)
3998     {
3999       if (pipe (selfds) == -1)
4000         {
4001           fprintf (stderr, "Failed to create pipe: %s\n",
4002                    emacs_strerror (errno));
4003           emacs_abort ();
4004         }
4006       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4007       FD_ZERO (&select_readfds);
4008       FD_ZERO (&select_writefds);
4009       pthread_mutex_init (&select_mutex, NULL);
4010     }
4012   ns_pending_files = [[NSMutableArray alloc] init];
4013   ns_pending_service_names = [[NSMutableArray alloc] init];
4014   ns_pending_service_args = [[NSMutableArray alloc] init];
4016 /* Start app and create the main menu, window, view.
4017      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4018      The view will then ask the NSApp to stop and return to Emacs. */
4019   [EmacsApp sharedApplication];
4020   if (NSApp == nil)
4021     return NULL;
4022   [NSApp setDelegate: NSApp];
4024   /* Start the select thread.  */
4025   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4026                            toTarget:NSApp
4027                          withObject:nil];
4029   /* debugging: log all notifications */
4030   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4031                                          selector: @selector (logNotification:)
4032                                              name: nil object: nil]; */
4034   dpyinfo = xzalloc (sizeof *dpyinfo);
4036   ns_initialize_display_info (dpyinfo);
4037   terminal = ns_create_terminal (dpyinfo);
4039   terminal->kboard = xmalloc (sizeof *terminal->kboard);
4040   init_kboard (terminal->kboard);
4041   kset_window_system (terminal->kboard, Qns);
4042   terminal->kboard->next_kboard = all_kboards;
4043   all_kboards = terminal->kboard;
4044   /* Don't let the initial kboard remain current longer than necessary.
4045      That would cause problems if a file loaded on startup tries to
4046      prompt in the mini-buffer.  */
4047   if (current_kboard == initial_kboard)
4048     current_kboard = terminal->kboard;
4049   terminal->kboard->reference_count++;
4051   dpyinfo->next = x_display_list;
4052   x_display_list = dpyinfo;
4054   /* Put it on ns_display_name_list */
4055   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
4056                                 ns_display_name_list);
4057   dpyinfo->name_list_element = XCAR (ns_display_name_list);
4059   terminal->name = xstrdup (SSDATA (display_name));
4061   unblock_input ();
4063   if (!inhibit_x_resources)
4064     {
4065       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4066                  Qt, Qnil, NO, NO);
4067       tmp = Qnil;
4068       /* this is a standard variable */
4069       ns_default ("AppleAntiAliasingThreshold", &tmp,
4070                  make_float (10.0), make_float (6.0), YES, NO);
4071       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4072     }
4074   ns_selection_color = [[NSUserDefaults standardUserDefaults]
4075                          stringForKey: @"AppleHighlightColor"];
4076   if (ns_selection_color == nil)
4077     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
4079   {
4080     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4082     if ( cl == nil )
4083       {
4084         Lisp_Object color_file, color_map, color;
4085         unsigned long c;
4086         char *name;
4088         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4089                          Fsymbol_value (intern ("data-directory")));
4090         if (NILP (Ffile_readable_p (color_file)))
4091           fatal ("Could not find %s.\n", SDATA (color_file));
4093         color_map = Fx_load_color_file (color_file);
4094         if (NILP (color_map))
4095           fatal ("Could not read %s.\n", SDATA (color_file));
4097         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4098         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4099           {
4100             color = XCAR (color_map);
4101             name = SSDATA (XCAR (color));
4102             c = XINT (XCDR (color));
4103             [cl setColor:
4104                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4105                                             green: GREEN_FROM_ULONG (c) / 255.0
4106                                              blue: BLUE_FROM_ULONG (c) / 255.0
4107                                             alpha: 1.0]
4108                   forKey: [NSString stringWithUTF8String: name]];
4109           }
4110         [cl writeToFile: nil];
4111       }
4112   }
4114   {
4115 #ifdef NS_IMPL_GNUSTEP
4116     Vwindow_system_version = build_string (gnustep_base_version);
4117 #else
4118     /*PSnextrelease (128, c); */
4119     char c[DBL_BUFSIZE_BOUND];
4120     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4121     Vwindow_system_version = make_unibyte_string (c, len);
4122 #endif
4123   }
4125   delete_keyboard_wait_descriptor (0);
4127   ns_app_name = [[NSProcessInfo processInfo] processName];
4129 /* Set up OS X app menu */
4130 #ifdef NS_IMPL_COCOA
4131   {
4132     NSMenu *appMenu;
4133     NSMenuItem *item;
4134     /* set up the application menu */
4135     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4136     [svcsMenu setAutoenablesItems: NO];
4137     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4138     [appMenu setAutoenablesItems: NO];
4139     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4140     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4142     [appMenu insertItemWithTitle: @"About Emacs"
4143                           action: @selector (orderFrontStandardAboutPanel:)
4144                    keyEquivalent: @""
4145                          atIndex: 0];
4146     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4147     [appMenu insertItemWithTitle: @"Preferences..."
4148                           action: @selector (showPreferencesWindow:)
4149                    keyEquivalent: @","
4150                          atIndex: 2];
4151     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4152     item = [appMenu insertItemWithTitle: @"Services"
4153                                  action: @selector (menuDown:)
4154                           keyEquivalent: @""
4155                                 atIndex: 4];
4156     [appMenu setSubmenu: svcsMenu forItem: item];
4157     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4158     [appMenu insertItemWithTitle: @"Hide Emacs"
4159                           action: @selector (hide:)
4160                    keyEquivalent: @"h"
4161                          atIndex: 6];
4162     item =  [appMenu insertItemWithTitle: @"Hide Others"
4163                           action: @selector (hideOtherApplications:)
4164                    keyEquivalent: @"h"
4165                          atIndex: 7];
4166     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4167     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4168     [appMenu insertItemWithTitle: @"Quit Emacs"
4169                           action: @selector (terminate:)
4170                    keyEquivalent: @"q"
4171                          atIndex: 9];
4173     item = [mainMenu insertItemWithTitle: ns_app_name
4174                                   action: @selector (menuDown:)
4175                            keyEquivalent: @""
4176                                  atIndex: 0];
4177     [mainMenu setSubmenu: appMenu forItem: item];
4178     [dockMenu insertItemWithTitle: @"New Frame"
4179                            action: @selector (newFrame:)
4180                     keyEquivalent: @""
4181                           atIndex: 0];
4183     [NSApp setMainMenu: mainMenu];
4184     [NSApp setAppleMenu: appMenu];
4185     [NSApp setServicesMenu: svcsMenu];
4186     /* Needed at least on Cocoa, to get dock menu to show windows */
4187     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4189     [[NSNotificationCenter defaultCenter]
4190       addObserver: mainMenu
4191          selector: @selector (trackingNotification:)
4192              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4193     [[NSNotificationCenter defaultCenter]
4194       addObserver: mainMenu
4195          selector: @selector (trackingNotification:)
4196              name: NSMenuDidEndTrackingNotification object: mainMenu];
4197   }
4198 #endif /* MAC OS X menu setup */
4200   /* Register our external input/output types, used for determining
4201      applicable services and also drag/drop eligibility. */
4202   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4203   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4204                       retain];
4205   ns_drag_types = [[NSArray arrayWithObjects:
4206                             NSStringPboardType,
4207                             NSTabularTextPboardType,
4208                             NSFilenamesPboardType,
4209                             NSURLPboardType,
4210                             NSColorPboardType,
4211                             NSFontPboardType, nil] retain];
4214   [NSApp run];
4215   ns_do_open_file = YES;
4216   return dpyinfo;
4220 void
4221 ns_term_shutdown (int sig)
4223   [[NSUserDefaults standardUserDefaults] synchronize];
4225   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4226   if (STRINGP (Vauto_save_list_file_name))
4227     unlink (SSDATA (Vauto_save_list_file_name));
4229   if (sig == 0 || sig == SIGTERM)
4230     {
4231       [NSApp terminate: NSApp];
4232     }
4233   else // force a stack trace to happen
4234     {
4235       emacs_abort ();
4236     }
4240 /* ==========================================================================
4242     EmacsApp implementation
4244    ========================================================================== */
4247 @implementation EmacsApp
4249 - (void)logNotification: (NSNotification *)notification
4251   const char *name = [[notification name] UTF8String];
4252   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4253       && !strstr (name, "WindowNumber"))
4254     NSLog (@"notification: '%@'", [notification name]);
4258 - (void)sendEvent: (NSEvent *)theEvent
4259 /* --------------------------------------------------------------------------
4260      Called when NSApp is running for each event received.  Used to stop
4261      the loop when we choose, since there's no way to just run one iteration.
4262    -------------------------------------------------------------------------- */
4264   int type = [theEvent type];
4265   NSWindow *window = [theEvent window];
4266 /*  NSTRACE (sendEvent); */
4267 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4269 #ifdef NS_IMPL_COCOA
4270   if (type == NSApplicationDefined
4271       && [theEvent data2] == NSAPP_DATA2_RUNASSCRIPT)
4272     {
4273       ns_run_ascript ();
4274       [self stop: self];
4275       return;
4276     }
4277 #endif
4279   if (type == NSCursorUpdate && window == nil)
4280     {
4281       fprintf (stderr, "Dropping external cursor update event.\n");
4282       return;
4283     }
4285 #ifdef NS_IMPL_COCOA
4286   /* pass mouse down in resize handle and subsequent drags directly to
4287      EmacsWindow so we can generate continuous redisplays */
4288   if (ns_in_resize)
4289     {
4290       if (type == NSLeftMouseDragged)
4291         {
4292           [window mouseDragged: theEvent];
4293           return;
4294         }
4295       else if (type == NSLeftMouseUp)
4296         {
4297           [window mouseUp: theEvent];
4298           return;
4299         }
4300     }
4301   else if (type == NSLeftMouseDown)
4302     {
4303       NSRect r = ns_resize_handle_rect (window);
4304       if (NSPointInRect ([theEvent locationInWindow], r))
4305         {
4306           ns_in_resize = YES;
4307           [window mouseDown: theEvent];
4308           return;
4309         }
4310     }
4311 #endif
4313   if (type == NSApplicationDefined)
4314     {
4315       /* Events posted by ns_send_appdefined interrupt the run loop here.
4316          But, if a modal window is up, an appdefined can still come through,
4317          (e.g., from a makeKeyWindow event) but stopping self also stops the
4318          modal loop. Just defer it until later. */
4319       if ([NSApp modalWindow] == nil)
4320         {
4321           last_appdefined_event = theEvent;
4322           [self stop: self];
4323         }
4324       else
4325         {
4326           send_appdefined = YES;
4327         }
4328     }
4330   [super sendEvent: theEvent];
4334 - (void)showPreferencesWindow: (id)sender
4336   struct frame *emacsframe = SELECTED_FRAME ();
4337   NSEvent *theEvent = [NSApp currentEvent];
4339   if (!emacs_event)
4340     return;
4341   emacs_event->kind = NS_NONKEY_EVENT;
4342   emacs_event->code = KEY_NS_SHOW_PREFS;
4343   emacs_event->modifiers = 0;
4344   EV_TRAILER (theEvent);
4348 - (void)newFrame: (id)sender
4350   struct frame *emacsframe = SELECTED_FRAME ();
4351   NSEvent *theEvent = [NSApp currentEvent];
4353   if (!emacs_event)
4354     return;
4355   emacs_event->kind = NS_NONKEY_EVENT;
4356   emacs_event->code = KEY_NS_NEW_FRAME;
4357   emacs_event->modifiers = 0;
4358   EV_TRAILER (theEvent);
4362 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4363 - (BOOL) openFile: (NSString *)fileName
4365   struct frame *emacsframe = SELECTED_FRAME ();
4366   NSEvent *theEvent = [NSApp currentEvent];
4368   if (!emacs_event)
4369     return NO;
4371   emacs_event->kind = NS_NONKEY_EVENT;
4372   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4373   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4374   ns_input_line = Qnil; /* can be start or cons start,end */
4375   emacs_event->modifiers =0;
4376   EV_TRAILER (theEvent);
4378   return YES;
4382 /* **************************************************************************
4384       EmacsApp delegate implementation
4386    ************************************************************************** */
4388 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4389 /* --------------------------------------------------------------------------
4390      When application is loaded, terminate event loop in ns_term_init
4391    -------------------------------------------------------------------------- */
4393   NSTRACE (applicationDidFinishLaunching);
4394   [NSApp setServicesProvider: NSApp];
4395   ns_send_appdefined (-2);
4399 /* Termination sequences:
4400     C-x C-c:
4401     Cmd-Q:
4402     MenuBar | File | Exit:
4403     Select Quit from App menubar:
4404         -terminate
4405         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4406         ns_term_shutdown()
4408     Select Quit from Dock menu:
4409     Logout attempt:
4410         -appShouldTerminate
4411           Cancel -> Nothing else
4412           Accept ->
4414           -terminate
4415           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4416           ns_term_shutdown()
4420 - (void) terminate: (id)sender
4422   struct frame *emacsframe = SELECTED_FRAME ();
4424   if (!emacs_event)
4425     return;
4427   emacs_event->kind = NS_NONKEY_EVENT;
4428   emacs_event->code = KEY_NS_POWER_OFF;
4429   emacs_event->arg = Qt; /* mark as non-key event */
4430   EV_TRAILER ((id)nil);
4434 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4436   int ret;
4438   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4439     return NSTerminateNow;
4441     ret = NSRunAlertPanel(ns_app_name,
4442                           @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
4443                           @"Save Buffers and Exit", @"Cancel", nil);
4445     if (ret == NSAlertDefaultReturn)
4446         return NSTerminateNow;
4447     else if (ret == NSAlertAlternateReturn)
4448         return NSTerminateCancel;
4449     return NSTerminateNow;  /* just in case */
4452 static int
4453 not_in_argv (NSString *arg)
4455   int k;
4456   const char *a = [arg UTF8String];
4457   for (k = 1; k < initial_argc; ++k)
4458     if (strcmp (a, initial_argv[k]) == 0) return 0;
4459   return 1;
4462 /*   Notification from the Workspace to open a file */
4463 - (BOOL)application: sender openFile: (NSString *)file
4465   if (ns_do_open_file || not_in_argv (file))
4466     [ns_pending_files addObject: file];
4467   return YES;
4471 /*   Open a file as a temporary file */
4472 - (BOOL)application: sender openTempFile: (NSString *)file
4474   if (ns_do_open_file || not_in_argv (file))
4475     [ns_pending_files addObject: file];
4476   return YES;
4480 /*   Notification from the Workspace to open a file noninteractively (?) */
4481 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4483   if (ns_do_open_file || not_in_argv (file))
4484     [ns_pending_files addObject: file];
4485   return YES;
4488 /*   Notification from the Workspace to open multiple files */
4489 - (void)application: sender openFiles: (NSArray *)fileList
4491   NSEnumerator *files = [fileList objectEnumerator];
4492   NSString *file;
4493   /* Don't open files from the command line unconditionally,
4494      Cocoa parses the command line wrong, --option value tries to open value
4495      if --option is the last option.  */
4496   while ((file = [files nextObject]) != nil)
4497     if (ns_do_open_file || not_in_argv (file))
4498       [ns_pending_files addObject: file];
4500   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4505 /* Handle dock menu requests.  */
4506 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4508   return dockMenu;
4512 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4513 - (void)applicationWillBecomeActive: (NSNotification *)notification
4515   //ns_app_active=YES;
4517 - (void)applicationDidBecomeActive: (NSNotification *)notification
4519   NSTRACE (applicationDidBecomeActive);
4521   //ns_app_active=YES;
4523   ns_update_auto_hide_menu_bar ();
4524   // No constraining takes place when the application is not active.
4525   ns_constrain_all_frames ();
4527 - (void)applicationDidResignActive: (NSNotification *)notification
4529   //ns_app_active=NO;
4530   ns_send_appdefined (-1);
4535 /* ==========================================================================
4537     EmacsApp aux handlers for managing event loop
4539    ========================================================================== */
4542 - (void)timeout_handler: (NSTimer *)timedEntry
4543 /* --------------------------------------------------------------------------
4544      The timeout specified to ns_select has passed.
4545    -------------------------------------------------------------------------- */
4547   /*NSTRACE (timeout_handler); */
4548   ns_send_appdefined (-2);
4551 - (void)fd_handler:(id)unused
4552 /* --------------------------------------------------------------------------
4553      Check data waiting on file descriptors and terminate if so
4554    -------------------------------------------------------------------------- */
4556   int result;
4557   int waiting = 1, nfds;
4558   char c;
4560   SELECT_TYPE readfds, writefds, *wfds;
4561   EMACS_TIME timeout, *tmo;
4562   NSAutoreleasePool *pool = nil;
4564   /* NSTRACE (fd_handler); */
4566   for (;;)
4567     {
4568       [pool release];
4569       pool = [[NSAutoreleasePool alloc] init];
4571       if (waiting)
4572         {
4573           SELECT_TYPE fds;
4575           FD_SET (selfds[0], &fds);
4576           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
4577           if (result > 0)
4578             {
4579               read (selfds[0], &c, 1);
4580               if (c == 'g') waiting = 0;
4581             }
4582         }
4583       else
4584         {
4585           pthread_mutex_lock (&select_mutex);
4586           nfds = select_nfds;
4588           if (select_valid & SELECT_HAVE_READ)
4589             readfds = select_readfds;
4590           else
4591             FD_ZERO (&readfds);
4593           if (select_valid & SELECT_HAVE_WRITE)
4594             {
4595               writefds = select_writefds;
4596               wfds = &writefds;
4597             }
4598           else
4599             wfds = NULL;
4600           if (select_valid & SELECT_HAVE_TMO)
4601             {
4602               timeout = select_timeout;
4603               tmo = &timeout;
4604             }
4605           else
4606             tmo = NULL;
4608           pthread_mutex_unlock (&select_mutex);
4610           FD_SET (selfds[0], &readfds);
4611           if (selfds[0] >= nfds) nfds = selfds[0]+1;
4613           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
4615           if (result == 0)
4616             ns_send_appdefined (-2);
4617           else if (result > 0)
4618             {
4619               if (FD_ISSET (selfds[0], &readfds))
4620                 {
4621                   read (selfds[0], &c, 1);
4622                   if (c == 's') waiting = 1;
4623                 }
4624               else
4625                 {
4626                   pthread_mutex_lock (&select_mutex);
4627                   if (select_valid & SELECT_HAVE_READ)
4628                     select_readfds = readfds;
4629                   if (select_valid & SELECT_HAVE_WRITE)
4630                     select_writefds = writefds;
4631                   if (select_valid & SELECT_HAVE_TMO)
4632                     select_timeout = timeout;
4633                   pthread_mutex_unlock (&select_mutex);
4635                   ns_send_appdefined (result);
4636                 }
4637             }
4638           waiting = 1;
4639         }
4640     }
4645 /* ==========================================================================
4647     Service provision
4649    ========================================================================== */
4651 /* called from system: queue for next pass through event loop */
4652 - (void)requestService: (NSPasteboard *)pboard
4653               userData: (NSString *)userData
4654                  error: (NSString **)error
4656   [ns_pending_service_names addObject: userData];
4657   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4658       SSDATA (ns_string_from_pasteboard (pboard))]];
4662 /* called from ns_read_socket to clear queue */
4663 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4665   struct frame *emacsframe = SELECTED_FRAME ();
4666   NSEvent *theEvent = [NSApp currentEvent];
4668   if (!emacs_event)
4669     return NO;
4671   emacs_event->kind = NS_NONKEY_EVENT;
4672   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4673   ns_input_spi_name = build_string ([name UTF8String]);
4674   ns_input_spi_arg = build_string ([arg UTF8String]);
4675   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4676   EV_TRAILER (theEvent);
4678   return YES;
4682 @end  /* EmacsApp */
4686 /* ==========================================================================
4688     EmacsView implementation
4690    ========================================================================== */
4693 @implementation EmacsView
4695 /* needed to inform when window closed from LISP */
4696 - (void) setWindowClosing: (BOOL)closing
4698   windowClosing = closing;
4702 - (void)dealloc
4704   NSTRACE (EmacsView_dealloc);
4705   [toolbar release];
4706   if (fs_state == FULLSCREEN_BOTH)
4707     [nonfs_window release];
4708   [super dealloc];
4712 /* called on font panel selection */
4713 - (void)changeFont: (id)sender
4715   NSEvent *e =[[self window] currentEvent];
4716   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4717   id newFont;
4718   float size;
4720   NSTRACE (changeFont);
4721   if (!emacs_event)
4722     return;
4724   if ((newFont = [sender convertFont:
4725                            ((struct nsfont_info *)face->font)->nsfont]))
4726     {
4727       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4729       emacs_event->kind = NS_NONKEY_EVENT;
4730       emacs_event->modifiers = 0;
4731       emacs_event->code = KEY_NS_CHANGE_FONT;
4733       size = [newFont pointSize];
4734       ns_input_fontsize = make_number (lrint (size));
4735       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4736       EV_TRAILER (e);
4737     }
4741 - (BOOL)acceptsFirstResponder
4743   NSTRACE (acceptsFirstResponder);
4744   return YES;
4748 - (void)resetCursorRects
4750   NSRect visible = [self visibleRect];
4751   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4752   NSTRACE (resetCursorRects);
4754   if (currentCursor == nil)
4755     currentCursor = [NSCursor arrowCursor];
4757   if (!NSIsEmptyRect (visible))
4758     [self addCursorRect: visible cursor: currentCursor];
4759   [currentCursor setOnMouseEntered: YES];
4764 /*****************************************************************************/
4765 /* Keyboard handling. */
4766 #define NS_KEYLOG 0
4768 - (void)keyDown: (NSEvent *)theEvent
4770   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4771   int code;
4772   unsigned fnKeysym = 0;
4773   int flags;
4774   static NSMutableArray *nsEvArray;
4775 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4776   static BOOL firstTime = YES;
4777 #endif
4778   int left_is_none;
4780   NSTRACE (keyDown);
4782   /* Rhapsody and OS X give up and down events for the arrow keys */
4783   if (ns_fake_keydown == YES)
4784     ns_fake_keydown = NO;
4785   else if ([theEvent type] != NSKeyDown)
4786     return;
4788   if (!emacs_event)
4789     return;
4791  if (![[self window] isKeyWindow]
4792      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4793      /* we must avoid an infinite loop here. */
4794      && (EmacsView *)[[theEvent window] delegate] != self)
4795    {
4796      /* XXX: There is an occasional condition in which, when Emacs display
4797          updates a different frame from the current one, and temporarily
4798          selects it, then processes some interrupt-driven input
4799          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4800          for some reason that window has its first responder set to the NSView
4801          most recently updated (I guess), which is not the correct one. */
4802      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4803      return;
4804    }
4806   if (nsEvArray == nil)
4807     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4809   [NSCursor setHiddenUntilMouseMoves: YES];
4811   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4812     {
4813       clear_mouse_face (hlinfo);
4814       hlinfo->mouse_face_hidden = 1;
4815     }
4817   if (!processingCompose)
4818     {
4819       /* When using screen sharing, no left or right information is sent,
4820          so use Left key in those cases.  */
4821       int is_left_key, is_right_key;
4823       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4824         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4826       /* (Carbon way: [theEvent keyCode]) */
4828       /* is it a "function key"? */
4829       fnKeysym = ns_convert_key (code);
4830       if (fnKeysym)
4831         {
4832           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4833              because Emacs treats Delete and KP-Delete same (in simple.el). */
4834           if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4835             code = 0xFF08; /* backspace */
4836           else
4837             code = fnKeysym;
4838         }
4840       /* are there modifiers? */
4841       emacs_event->modifiers = 0;
4842       flags = [theEvent modifierFlags];
4844       if (flags & NSHelpKeyMask)
4845           emacs_event->modifiers |= hyper_modifier;
4847       if (flags & NSShiftKeyMask)
4848         emacs_event->modifiers |= shift_modifier;
4850       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
4851       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
4852         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
4854       if (is_right_key)
4855         emacs_event->modifiers |= parse_solitary_modifier
4856           (EQ (ns_right_command_modifier, Qleft)
4857            ? ns_command_modifier
4858            : ns_right_command_modifier);
4860       if (is_left_key)
4861         {
4862           emacs_event->modifiers |= parse_solitary_modifier
4863             (ns_command_modifier);
4865           /* if super (default), take input manager's word so things like
4866              dvorak / qwerty layout work */
4867           if (EQ (ns_command_modifier, Qsuper)
4868               && !fnKeysym
4869               && [[theEvent characters] length] != 0)
4870             {
4871               /* XXX: the code we get will be unshifted, so if we have
4872                  a shift modifier, must convert ourselves */
4873               if (!(flags & NSShiftKeyMask))
4874                 code = [[theEvent characters] characterAtIndex: 0];
4875 #if 0
4876               /* this is ugly and also requires linking w/Carbon framework
4877                  (for LMGetKbdType) so for now leave this rare (?) case
4878                  undealt with.. in future look into CGEvent methods */
4879               else
4880                 {
4881                   long smv = GetScriptManagerVariable (smKeyScript);
4882                   Handle uchrHandle = GetResource
4883                     ('uchr', GetScriptVariable (smv, smScriptKeys));
4884                   UInt32 dummy = 0;
4885                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
4886                                  [[theEvent characters] characterAtIndex: 0],
4887                                  kUCKeyActionDisplay,
4888                                  (flags & ~NSCommandKeyMask) >> 8,
4889                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
4890                                  &dummy, 1, &dummy, &code);
4891                   code &= 0xFF;
4892                 }
4893 #endif
4894             }
4895         }
4897       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
4898       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
4899         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
4901       if (is_right_key)
4902           emacs_event->modifiers |= parse_solitary_modifier
4903               (EQ (ns_right_control_modifier, Qleft)
4904                ? ns_control_modifier
4905                : ns_right_control_modifier);
4907       if (is_left_key)
4908         emacs_event->modifiers |= parse_solitary_modifier
4909           (ns_control_modifier);
4911       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
4912           emacs_event->modifiers |=
4913             parse_solitary_modifier (ns_function_modifier);
4915       left_is_none = NILP (ns_alternate_modifier)
4916         || EQ (ns_alternate_modifier, Qnone);
4918       is_right_key = (flags & NSRightAlternateKeyMask)
4919         == NSRightAlternateKeyMask;
4920       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
4921         || (! is_right_key
4922             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
4924       if (is_right_key)
4925         {
4926           if ((NILP (ns_right_alternate_modifier)
4927                || EQ (ns_right_alternate_modifier, Qnone)
4928                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
4929               && !fnKeysym)
4930             {   /* accept pre-interp alt comb */
4931               if ([[theEvent characters] length] > 0)
4932                 code = [[theEvent characters] characterAtIndex: 0];
4933               /*HACK: clear lone shift modifier to stop next if from firing */
4934               if (emacs_event->modifiers == shift_modifier)
4935                 emacs_event->modifiers = 0;
4936             }
4937           else
4938             emacs_event->modifiers |= parse_solitary_modifier
4939               (EQ (ns_right_alternate_modifier, Qleft)
4940                ? ns_alternate_modifier
4941                : ns_right_alternate_modifier);
4942         }
4944       if (is_left_key) /* default = meta */
4945         {
4946           if (left_is_none && !fnKeysym)
4947             {   /* accept pre-interp alt comb */
4948               if ([[theEvent characters] length] > 0)
4949                 code = [[theEvent characters] characterAtIndex: 0];
4950               /*HACK: clear lone shift modifier to stop next if from firing */
4951               if (emacs_event->modifiers == shift_modifier)
4952                 emacs_event->modifiers = 0;
4953             }
4954           else
4955               emacs_event->modifiers |=
4956                 parse_solitary_modifier (ns_alternate_modifier);
4957         }
4959   if (NS_KEYLOG)
4960     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
4961              code, fnKeysym, flags, emacs_event->modifiers);
4963       /* if it was a function key or had modifiers, pass it directly to emacs */
4964       if (fnKeysym || (emacs_event->modifiers
4965                        && (emacs_event->modifiers != shift_modifier)
4966                        && [[theEvent charactersIgnoringModifiers] length] > 0))
4967 /*[[theEvent characters] length] */
4968         {
4969           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4970           if (code < 0x20)
4971             code |= (1<<28)|(3<<16);
4972           else if (code == 0x7f)
4973             code |= (1<<28)|(3<<16);
4974           else if (!fnKeysym)
4975             emacs_event->kind = code > 0xFF
4976               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4978           emacs_event->code = code;
4979           EV_TRAILER (theEvent);
4980           return;
4981         }
4982     }
4985 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4986   /* if we get here we should send the key for input manager processing */
4987   if (firstTime && [[NSInputManager currentInputManager]
4988                      wantsToDelayTextChangeNotifications] == NO)
4989     fprintf (stderr,
4990           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
4991   firstTime = NO;
4992 #endif
4993   if (NS_KEYLOG && !processingCompose)
4994     fprintf (stderr, "keyDown: Begin compose sequence.\n");
4996   processingCompose = YES;
4997   [nsEvArray addObject: theEvent];
4998   [self interpretKeyEvents: nsEvArray];
4999   [nsEvArray removeObject: theEvent];
5003 #ifdef NS_IMPL_COCOA
5004 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5005    decided not to send key-down for.
5006    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5007    This only applies on Tiger and earlier.
5008    If it matches one of these, send it on to keyDown. */
5009 -(void)keyUp: (NSEvent *)theEvent
5011   int flags = [theEvent modifierFlags];
5012   int code = [theEvent keyCode];
5013   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5014       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5015     {
5016       if (NS_KEYLOG)
5017         fprintf (stderr, "keyUp: passed test");
5018       ns_fake_keydown = YES;
5019       [self keyDown: theEvent];
5020     }
5022 #endif
5025 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5028 /* <NSTextInput>: called when done composing;
5029    NOTE: also called when we delete over working text, followed immed.
5030          by doCommandBySelector: deleteBackward: */
5031 - (void)insertText: (id)aString
5033   int code;
5034   int len = [(NSString *)aString length];
5035   int i;
5037   if (NS_KEYLOG)
5038     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5039   processingCompose = NO;
5041   if (!emacs_event)
5042     return;
5044   /* first, clear any working text */
5045   if (workingText != nil)
5046     [self deleteWorkingText];
5048   /* now insert the string as keystrokes */
5049   for (i =0; i<len; i++)
5050     {
5051       code = [aString characterAtIndex: i];
5052       /* TODO: still need this? */
5053       if (code == 0x2DC)
5054         code = '~'; /* 0x7E */
5055       if (code != 32) /* Space */
5056         emacs_event->modifiers = 0;
5057       emacs_event->kind
5058         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5059       emacs_event->code = code;
5060       EV_TRAILER ((id)nil);
5061     }
5065 /* <NSTextInput>: inserts display of composing characters */
5066 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5068   NSString *str = [aString respondsToSelector: @selector (string)] ?
5069     [aString string] : aString;
5070   if (NS_KEYLOG)
5071     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
5072            selRange.length, selRange.location);
5074   if (workingText != nil)
5075     [self deleteWorkingText];
5076   if ([str length] == 0)
5077     return;
5079   if (!emacs_event)
5080     return;
5082   processingCompose = YES;
5083   workingText = [str copy];
5084   ns_working_text = build_string ([workingText UTF8String]);
5086   emacs_event->kind = NS_TEXT_EVENT;
5087   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5088   EV_TRAILER ((id)nil);
5092 /* delete display of composing characters [not in <NSTextInput>] */
5093 - (void)deleteWorkingText
5095   if (workingText == nil)
5096     return;
5097   if (NS_KEYLOG)
5098     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
5099   [workingText release];
5100   workingText = nil;
5101   processingCompose = NO;
5103   if (!emacs_event)
5104     return;
5106   emacs_event->kind = NS_TEXT_EVENT;
5107   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5108   EV_TRAILER ((id)nil);
5112 - (BOOL)hasMarkedText
5114   return workingText != nil;
5118 - (NSRange)markedRange
5120   NSRange rng = workingText != nil
5121     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5122   if (NS_KEYLOG)
5123     NSLog (@"markedRange request");
5124   return rng;
5128 - (void)unmarkText
5130   if (NS_KEYLOG)
5131     NSLog (@"unmark (accept) text");
5132   [self deleteWorkingText];
5133   processingCompose = NO;
5137 /* used to position char selection windows, etc. */
5138 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5140   NSRect rect;
5141   NSPoint pt;
5142   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5143   if (NS_KEYLOG)
5144     NSLog (@"firstRectForCharRange request");
5146   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5147   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5148   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5149   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5150                                        +FRAME_LINE_HEIGHT (emacsframe));
5152   pt = [self convertPoint: pt toView: nil];
5153   pt = [[self window] convertBaseToScreen: pt];
5154   rect.origin = pt;
5155   return rect;
5159 - (NSInteger)conversationIdentifier
5161   return (NSInteger)self;
5165 - (void)doCommandBySelector: (SEL)aSelector
5167   if (NS_KEYLOG)
5168     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5170   if (aSelector == @selector (deleteBackward:))
5171     {
5172       /* happens when user backspaces over an ongoing composition:
5173          throw a 'delete' into the event queue */
5174       if (!emacs_event)
5175         return;
5176       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5177       emacs_event->code = 0xFF08;
5178       EV_TRAILER ((id)nil);
5179     }
5182 - (NSArray *)validAttributesForMarkedText
5184   static NSArray *arr = nil;
5185   if (arr == nil) arr = [NSArray new];
5186  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5187   return arr;
5190 - (NSRange)selectedRange
5192   if (NS_KEYLOG)
5193     NSLog (@"selectedRange request");
5194   return NSMakeRange (NSNotFound, 0);
5197 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5199   if (NS_KEYLOG)
5200     NSLog (@"characterIndexForPoint request");
5201   return 0;
5204 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5206   static NSAttributedString *str = nil;
5207   if (str == nil) str = [NSAttributedString new];
5208   if (NS_KEYLOG)
5209     NSLog (@"attributedSubstringFromRange request");
5210   return str;
5213 /* End <NSTextInput> impl. */
5214 /*****************************************************************************/
5217 /* This is what happens when the user presses a mouse button.  */
5218 - (void)mouseDown: (NSEvent *)theEvent
5220   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5222   NSTRACE (mouseDown);
5224   [self deleteWorkingText];
5226   if (!emacs_event)
5227     return;
5229   last_mouse_frame = emacsframe;
5230   /* appears to be needed to prevent spurious movement events generated on
5231      button clicks */
5232   last_mouse_frame->mouse_moved = 0;
5234   if ([theEvent type] == NSScrollWheel)
5235     {
5236       float delta = [theEvent deltaY];
5237       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5238       if (delta == 0)
5239         return;
5240       emacs_event->kind = WHEEL_EVENT;
5241       emacs_event->code = 0;
5242       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5243         ((delta > 0) ? up_modifier : down_modifier);
5244     }
5245   else
5246     {
5247       emacs_event->kind = MOUSE_CLICK_EVENT;
5248       emacs_event->code = EV_BUTTON (theEvent);
5249       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5250                              | EV_UDMODIFIERS (theEvent);
5251     }
5252   XSETINT (emacs_event->x, lrint (p.x));
5253   XSETINT (emacs_event->y, lrint (p.y));
5254   EV_TRAILER (theEvent);
5258 - (void)rightMouseDown: (NSEvent *)theEvent
5260   NSTRACE (rightMouseDown);
5261   [self mouseDown: theEvent];
5265 - (void)otherMouseDown: (NSEvent *)theEvent
5267   NSTRACE (otherMouseDown);
5268   [self mouseDown: theEvent];
5272 - (void)mouseUp: (NSEvent *)theEvent
5274   NSTRACE (mouseUp);
5275   [self mouseDown: theEvent];
5279 - (void)rightMouseUp: (NSEvent *)theEvent
5281   NSTRACE (rightMouseUp);
5282   [self mouseDown: theEvent];
5286 - (void)otherMouseUp: (NSEvent *)theEvent
5288   NSTRACE (otherMouseUp);
5289   [self mouseDown: theEvent];
5293 - (void) scrollWheel: (NSEvent *)theEvent
5295   NSTRACE (scrollWheel);
5296   [self mouseDown: theEvent];
5300 /* Tell emacs the mouse has moved. */
5301 - (void)mouseMoved: (NSEvent *)e
5303   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5304   Lisp_Object frame;
5306 //  NSTRACE (mouseMoved);
5308   last_mouse_movement_time = EV_TIMESTAMP (e);
5309   last_mouse_motion_position
5310     = [self convertPoint: [e locationInWindow] fromView: nil];
5312   /* update any mouse face */
5313   if (hlinfo->mouse_face_hidden)
5314     {
5315       hlinfo->mouse_face_hidden = 0;
5316       clear_mouse_face (hlinfo);
5317     }
5319   /* tooltip handling */
5320   previous_help_echo_string = help_echo_string;
5321   help_echo_string = Qnil;
5323   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
5324                             last_mouse_motion_position.y))
5325     help_echo_string = previous_help_echo_string;
5327   XSETFRAME (frame, emacsframe);
5328   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5329     {
5330       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5331          (note_mouse_highlight), which is called through the
5332          note_mouse_movement () call above */
5333       gen_help_event (help_echo_string, frame, help_echo_window,
5334                       help_echo_object, help_echo_pos);
5335     }
5336   else
5337     {
5338       help_echo_string = Qnil;
5339       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5340     }
5342   if (emacsframe->mouse_moved && send_appdefined)
5343     ns_send_appdefined (-1);
5347 - (void)mouseDragged: (NSEvent *)e
5349   NSTRACE (mouseDragged);
5350   [self mouseMoved: e];
5354 - (void)rightMouseDragged: (NSEvent *)e
5356   NSTRACE (rightMouseDragged);
5357   [self mouseMoved: e];
5361 - (void)otherMouseDragged: (NSEvent *)e
5363   NSTRACE (otherMouseDragged);
5364   [self mouseMoved: e];
5368 - (BOOL)windowShouldClose: (id)sender
5370   NSEvent *e =[[self window] currentEvent];
5372   NSTRACE (windowShouldClose);
5373   windowClosing = YES;
5374   if (!emacs_event)
5375     return NO;
5376   emacs_event->kind = DELETE_WINDOW_EVENT;
5377   emacs_event->modifiers = 0;
5378   emacs_event->code = 0;
5379   EV_TRAILER (e);
5380   /* Don't close this window, let this be done from lisp code.  */
5381   return NO;
5384 - (void) updateFrameSize: (BOOL) delay;
5386   NSWindow *window = [self window];
5387   NSRect wr = [window frame];
5388 #ifdef NS_IMPL_GNUSTEP
5389   int extra = 3;
5390 #else
5391   int extra = 0;
5392 #endif
5394   int oldc = cols, oldr = rows;
5395   int oldw = FRAME_PIXEL_WIDTH (emacsframe),
5396     oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5397   int neww, newh;
5399   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, wr.size.width + extra);
5401   if (cols < MINWIDTH)
5402     cols = MINWIDTH;
5404   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES
5405     (emacsframe, wr.size.height
5406      - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + extra
5407      - FRAME_TOOLBAR_HEIGHT (emacsframe));
5409   if (rows < MINHEIGHT)
5410     rows = MINHEIGHT;
5412   neww = (int)wr.size.width - emacsframe->border_width;
5413   newh = ((int)wr.size.height
5414           - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5415           - FRAME_TOOLBAR_HEIGHT (emacsframe));
5417   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5418     {
5419       NSView *view = FRAME_NS_VIEW (emacsframe);
5420       FRAME_PIXEL_WIDTH (emacsframe) = neww;
5421       FRAME_PIXEL_HEIGHT (emacsframe) = newh;
5422       change_frame_size (emacsframe, rows, cols, 0, delay, 0);
5423       SET_FRAME_GARBAGED (emacsframe);
5424       cancel_mouse_face (emacsframe);
5425       [view setFrame: NSMakeRect (0, 0, neww, newh)];
5426       [self windowDidMove:nil];   // Update top/left.
5427     }
5430 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5431 /* normalize frame to gridded text size */
5433   NSTRACE (windowWillResize);
5434 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5436   if (fs_state == FULLSCREEN_MAXIMIZED
5437       && (maximized_width != (int)frameSize.width
5438           || maximized_height != (int)frameSize.height))
5439     [self setFSValue: FULLSCREEN_NONE];
5440   else if (fs_state == FULLSCREEN_WIDTH
5441            && maximized_width != (int)frameSize.width)
5442     [self setFSValue: FULLSCREEN_NONE];
5443   else if (fs_state == FULLSCREEN_HEIGHT
5444            && maximized_height != (int)frameSize.height)
5445     [self setFSValue: FULLSCREEN_NONE];
5446   if (fs_state == FULLSCREEN_NONE)
5447     maximized_width = maximized_height = -1;
5449   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5450 #ifdef NS_IMPL_GNUSTEP
5451                                         frameSize.width + 3);
5452 #else
5453                                         frameSize.width);
5454 #endif
5455   if (cols < MINWIDTH)
5456     cols = MINWIDTH;
5458   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, frameSize.height
5459 #ifdef NS_IMPL_GNUSTEP
5460       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + 3
5461         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5462 #else
5463       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5464         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5465 #endif
5466   if (rows < MINHEIGHT)
5467     rows = MINHEIGHT;
5468 #ifdef NS_IMPL_COCOA
5469   {
5470     /* this sets window title to have size in it; the wm does this under GS */
5471     NSRect r = [[self window] frame];
5472     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5473       {
5474         if (old_title != 0)
5475           {
5476             xfree (old_title);
5477             old_title = 0;
5478           }
5479       }
5480     else
5481       {
5482         char *size_title;
5483         NSWindow *window = [self window];
5484         if (old_title == 0)
5485           {
5486             const char *t = [[[self window] title] UTF8String];
5487             char *pos = strstr (t, "  â€”  ");
5488             if (pos)
5489               *pos = '\0';
5490             old_title = xstrdup (t);
5491           }
5492         size_title = xmalloc (strlen (old_title) + 40);
5493         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5494         [window setTitle: [NSString stringWithUTF8String: size_title]];
5495         [window display];
5496         xfree (size_title);
5497       }
5498   }
5499 #endif /* NS_IMPL_COCOA */
5500 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5502   return frameSize;
5506 - (void)windowDidResize: (NSNotification *)notification
5508 #ifdef NS_IMPL_GNUSTEP
5509   NSWindow *theWindow = [notification object];
5511    /* in GNUstep, at least currently, it's possible to get a didResize
5512       without getting a willResize.. therefore we need to act as if we got
5513       the willResize now */
5514   NSSize sz = [theWindow frame].size;
5515   sz = [self windowWillResize: theWindow toSize: sz];
5516 #endif /* NS_IMPL_GNUSTEP */
5518   NSTRACE (windowDidResize);
5519 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5521 #ifdef NS_IMPL_COCOA
5522   if (old_title != 0)
5523     {
5524       xfree (old_title);
5525       old_title = 0;
5526     }
5527 #endif /* NS_IMPL_COCOA */
5529   /* Avoid loop under GNUstep due to call at beginning of this function.
5530      (x_set_window_size causes a resize which causes
5531      a "windowDidResize" which calls x_set_window_size).  */
5532 #ifndef NS_IMPL_GNUSTEP
5533   if (cols > 0 && rows > 0)
5534     {
5535       if (ns_in_resize)
5536         x_set_window_size (emacsframe, 0, cols, rows);
5537       else
5538         {
5539           [self updateFrameSize: YES];
5540         }
5541     }
5542 #endif
5544   ns_send_appdefined (-1);
5548 - (void)windowDidBecomeKey: (NSNotification *)notification
5549 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5551   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5552   struct frame *old_focus = dpyinfo->x_focus_frame;
5554   NSTRACE (windowDidBecomeKey);
5556   if (emacsframe != old_focus)
5557     dpyinfo->x_focus_frame = emacsframe;
5559   ns_frame_rehighlight (emacsframe);
5561   if (emacs_event)
5562     {
5563       emacs_event->kind = FOCUS_IN_EVENT;
5564       EV_TRAILER ((id)nil);
5565     }
5569 - (void)windowDidResignKey: (NSNotification *)notification
5570 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5572   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5573   NSTRACE (windowDidResignKey);
5575   if (dpyinfo->x_focus_frame == emacsframe)
5576     dpyinfo->x_focus_frame = 0;
5578   ns_frame_rehighlight (emacsframe);
5580   /* FIXME: for some reason needed on second and subsequent clicks away
5581             from sole-frame Emacs to get hollow box to show */
5582   if (!windowClosing && [[self window] isVisible] == YES)
5583     {
5584       x_update_cursor (emacsframe, 1);
5585       x_set_frame_alpha (emacsframe);
5586     }
5588   if (emacs_event)
5589     {
5590       [self deleteWorkingText];
5591       emacs_event->kind = FOCUS_IN_EVENT;
5592       EV_TRAILER ((id)nil);
5593     }
5597 - (void)windowWillMiniaturize: sender
5599   NSTRACE (windowWillMiniaturize);
5603 - (BOOL)isFlipped
5605   return YES;
5609 - (BOOL)isOpaque
5611   return NO;
5615 - initFrameFromEmacs: (struct frame *)f
5617   NSRect r, wr;
5618   Lisp_Object tem;
5619   NSWindow *win;
5620   NSButton *toggleButton;
5621   NSSize sz;
5622   NSColor *col;
5623   NSString *name;
5625   NSTRACE (initFrameFromEmacs);
5627   windowClosing = NO;
5628   processingCompose = NO;
5629   scrollbarsNeedingUpdate = 0;
5630   fs_state = FULLSCREEN_NONE;
5631   fs_before_fs = next_maximized = -1;
5632   maximized_width = maximized_height = -1;
5633   nonfs_window = nil;
5635 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5637   ns_userRect = NSMakeRect (0, 0, 0, 0);
5638   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5639                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5640   [self initWithFrame: r];
5641   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5643   FRAME_NS_VIEW (f) = self;
5644   emacsframe = f;
5645   old_title = 0;
5647   win = [[EmacsWindow alloc]
5648             initWithContentRect: r
5649                       styleMask: (NSResizableWindowMask |
5650 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5651                                   NSTitledWindowMask |
5652 #endif
5653                                   NSMiniaturizableWindowMask |
5654                                   NSClosableWindowMask)
5655                         backing: NSBackingStoreBuffered
5656                           defer: YES];
5658 #ifdef NEW_STYLE_FS
5659     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
5660 #endif
5662   wr = [win frame];
5663   bwidth = f->border_width = wr.size.width - r.size.width;
5664   tbar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5666   [win setAcceptsMouseMovedEvents: YES];
5667   [win setDelegate: self];
5668   [win useOptimizedDrawing: YES];
5670   sz.width = FRAME_COLUMN_WIDTH (f);
5671   sz.height = FRAME_LINE_HEIGHT (f);
5672   [win setResizeIncrements: sz];
5674   [[win contentView] addSubview: self];
5676   if (ns_drag_types)
5677     [self registerForDraggedTypes: ns_drag_types];
5679   tem = f->name;
5680   name = [NSString stringWithUTF8String:
5681                    NILP (tem) ? "Emacs" : SSDATA (tem)];
5682   [win setTitle: name];
5684   /* toolbar support */
5685   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5686                          [NSString stringWithFormat: @"Emacs Frame %d",
5687                                    ns_window_num]];
5688   [win setToolbar: toolbar];
5689   [toolbar setVisible: NO];
5690 #ifdef NS_IMPL_COCOA
5691   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5692   [toggleButton setTarget: self];
5693   [toggleButton setAction: @selector (toggleToolbar: )];
5694 #endif
5695   FRAME_TOOLBAR_HEIGHT (f) = 0;
5697   tem = f->icon_name;
5698   if (!NILP (tem))
5699     [win setMiniwindowTitle:
5700            [NSString stringWithUTF8String: SSDATA (tem)]];
5702   {
5703     NSScreen *screen = [win screen];
5705     if (screen != 0)
5706       [win setFrameTopLeftPoint: NSMakePoint
5707            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5708             IN_BOUND (-SCREENMAX,
5709                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5710   }
5712   [win makeFirstResponder: self];
5714   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5715                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5716   [win setBackgroundColor: col];
5717   if ([col alphaComponent] != 1.0)
5718     [win setOpaque: NO];
5720   [self allocateGState];
5722   [NSApp registerServicesMenuSendTypes: ns_send_types
5723                            returnTypes: nil];
5725   ns_window_num++;
5726   return self;
5730 - (void)windowDidMove: sender
5732   NSWindow *win = [self window];
5733   NSRect r = [win frame];
5734   NSArray *screens = [NSScreen screens];
5735   NSScreen *screen = [screens objectAtIndex: 0];
5737   NSTRACE (windowDidMove);
5739   if (!emacsframe->output_data.ns)
5740     return;
5741   if (screen != nil)
5742     {
5743       emacsframe->left_pos = r.origin.x;
5744       emacsframe->top_pos =
5745         [screen frame].size.height - (r.origin.y + r.size.height);
5746     }
5750 /* Called AFTER method below, but before our windowWillResize call there leads
5751    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5752    location so set_window_size moves the frame. */
5753 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5755   emacsframe->output_data.ns->zooming = 1;
5756   return YES;
5760 /* Override to do something slightly nonstandard, but nice.  First click on
5761    zoom button will zoom vertically.  Second will zoom completely.  Third
5762    returns to original. */
5763 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5764                         defaultFrame:(NSRect)defaultFrame
5766   NSRect result = [sender frame];
5768   NSTRACE (windowWillUseStandardFrame);
5770   if (fs_before_fs != -1) /* Entering fullscreen */
5771       {
5772         result = defaultFrame;
5773       }
5774   else if (next_maximized == FULLSCREEN_HEIGHT
5775       || (next_maximized == -1
5776           && abs (defaultFrame.size.height - result.size.height)
5777           > FRAME_LINE_HEIGHT (emacsframe)))
5778     {
5779       /* first click */
5780       ns_userRect = result;
5781       maximized_height = result.size.height = defaultFrame.size.height;
5782       maximized_width = -1;
5783       result.origin.y = defaultFrame.origin.y;
5784       [self setFSValue: FULLSCREEN_HEIGHT];
5785     }
5786   else if (next_maximized == FULLSCREEN_WIDTH)
5787     {
5788       ns_userRect = result;
5789       maximized_width = result.size.width = defaultFrame.size.width;
5790       maximized_height = -1;
5791       result.origin.x = defaultFrame.origin.x;
5792       [self setFSValue: FULLSCREEN_WIDTH];
5793     }
5794   else if (next_maximized == FULLSCREEN_MAXIMIZED
5795            || (next_maximized == -1
5796                && abs (defaultFrame.size.width - result.size.width)
5797                > FRAME_COLUMN_WIDTH (emacsframe)))
5798     {
5799       result = defaultFrame;  /* second click */
5800       maximized_width = result.size.width;
5801       maximized_height = result.size.height;
5802       [self setFSValue: FULLSCREEN_MAXIMIZED];
5803     }
5804   else
5805     {
5806       /* restore */
5807       result = ns_userRect.size.height ? ns_userRect : result;
5808       ns_userRect = NSMakeRect (0, 0, 0, 0);
5809       [self setFSValue: FULLSCREEN_NONE];
5810       maximized_width = maximized_width = -1;
5811     }
5813   if (fs_before_fs == -1) next_maximized = -1;
5814   [self windowWillResize: sender toSize: result.size];
5815   return result;
5819 - (void)windowDidDeminiaturize: sender
5821   NSTRACE (windowDidDeminiaturize);
5822   if (!emacsframe->output_data.ns)
5823     return;
5824   emacsframe->async_iconified = 0;
5825   emacsframe->async_visible   = 1;
5826   windows_or_buffers_changed++;
5828   if (emacs_event)
5829     {
5830       emacs_event->kind = ICONIFY_EVENT;
5831       EV_TRAILER ((id)nil);
5832     }
5836 - (void)windowDidExpose: sender
5838   NSTRACE (windowDidExpose);
5839   if (!emacsframe->output_data.ns)
5840     return;
5841   emacsframe->async_visible = 1;
5842   SET_FRAME_GARBAGED (emacsframe);
5844   if (send_appdefined)
5845     ns_send_appdefined (-1);
5849 - (void)windowDidMiniaturize: sender
5851   NSTRACE (windowDidMiniaturize);
5852   if (!emacsframe->output_data.ns)
5853     return;
5855   emacsframe->async_iconified = 1;
5856   emacsframe->async_visible = 0;
5858   if (emacs_event)
5859     {
5860       emacs_event->kind = ICONIFY_EVENT;
5861       EV_TRAILER ((id)nil);
5862     }
5865 - (void)windowWillEnterFullScreen:(NSNotification *)notification
5867   fs_before_fs = fs_state;
5870 - (void)windowDidEnterFullScreen:(NSNotification *)notification
5872   [self setFSValue: FULLSCREEN_BOTH];
5873 #ifndef NEW_STYLE_FS
5874   [self windowDidBecomeKey:notification];
5875 #endif
5878 - (void)windowWillExitFullScreen:(NSNotification *)notification
5880   if (next_maximized != -1)
5881     fs_before_fs = next_maximized;
5884 - (void)windowDidExitFullScreen:(NSNotification *)notification
5886   [self setFSValue: fs_before_fs];
5887   fs_before_fs = -1;
5888   if (next_maximized != -1)
5889     [[self window] performZoom:self];
5892 - (void)toggleFullScreen: (id)sender
5894   /* Bugs remain:
5895      1) Having fullscreen in initial/default frame alist.
5896      2) Fullscreen in default frame alist only applied to first frame.
5897   */
5899 #ifdef NEW_STYLE_FS
5900   [[self window] toggleFullScreen:sender];
5901 #else
5902   NSWindow *w = [self window], *fw;
5903   BOOL onFirstScreen = [[w screen]
5904                          isEqual:[[NSScreen screens] objectAtIndex:0]];
5905   struct frame *f = emacsframe;
5906   NSSize sz;
5907   NSRect r;
5908   NSColor *col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5909                                           (FRAME_DEFAULT_FACE (f)),
5910                                           f);
5912   sz.width = FRAME_COLUMN_WIDTH (f);
5913   sz.height = FRAME_LINE_HEIGHT (f);
5915   if (fs_state != FULLSCREEN_BOTH)
5916     {
5917       /* Hide dock and menubar if we are on the primary screen.  */
5918       if (onFirstScreen)
5919         {
5920 #if defined (NS_IMPL_COCOA) && \
5921   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
5922           NSApplicationPresentationOptions options
5923             = NSApplicationPresentationAutoHideDock
5924             | NSApplicationPresentationAutoHideMenuBar;
5926           [NSApp setPresentationOptions: options];
5927 #else
5928           [NSMenu setMenuBarVisible:NO];
5929 #endif
5930         }
5932       fw = [[EmacsFSWindow alloc]
5933                        initWithContentRect:[w contentRectForFrameRect:[w frame]]
5934                                  styleMask:NSBorderlessWindowMask
5935                                    backing:NSBackingStoreBuffered
5936                                      defer:YES
5937                                     screen:[w screen]];
5939       [fw setContentView:[w contentView]];
5940       [fw setTitle:[w title]];
5941       [fw makeKeyAndOrderFront:NSApp];
5942       [fw setDelegate:self];
5943       [fw makeFirstResponder:self];
5944       [fw setAcceptsMouseMovedEvents: YES];
5945       [fw useOptimizedDrawing: YES];
5946       [fw setResizeIncrements: sz];
5947       [fw setBackgroundColor: col];
5948       if ([col alphaComponent] != 1.0)
5949         [fw setOpaque: NO];
5951       f->border_width = 0;
5952       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
5954       nonfs_window = w;
5955       [self windowWillEnterFullScreen:nil];
5956       [w orderOut:self];
5957       r = [fw frameRectForContentRect:[[fw screen] frame]];
5958       [fw setFrame: r display:YES animate:YES];
5959       [self windowDidEnterFullScreen:nil];
5960     }
5961   else
5962     {
5963       fw = w;
5964       w = nonfs_window;
5966       if (onFirstScreen)
5967         {
5968 #if defined (NS_IMPL_COCOA) && \
5969   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
5970           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
5971 #else
5972           [NSMenu setMenuBarVisible:YES];
5973 #endif
5974         }
5976       [w setContentView:[fw contentView]];
5977       [w setResizeIncrements: sz];
5978       [w setBackgroundColor: col];
5979       if ([col alphaComponent] != 1.0)
5980         [w setOpaque: NO];
5981       
5982       f->border_width = bwidth;
5983       FRAME_NS_TITLEBAR_HEIGHT (f) = tbar_height;
5985       [self windowWillExitFullScreen:nil];
5986       [fw setFrame: [w frame] display:YES animate:YES];
5987       [fw close];
5988       [w makeKeyAndOrderFront:NSApp];
5989       [self windowDidExitFullScreen:nil];
5990     }
5991 #endif
5994 - (void)handleFS
5996   if (fs_state != emacsframe->want_fullscreen)
5997     {
5998       if (fs_state == FULLSCREEN_BOTH)
5999         {
6000           [self toggleFullScreen:self];
6001         }
6003       switch (emacsframe->want_fullscreen)
6004         {
6005         case FULLSCREEN_BOTH:
6006           [self toggleFullScreen:self];
6007           break;
6008         case FULLSCREEN_WIDTH:
6009           next_maximized = FULLSCREEN_WIDTH;
6010           if (fs_state != FULLSCREEN_BOTH)
6011             [[self window] performZoom:self];
6012           break;
6013         case FULLSCREEN_HEIGHT:
6014           next_maximized = FULLSCREEN_HEIGHT;
6015           if (fs_state != FULLSCREEN_BOTH)
6016             [[self window] performZoom:self];
6017           break;
6018         case FULLSCREEN_MAXIMIZED:
6019           next_maximized = FULLSCREEN_MAXIMIZED;
6020           if (fs_state != FULLSCREEN_BOTH)
6021             [[self window] performZoom:self];
6022           break;
6023         case FULLSCREEN_NONE:
6024           if (fs_state != FULLSCREEN_BOTH)
6025             {
6026               next_maximized = FULLSCREEN_NONE;
6027               [[self window] performZoom:self];
6028             }
6029           break;
6030         }
6031   
6032       emacsframe->want_fullscreen = FULLSCREEN_NONE;
6033     }
6037 - (void) setFSValue: (int)value
6039   Lisp_Object lval = Qnil;
6040   switch (value)
6041     {
6042     case FULLSCREEN_BOTH:
6043       lval = Qfullboth;
6044       break;
6045     case FULLSCREEN_WIDTH:
6046       lval = Qfullwidth;
6047       break;
6048     case FULLSCREEN_HEIGHT:
6049       lval = Qfullheight;
6050       break;
6051     case FULLSCREEN_MAXIMIZED:
6052       lval = Qmaximized;
6053       break;
6054     }
6055   store_frame_param (emacsframe, Qfullscreen, lval);
6056   fs_state = value;
6059 - (void)mouseEntered: (NSEvent *)theEvent
6061   NSTRACE (mouseEntered);
6062   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
6066 - (void)mouseExited: (NSEvent *)theEvent
6068   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6070   NSTRACE (mouseExited);
6072   if (!hlinfo)
6073     return;
6075   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
6077   if (emacsframe == hlinfo->mouse_face_mouse_frame)
6078     {
6079       clear_mouse_face (hlinfo);
6080       hlinfo->mouse_face_mouse_frame = 0;
6081     }
6085 - menuDown: sender
6087   NSTRACE (menuDown);
6088   if (context_menu_value == -1)
6089     context_menu_value = [sender tag];
6090   else
6091     {
6092       NSInteger tag = [sender tag];
6093       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6094                                     emacsframe->menu_bar_vector,
6095                                     (void *)tag);
6096     }
6098   ns_send_appdefined (-1);
6099   return self;
6103 - (EmacsToolbar *)toolbar
6105   return toolbar;
6109 /* this gets called on toolbar button click */
6110 - toolbarClicked: (id)item
6112   NSEvent *theEvent;
6113   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6115   NSTRACE (toolbarClicked);
6117   if (!emacs_event)
6118     return self;
6120   /* send first event (for some reason two needed) */
6121   theEvent = [[self window] currentEvent];
6122   emacs_event->kind = TOOL_BAR_EVENT;
6123   XSETFRAME (emacs_event->arg, emacsframe);
6124   EV_TRAILER (theEvent);
6126   emacs_event->kind = TOOL_BAR_EVENT;
6127 /*   XSETINT (emacs_event->code, 0); */
6128   emacs_event->arg = AREF (emacsframe->tool_bar_items,
6129                            idx + TOOL_BAR_ITEM_KEY);
6130   emacs_event->modifiers = EV_MODIFIERS (theEvent);
6131   EV_TRAILER (theEvent);
6132   return self;
6136 - toggleToolbar: (id)sender
6138   if (!emacs_event)
6139     return self;
6141   emacs_event->kind = NS_NONKEY_EVENT;
6142   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6143   EV_TRAILER ((id)nil);
6144   return self;
6148 - (void)drawRect: (NSRect)rect
6150   int x = NSMinX (rect), y = NSMinY (rect);
6151   int width = NSWidth (rect), height = NSHeight (rect);
6153   NSTRACE (drawRect);
6155   if (!emacsframe || !emacsframe->output_data.ns || ns_in_resize)
6156     return;
6158   ns_clear_frame_area (emacsframe, x, y, width, height);
6159   expose_frame (emacsframe, x, y, width, height);
6161   /*
6162     drawRect: may be called (at least in OS X 10.5) for invisible
6163     views as well for some reason.  Thus, do not infer visibility
6164     here.
6166     emacsframe->async_visible = 1;
6167     emacsframe->async_iconified = 0;
6168   */
6172 /* NSDraggingDestination protocol methods.  Actually this is not really a
6173    protocol, but a category of Object.  O well...  */
6175 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
6177   NSTRACE (draggingEntered);
6178   return NSDragOperationGeneric;
6182 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6184   return YES;
6188 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6190   id pb;
6191   int x, y;
6192   NSString *type;
6193   NSEvent *theEvent = [[self window] currentEvent];
6194   NSPoint position;
6196   NSTRACE (performDragOperation);
6198   if (!emacs_event)
6199     return NO;
6201   position = [self convertPoint: [sender draggingLocation] fromView: nil];
6202   x = lrint (position.x);  y = lrint (position.y);
6204   pb = [sender draggingPasteboard];
6205   type = [pb availableTypeFromArray: ns_drag_types];
6206   if (type == 0)
6207     {
6208       return NO;
6209     }
6210   else if ([type isEqualToString: NSFilenamesPboardType])
6211     {
6212       NSArray *files;
6213       NSEnumerator *fenum;
6214       NSString *file;
6216       if (!(files = [pb propertyListForType: type]))
6217         return NO;
6219       fenum = [files objectEnumerator];
6220       while ( (file = [fenum nextObject]) )
6221         {
6222           emacs_event->kind = NS_NONKEY_EVENT;
6223           emacs_event->code = KEY_NS_DRAG_FILE;
6224           XSETINT (emacs_event->x, x);
6225           XSETINT (emacs_event->y, y);
6226           ns_input_file = append2 (ns_input_file,
6227                                    build_string ([file UTF8String]));
6228           emacs_event->modifiers = EV_MODIFIERS (theEvent);
6229           EV_TRAILER (theEvent);
6230         }
6231       return YES;
6232     }
6233   else if ([type isEqualToString: NSURLPboardType])
6234     {
6235       NSString *file;
6236       NSURL *fileURL;
6238       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
6239           [fileURL isFileURL] == NO)
6240         return NO;
6242       file = [fileURL path];
6243       emacs_event->kind = NS_NONKEY_EVENT;
6244       emacs_event->code = KEY_NS_DRAG_FILE;
6245       XSETINT (emacs_event->x, x);
6246       XSETINT (emacs_event->y, y);
6247       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
6248       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6249       EV_TRAILER (theEvent);
6250       return YES;
6251     }
6252   else if ([type isEqualToString: NSStringPboardType]
6253            || [type isEqualToString: NSTabularTextPboardType])
6254     {
6255       NSString *data;
6257       if (! (data = [pb stringForType: type]))
6258         return NO;
6260       emacs_event->kind = NS_NONKEY_EVENT;
6261       emacs_event->code = KEY_NS_DRAG_TEXT;
6262       XSETINT (emacs_event->x, x);
6263       XSETINT (emacs_event->y, y);
6264       ns_input_text = build_string ([data UTF8String]);
6265       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6266       EV_TRAILER (theEvent);
6267       return YES;
6268     }
6269   else if ([type isEqualToString: NSColorPboardType])
6270     {
6271       NSColor *c = [NSColor colorFromPasteboard: pb];
6272       emacs_event->kind = NS_NONKEY_EVENT;
6273       emacs_event->code = KEY_NS_DRAG_COLOR;
6274       XSETINT (emacs_event->x, x);
6275       XSETINT (emacs_event->y, y);
6276       ns_input_color = ns_color_to_lisp (c);
6277       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6278       EV_TRAILER (theEvent);
6279       return YES;
6280     }
6281   else if ([type isEqualToString: NSFontPboardType])
6282     {
6283       /* impl based on GNUstep NSTextView.m */
6284       NSData *data = [pb dataForType: NSFontPboardType];
6285       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
6286       NSFont *font = [dict objectForKey: NSFontAttributeName];
6287       char fontSize[10];
6289       if (font == nil)
6290         return NO;
6292       emacs_event->kind = NS_NONKEY_EVENT;
6293       emacs_event->code = KEY_NS_CHANGE_FONT;
6294       XSETINT (emacs_event->x, x);
6295       XSETINT (emacs_event->y, y);
6296       ns_input_font = build_string ([[font fontName] UTF8String]);
6297       snprintf (fontSize, 10, "%f", [font pointSize]);
6298       ns_input_fontsize = build_string (fontSize);
6299       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6300       EV_TRAILER (theEvent);
6301       return YES;
6302     }
6303   else
6304     {
6305       error ("Invalid data type in dragging pasteboard.");
6306       return NO;
6307     }
6311 - (id) validRequestorForSendType: (NSString *)typeSent
6312                       returnType: (NSString *)typeReturned
6314   NSTRACE (validRequestorForSendType);
6315   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6316       && typeReturned == nil)
6317     {
6318       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6319         return self;
6320     }
6322   return [super validRequestorForSendType: typeSent
6323                                returnType: typeReturned];
6327 /* The next two methods are part of NSServicesRequests informal protocol,
6328    supposedly called when a services menu item is chosen from this app.
6329    But this should not happen because we override the services menu with our
6330    own entries which call ns-perform-service.
6331    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6332    So let's at least stub them out until further investigation can be done. */
6334 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6336   /* we could call ns_string_from_pasteboard(pboard) here but then it should
6337      be written into the buffer in place of the existing selection..
6338      ordinary service calls go through functions defined in ns-win.el */
6339   return NO;
6342 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6344   NSArray *typesDeclared;
6345   Lisp_Object val;
6347   /* We only support NSStringPboardType */
6348   if ([types containsObject:NSStringPboardType] == NO) {
6349     return NO;
6350   }
6352   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6353   if (CONSP (val) && SYMBOLP (XCAR (val)))
6354     {
6355       val = XCDR (val);
6356       if (CONSP (val) && NILP (XCDR (val)))
6357         val = XCAR (val);
6358     }
6359   if (! STRINGP (val))
6360     return NO;
6362   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6363   [pb declareTypes:typesDeclared owner:nil];
6364   ns_string_to_pasteboard (pb, val);
6365   return YES;
6369 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6370    (gives a miniaturized version of the window); currently we use the latter for
6371    frames whose active buffer doesn't correspond to any file
6372    (e.g., '*scratch*') */
6373 - setMiniwindowImage: (BOOL) setMini
6375   id image = [[self window] miniwindowImage];
6376   NSTRACE (setMiniwindowImage);
6378   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6379      about "AppleDockIconEnabled" notwithstanding, however the set message
6380      below has its effect nonetheless. */
6381   if (image != emacsframe->output_data.ns->miniimage)
6382     {
6383       if (image && [image isKindOfClass: [EmacsImage class]])
6384         [image release];
6385       [[self window] setMiniwindowImage:
6386                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6387     }
6389   return self;
6393 - (void) setRows: (int) r andColumns: (int) c
6395   rows = r;
6396   cols = c;
6399 @end  /* EmacsView */
6403 /* ==========================================================================
6405     EmacsWindow implementation
6407    ========================================================================== */
6409 @implementation EmacsWindow
6411 #ifdef NS_IMPL_COCOA
6412 - (id)accessibilityAttributeValue:(NSString *)attribute
6414   Lisp_Object str = Qnil;
6415   struct frame *f = SELECTED_FRAME ();
6416   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->buffer);
6418   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6419     return NSAccessibilityTextFieldRole;
6421   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6422       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6423     {
6424       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6425     }
6426   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
6427     {
6428       if (! NILP (BVAR (curbuf, mark_active)))
6429           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6431       if (NILP (str))
6432         {
6433           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
6434           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
6435           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
6437           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
6438             str = make_uninit_multibyte_string (range, byte_range);
6439           else
6440             str = make_uninit_string (range);
6441           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
6442              Is this a problem?  */
6443           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
6444         }
6445     }
6448   if (! NILP (str))
6449     {
6450       if (CONSP (str) && SYMBOLP (XCAR (str)))
6451         {
6452           str = XCDR (str);
6453           if (CONSP (str) && NILP (XCDR (str)))
6454             str = XCAR (str);
6455         }
6456       if (STRINGP (str))
6457         {
6458           const char *utfStr = SSDATA (str);
6459           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
6460           return nsStr;
6461         }
6462     }
6464   return [super accessibilityAttributeValue:attribute];
6466 #endif /* NS_IMPL_COCOA */
6468 /* If we have multiple monitors, one above the other, we don't want to
6469    restrict the height to just one monitor.  So we override this.  */
6470 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6472   /* When making the frame visible for the first time or if there is just
6473      one screen, we want to constrain.  Other times not.  */
6474   NSUInteger nr_screens = [[NSScreen screens] count];
6475   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6476   NSTRACE (constrainFrameRect);
6478   if (nr_screens == 1)
6479     {
6480       NSRect r = [super constrainFrameRect:frameRect toScreen:screen];
6481       return r;
6482     }
6484   if (f->output_data.ns->dont_constrain
6485       || ns_menu_bar_should_be_hidden ())
6486     return frameRect;
6488   f->output_data.ns->dont_constrain = 1;
6489   return [super constrainFrameRect:frameRect toScreen:screen];
6493 /* called only on resize clicks by special case in EmacsApp-sendEvent */
6494 - (void)mouseDown: (NSEvent *)theEvent
6496   if (ns_in_resize)
6497     {
6498       NSSize size = [[theEvent window] frame].size;
6499       grabOffset = [theEvent locationInWindow];
6500       grabOffset.x = size.width - grabOffset.x;
6501     }
6502   else
6503     [super mouseDown: theEvent];
6507 /* stop resizing */
6508 - (void)mouseUp: (NSEvent *)theEvent
6510   if (ns_in_resize)
6511     {
6512       struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6513       ns_in_resize = NO;
6514       ns_set_name_as_filename (f);
6515       [self display];
6516       ns_send_appdefined (-1);
6517     }
6518   else
6519     [super mouseUp: theEvent];
6523 /* send resize events */
6524 - (void)mouseDragged: (NSEvent *)theEvent
6526   if (ns_in_resize)
6527     {
6528       NSPoint p = [theEvent locationInWindow];
6529       NSSize size, vettedSize, origSize = [self frame].size;
6531       size.width = p.x + grabOffset.x;
6532       size.height = origSize.height - p.y + grabOffset.y;
6534       if (size.width == origSize.width && size.height == origSize.height)
6535         return;
6537       vettedSize = [[self delegate] windowWillResize: self toSize: size];
6538       [[NSNotificationCenter defaultCenter]
6539             postNotificationName: NSWindowDidResizeNotification
6540                           object: self];
6541     }
6542   else
6543     [super mouseDragged: theEvent];
6546 @end /* EmacsWindow */
6549 @implementation EmacsFSWindow
6551 - (BOOL)canBecomeKeyWindow
6553   return YES;
6556 @end
6558 /* ==========================================================================
6560     EmacsScroller implementation
6562    ========================================================================== */
6565 @implementation EmacsScroller
6567 /* for repeat button push */
6568 #define SCROLL_BAR_FIRST_DELAY 0.5
6569 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6571 + (CGFloat) scrollerWidth
6573   /* TODO: if we want to allow variable widths, this is the place to do it,
6574            however neither GNUstep nor Cocoa support it very well */
6575   return [NSScroller scrollerWidth];
6579 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6581   NSTRACE (EmacsScroller_initFrame);
6583   r.size.width = [EmacsScroller scrollerWidth];
6584   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6585   [self setContinuous: YES];
6586   [self setEnabled: YES];
6588   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6589      locked against the top and bottom edges, and right edge on OS X, where
6590      scrollers are on right. */
6591 #ifdef NS_IMPL_GNUSTEP
6592   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6593 #else
6594   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6595 #endif
6597   win = nwin;
6598   condemned = NO;
6599   pixel_height = NSHeight (r);
6600   if (pixel_height == 0) pixel_height = 1;
6601   min_portion = 20 / pixel_height;
6603   frame = XFRAME (XWINDOW (win)->frame);
6604   if (FRAME_LIVE_P (frame))
6605     {
6606       int i;
6607       EmacsView *view = FRAME_NS_VIEW (frame);
6608       NSView *sview = [[view window] contentView];
6609       NSArray *subs = [sview subviews];
6611       /* disable optimization stopping redraw of other scrollbars */
6612       view->scrollbarsNeedingUpdate = 0;
6613       for (i =[subs count]-1; i >= 0; i--)
6614         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6615           view->scrollbarsNeedingUpdate++;
6616       [sview addSubview: self];
6617     }
6619 /*  [self setFrame: r]; */
6621   return self;
6625 - (void)setFrame: (NSRect)newRect
6627   NSTRACE (EmacsScroller_setFrame);
6628 /*  block_input (); */
6629   pixel_height = NSHeight (newRect);
6630   if (pixel_height == 0) pixel_height = 1;
6631   min_portion = 20 / pixel_height;
6632   [super setFrame: newRect];
6633   [self display];
6634 /*  unblock_input (); */
6638 - (void)dealloc
6640   NSTRACE (EmacsScroller_dealloc);
6641   if (!NILP (win))
6642     wset_vertical_scroll_bar (XWINDOW (win), Qnil);
6643   [super dealloc];
6647 - condemn
6649   NSTRACE (condemn);
6650   condemned =YES;
6651   return self;
6655 - reprieve
6657   NSTRACE (reprieve);
6658   condemned =NO;
6659   return self;
6663 - judge
6665   NSTRACE (judge);
6666   if (condemned)
6667     {
6668       EmacsView *view;
6669       block_input ();
6670       /* ensure other scrollbar updates after deletion */
6671       view = (EmacsView *)FRAME_NS_VIEW (frame);
6672       if (view != nil)
6673         view->scrollbarsNeedingUpdate++;
6674       [self removeFromSuperview];
6675       [self release];
6676       unblock_input ();
6677     }
6678   return self;
6682 - (void)resetCursorRects
6684   NSRect visible = [self visibleRect];
6685   NSTRACE (resetCursorRects);
6687   if (!NSIsEmptyRect (visible))
6688     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6689   [[NSCursor arrowCursor] setOnMouseEntered: YES];
6693 - (int) checkSamePosition: (int) position portion: (int) portion
6694                     whole: (int) whole
6696   return em_position ==position && em_portion ==portion && em_whole ==whole
6697     && portion != whole; /* needed for resize empty buf */
6701 - setPosition: (int)position portion: (int)portion whole: (int)whole
6703   NSTRACE (setPosition);
6705   em_position = position;
6706   em_portion = portion;
6707   em_whole = whole;
6709   if (portion >= whole)
6710     {
6711 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6712       [self setKnobProportion: 1.0];
6713       [self setDoubleValue: 1.0];
6714 #else
6715       [self setFloatValue: 0.0 knobProportion: 1.0];
6716 #endif
6717     }
6718   else
6719     {
6720       float pos, por;
6721       portion = max ((float)whole*min_portion/pixel_height, portion);
6722       pos = (float)position / (whole - portion);
6723       por = (float)portion/whole;
6724 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6725       [self setKnobProportion: por];
6726       [self setDoubleValue: pos];
6727 #else
6728       [self setFloatValue: pos knobProportion: por];
6729 #endif
6730     }
6731   return self;
6734 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6735      drag events will go directly to the EmacsScroller.  Leaving in for now. */
6736 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6737                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
6739   *part = last_hit_part;
6740   *window = win;
6741   XSETINT (*y, pixel_height);
6742   if ([self floatValue] > 0.999)
6743     XSETINT (*x, pixel_height);
6744   else
6745     XSETINT (*x, pixel_height * [self floatValue]);
6749 /* set up emacs_event */
6750 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6752   if (!emacs_event)
6753     return;
6755   emacs_event->part = last_hit_part;
6756   emacs_event->code = 0;
6757   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
6758   emacs_event->frame_or_window = win;
6759   emacs_event->timestamp = EV_TIMESTAMP (e);
6760   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
6761   emacs_event->arg = Qnil;
6762   XSETINT (emacs_event->x, loc * pixel_height);
6763   XSETINT (emacs_event->y, pixel_height-20);
6765   if (q_event_ptr)
6766     {
6767       n_emacs_events_pending++;
6768       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
6769     }
6770   else
6771     kbd_buffer_store_event (emacs_event);
6772   EVENT_INIT (*emacs_event);
6773   ns_send_appdefined (-1);
6777 /* called manually thru timer to implement repeated button action w/hold-down */
6778 - repeatScroll: (NSTimer *)scrollEntry
6780   NSEvent *e = [[self window] currentEvent];
6781   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
6782   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
6784   /* clear timer if need be */
6785   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
6786     {
6787         [scroll_repeat_entry invalidate];
6788         [scroll_repeat_entry release];
6789         scroll_repeat_entry = nil;
6791         if (inKnob)
6792           return self;
6794         scroll_repeat_entry
6795           = [[NSTimer scheduledTimerWithTimeInterval:
6796                         SCROLL_BAR_CONTINUOUS_DELAY
6797                                             target: self
6798                                           selector: @selector (repeatScroll:)
6799                                           userInfo: 0
6800                                            repeats: YES]
6801               retain];
6802     }
6804   [self sendScrollEventAtLoc: 0 fromEvent: e];
6805   return self;
6809 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
6810    mouseDragged events without going into a modal loop. */
6811 - (void)mouseDown: (NSEvent *)e
6813   NSRect sr, kr;
6814   /* hitPart is only updated AFTER event is passed on */
6815   NSScrollerPart part = [self testPart: [e locationInWindow]];
6816   double inc = 0.0, loc, kloc, pos;
6817   int edge = 0;
6819   NSTRACE (EmacsScroller_mouseDown);
6821   switch (part)
6822     {
6823     case NSScrollerDecrementPage:
6824         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
6825     case NSScrollerIncrementPage:
6826         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
6827     case NSScrollerDecrementLine:
6828       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
6829     case NSScrollerIncrementLine:
6830       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
6831     case NSScrollerKnob:
6832       last_hit_part = scroll_bar_handle; break;
6833     case NSScrollerKnobSlot:  /* GNUstep-only */
6834       last_hit_part = scroll_bar_move_ratio; break;
6835     default:  /* NSScrollerNoPart? */
6836       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
6837                (long) part);
6838       return;
6839     }
6841   if (inc != 0.0)
6842     {
6843       pos = 0;      /* ignored */
6845       /* set a timer to repeat, as we can't let superclass do this modally */
6846       scroll_repeat_entry
6847         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
6848                                             target: self
6849                                           selector: @selector (repeatScroll:)
6850                                           userInfo: 0
6851                                            repeats: YES]
6852             retain];
6853     }
6854   else
6855     {
6856       /* handle, or on GNUstep possibly slot */
6857       NSEvent *fake_event;
6859       /* compute float loc in slot and mouse offset on knob */
6860       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6861                       toView: nil];
6862       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6863       if (loc <= 0.0)
6864         {
6865           loc = 0.0;
6866           edge = -1;
6867         }
6868       else if (loc >= NSHeight (sr))
6869         {
6870           loc = NSHeight (sr);
6871           edge = 1;
6872         }
6874       if (edge)
6875         kloc = 0.5 * edge;
6876       else
6877         {
6878           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
6879                           toView: nil];
6880           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
6881         }
6882       last_mouse_offset = kloc;
6884       /* if knob, tell emacs a location offset by knob pos
6885          (to indicate top of handle) */
6886       if (part == NSScrollerKnob)
6887           pos = (loc - last_mouse_offset) / NSHeight (sr);
6888       else
6889         /* else this is a slot click on GNUstep: go straight there */
6890         pos = loc / NSHeight (sr);
6892       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
6893       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
6894                                       location: [e locationInWindow]
6895                                  modifierFlags: [e modifierFlags]
6896                                      timestamp: [e timestamp]
6897                                   windowNumber: [e windowNumber]
6898                                        context: [e context]
6899                                    eventNumber: [e eventNumber]
6900                                     clickCount: [e clickCount]
6901                                       pressure: [e pressure]];
6902       [super mouseUp: fake_event];
6903     }
6905   if (part != NSScrollerKnob)
6906     [self sendScrollEventAtLoc: pos fromEvent: e];
6910 /* Called as we manually track scroller drags, rather than superclass. */
6911 - (void)mouseDragged: (NSEvent *)e
6913     NSRect sr;
6914     double loc, pos;
6915     int edge = 0;
6917     NSTRACE (EmacsScroller_mouseDragged);
6919       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6920                       toView: nil];
6921       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6923       if (loc <= 0.0)
6924         {
6925           loc = 0.0;
6926           edge = -1;
6927         }
6928       else if (loc >= NSHeight (sr) + last_mouse_offset)
6929         {
6930           loc = NSHeight (sr) + last_mouse_offset;
6931           edge = 1;
6932         }
6934       pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
6935       [self sendScrollEventAtLoc: pos fromEvent: e];
6939 - (void)mouseUp: (NSEvent *)e
6941   if (scroll_repeat_entry)
6942     {
6943       [scroll_repeat_entry invalidate];
6944       [scroll_repeat_entry release];
6945       scroll_repeat_entry = nil;
6946     }
6947   last_hit_part = 0;
6951 /* treat scrollwheel events in the bar as though they were in the main window */
6952 - (void) scrollWheel: (NSEvent *)theEvent
6954   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
6955   [view mouseDown: theEvent];
6958 @end  /* EmacsScroller */
6963 /* ==========================================================================
6965    Font-related functions; these used to be in nsfaces.m
6967    ========================================================================== */
6970 Lisp_Object
6971 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
6973   struct font *font = XFONT_OBJECT (font_object);
6975   if (fontset < 0)
6976     fontset = fontset_from_font (font_object);
6977   FRAME_FONTSET (f) = fontset;
6979   if (FRAME_FONT (f) == font)
6980     /* This font is already set in frame F.  There's nothing more to
6981        do.  */
6982     return font_object;
6984   FRAME_FONT (f) = font;
6986   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
6987   FRAME_COLUMN_WIDTH (f) = font->average_width;
6988   FRAME_SPACE_WIDTH (f) = font->space_width;
6989   FRAME_LINE_HEIGHT (f) = font->height;
6991   compute_fringe_widths (f, 1);
6993   /* Compute the scroll bar width in character columns.  */
6994   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6995     {
6996       int wid = FRAME_COLUMN_WIDTH (f);
6997       FRAME_CONFIG_SCROLL_BAR_COLS (f)
6998         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
6999     }
7000   else
7001     {
7002       int wid = FRAME_COLUMN_WIDTH (f);
7003       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
7004     }
7006   /* Now make the frame display the given font.  */
7007   if (FRAME_NS_WINDOW (f) != 0)
7008         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
7010   return font_object;
7014 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
7015 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
7016          in 1.43. */
7018 const char *
7019 ns_xlfd_to_fontname (const char *xlfd)
7020 /* --------------------------------------------------------------------------
7021     Convert an X font name (XLFD) to an NS font name.
7022     Only family is used.
7023     The string returned is temporarily allocated.
7024    -------------------------------------------------------------------------- */
7026   char *name = xmalloc (180);
7027   int i, len;
7028   const char *ret;
7030   if (!strncmp (xlfd, "--", 2))
7031     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7032   else
7033     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7035   /* stopgap for malformed XLFD input */
7036   if (strlen (name) == 0)
7037     strcpy (name, "Monaco");
7039   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7040      also uppercase after '-' or ' ' */
7041   name[0] = c_toupper (name[0]);
7042   for (len =strlen (name), i =0; i<len; i++)
7043     {
7044       if (name[i] == '$')
7045         {
7046           name[i] = '-';
7047           if (i+1<len)
7048             name[i+1] = c_toupper (name[i+1]);
7049         }
7050       else if (name[i] == '_')
7051         {
7052           name[i] = ' ';
7053           if (i+1<len)
7054             name[i+1] = c_toupper (name[i+1]);
7055         }
7056     }
7057 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
7058   ret = [[NSString stringWithUTF8String: name] UTF8String];
7059   xfree (name);
7060   return ret;
7064 void
7065 syms_of_nsterm (void)
7067   NSTRACE (syms_of_nsterm);
7069   ns_antialias_threshold = 10.0;
7071   /* from 23+ we need to tell emacs what modifiers there are.. */
7072   DEFSYM (Qmodifier_value, "modifier-value");
7073   DEFSYM (Qalt, "alt");
7074   DEFSYM (Qhyper, "hyper");
7075   DEFSYM (Qmeta, "meta");
7076   DEFSYM (Qsuper, "super");
7077   DEFSYM (Qcontrol, "control");
7078   DEFSYM (QUTF8_STRING, "UTF8_STRING");
7080   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7081   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7082   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7083   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7084   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7086   DEFVAR_LISP ("ns-input-file", ns_input_file,
7087               "The file specified in the last NS event.");
7088   ns_input_file =Qnil;
7090   DEFVAR_LISP ("ns-input-text", ns_input_text,
7091               "The data received in the last NS text drag event.");
7092   ns_input_text =Qnil;
7094   DEFVAR_LISP ("ns-working-text", ns_working_text,
7095               "String for visualizing working composition sequence.");
7096   ns_working_text =Qnil;
7098   DEFVAR_LISP ("ns-input-font", ns_input_font,
7099               "The font specified in the last NS event.");
7100   ns_input_font =Qnil;
7102   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7103               "The fontsize specified in the last NS event.");
7104   ns_input_fontsize =Qnil;
7106   DEFVAR_LISP ("ns-input-line", ns_input_line,
7107                "The line specified in the last NS event.");
7108   ns_input_line =Qnil;
7110   DEFVAR_LISP ("ns-input-color", ns_input_color,
7111                "The color specified in the last NS event.");
7112   ns_input_color =Qnil;
7114   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7115                "The service name specified in the last NS event.");
7116   ns_input_spi_name =Qnil;
7118   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7119                "The service argument specified in the last NS event.");
7120   ns_input_spi_arg =Qnil;
7122   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7123                "This variable describes the behavior of the alternate or option key.\n\
7124 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7125 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7126 at all, allowing it to be used at a lower level for accented character entry.");
7127   ns_alternate_modifier = Qmeta;
7129   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7130                "This variable describes the behavior of the right alternate or option key.\n\
7131 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7132 Set to left means be the same key as `ns-alternate-modifier'.\n\
7133 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7134 at all, allowing it to be used at a lower level for accented character entry.");
7135   ns_right_alternate_modifier = Qleft;
7137   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7138                "This variable describes the behavior of the command key.\n\
7139 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7140   ns_command_modifier = Qsuper;
7142   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7143                "This variable describes the behavior of the right command key.\n\
7144 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7145 Set to left means be the same key as `ns-command-modifier'.\n\
7146 Set to none means that the command / option key is not interpreted by Emacs\n\
7147 at all, allowing it to be used at a lower level for accented character entry.");
7148   ns_right_command_modifier = Qleft;
7150   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7151                "This variable describes the behavior of the control key.\n\
7152 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7153   ns_control_modifier = Qcontrol;
7155   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7156                "This variable describes the behavior of the right control key.\n\
7157 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7158 Set to left means be the same key as `ns-control-modifier'.\n\
7159 Set to none means that the control / option key is not interpreted by Emacs\n\
7160 at all, allowing it to be used at a lower level for accented character entry.");
7161   ns_right_control_modifier = Qleft;
7163   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7164                "This variable describes the behavior of the function key (on laptops).\n\
7165 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7166 Set to none means that the function key is not interpreted by Emacs at all,\n\
7167 allowing it to be used at a lower level for accented character entry.");
7168   ns_function_modifier = Qnone;
7170   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7171                "Non-nil (the default) means to render text antialiased. Only has an effect on OS X Panther and above.");
7172   ns_antialias_text = Qt;
7174   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7175                "Whether to confirm application quit using dialog.");
7176   ns_confirm_quit = Qnil;
7178   staticpro (&ns_display_name_list);
7179   ns_display_name_list = Qnil;
7181   staticpro (&last_mouse_motion_frame);
7182   last_mouse_motion_frame = Qnil;
7184   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7185                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7186 Only works on OSX 10.6 or later.  */);
7187   ns_auto_hide_menu_bar = Qnil;
7189   /* TODO: move to common code */
7190   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7191                doc: /* Which toolkit scroll bars Emacs uses, if any.
7192 A value of nil means Emacs doesn't use toolkit scroll bars.
7193 With the X Window system, the value is a symbol describing the
7194 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
7195 With MS Windows or Nextstep, the value is t.  */);
7196   Vx_toolkit_scroll_bars = Qt;
7198   DEFVAR_BOOL ("x-use-underline-position-properties",
7199                x_use_underline_position_properties,
7200      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7201 A value of nil means ignore them.  If you encounter fonts with bogus
7202 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7203 to 4.1, set this to nil. */);
7204   x_use_underline_position_properties = 0;
7206   DEFVAR_BOOL ("x-underline-at-descent-line",
7207                x_underline_at_descent_line,
7208      doc: /* Non-nil means to draw the underline at the same place as the descent line.
7209 A value of nil means to draw the underline according to the value of the
7210 variable `x-use-underline-position-properties', which is usually at the
7211 baseline level.  The default value is nil.  */);
7212   x_underline_at_descent_line = 0;
7214   /* Tell emacs about this window system. */
7215   Fprovide (intern ("ns"), Qnil);