Merge from mainline.
[emacs.git] / src / nsterm.m
blobc7cd411c61464a72ea06ee9049ac0c6d3eddf745
1 /* NeXT/Open/GNUstep / MacOSX communication module.
2    Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2011
3      Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
21 Originally by Carl Edman
22 Updated by Christian Limpach (chris@nice.ch)
23 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
24 MacOSX/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
25 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
28 /* This should be the first include, as it may set up #defines affecting
29    interpretation of even the system includes. */
30 #include <config.h>
32 #include <math.h>
33 #include <sys/types.h>
34 #include <time.h>
35 #include <signal.h>
36 #include <unistd.h>
37 #include <setjmp.h>
39 #include "lisp.h"
40 #include "blockinput.h"
41 #include "sysselect.h"
42 #include "nsterm.h"
43 #include "systime.h"
44 #include "character.h"
45 #include "fontset.h"
46 #include "composite.h"
47 #include "ccl.h"
49 #include "termhooks.h"
50 #include "termopts.h"
51 #include "termchar.h"
53 #include "window.h"
54 #include "keyboard.h"
56 #include "font.h"
58 /* call tracing */
59 #if 0
60 int term_trace_num = 0;
61 #define NSTRACE(x)        fprintf (stderr, "%s:%d: [%d] " #x "\n",         \
62                                 __FILE__, __LINE__, ++term_trace_num)
63 #else
64 #define NSTRACE(x)
65 #endif
68 /* ==========================================================================
70     Local declarations
72    ========================================================================== */
74 /* Convert a symbol indexed with an NSxxx value to a value as defined
75    in keyboard.c (lispy_function_key). I hope this is a correct way
76    of doing things... */
77 static unsigned convert_ns_to_X_keysym[] =
79   NSHomeFunctionKey,            0x50,
80   NSLeftArrowFunctionKey,       0x51,
81   NSUpArrowFunctionKey,         0x52,
82   NSRightArrowFunctionKey,      0x53,
83   NSDownArrowFunctionKey,       0x54,
84   NSPageUpFunctionKey,          0x55,
85   NSPageDownFunctionKey,        0x56,
86   NSEndFunctionKey,             0x57,
87   NSBeginFunctionKey,           0x58,
88   NSSelectFunctionKey,          0x60,
89   NSPrintFunctionKey,           0x61,
90   NSExecuteFunctionKey,         0x62,
91   NSInsertFunctionKey,          0x63,
92   NSUndoFunctionKey,            0x65,
93   NSRedoFunctionKey,            0x66,
94   NSMenuFunctionKey,            0x67,
95   NSFindFunctionKey,            0x68,
96   NSHelpFunctionKey,            0x6A,
97   NSBreakFunctionKey,           0x6B,
99   NSF1FunctionKey,              0xBE,
100   NSF2FunctionKey,              0xBF,
101   NSF3FunctionKey,              0xC0,
102   NSF4FunctionKey,              0xC1,
103   NSF5FunctionKey,              0xC2,
104   NSF6FunctionKey,              0xC3,
105   NSF7FunctionKey,              0xC4,
106   NSF8FunctionKey,              0xC5,
107   NSF9FunctionKey,              0xC6,
108   NSF10FunctionKey,             0xC7,
109   NSF11FunctionKey,             0xC8,
110   NSF12FunctionKey,             0xC9,
111   NSF13FunctionKey,             0xCA,
112   NSF14FunctionKey,             0xCB,
113   NSF15FunctionKey,             0xCC,
114   NSF16FunctionKey,             0xCD,
115   NSF17FunctionKey,             0xCE,
116   NSF18FunctionKey,             0xCF,
117   NSF19FunctionKey,             0xD0,
118   NSF20FunctionKey,             0xD1,
119   NSF21FunctionKey,             0xD2,
120   NSF22FunctionKey,             0xD3,
121   NSF23FunctionKey,             0xD4,
122   NSF24FunctionKey,             0xD5,
124   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
125   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
126   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
128   NSTabCharacter,               0x09,
129   0x19,                         0x09,  /* left tab->regular since pass shift */
130   NSCarriageReturnCharacter,    0x0D,
131   NSNewlineCharacter,           0x0D,
132   NSEnterCharacter,             0x8D,
134   0x1B,                         0x1B   /* escape */
138 static Lisp_Object Qmodifier_value;
139 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper, Qnone;
140 extern Lisp_Object Qcursor_color, Qcursor_type, Qns, Qleft;
142 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
143    the maximum font size to NOT antialias.  On GNUstep there is currently
144    no way to control this behavior. */
145 float ns_antialias_threshold;
147 /* Used to pick up AppleHighlightColor on OS X */
148 NSString *ns_selection_color;
150 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
151 NSString *ns_app_name = @"Emacs";  /* default changed later */
153 /* Display variables */
154 struct ns_display_info *x_display_list; /* Chain of existing displays */
155 Lisp_Object ns_display_name_list;
156 long context_menu_value = 0;
158 /* display update */
159 NSPoint last_mouse_motion_position;
160 static NSRect last_mouse_glyph;
161 static unsigned long last_mouse_movement_time = 0;
162 static Lisp_Object last_mouse_motion_frame;
163 static EmacsScroller *last_mouse_scroll_bar = nil;
164 static struct frame *ns_updating_frame;
165 static NSView *focus_view = NULL;
166 static int ns_window_num =0;
167 static NSRect uRect;
168 static BOOL gsaved = NO;
169 BOOL ns_in_resize = NO;
170 static BOOL ns_fake_keydown = NO;
171 int ns_tmp_flags; /* FIXME */
172 struct nsfont_info *ns_tmp_font; /* FIXME */
173 /*static int debug_lock = 0; */
175 /* event loop */
176 static BOOL send_appdefined = YES;
177 static NSEvent *last_appdefined_event = 0;
178 static NSTimer *timed_entry = 0;
179 static NSTimer *fd_entry = nil;
180 static NSTimer *scroll_repeat_entry = nil;
181 static fd_set select_readfds, t_readfds;
182 static struct timeval select_timeout;
183 static int select_nfds;
184 static NSAutoreleasePool *outerpool;
185 static struct input_event *emacs_event = NULL;
186 static struct input_event *q_event_ptr = NULL;
187 static int n_emacs_events_pending = 0;
188 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
189   *ns_pending_service_args;
190 static BOOL inNsSelect = 0;
192 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
193 #define NS_FUNCTION_KEY_MASK 0x800000
194 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
195 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
196 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
197 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
198 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
199 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
200 #define EV_MODIFIERS(e)                               \
201     ((([e modifierFlags] & NSHelpKeyMask) ?           \
202            hyper_modifier : 0)                        \
203      | (!EQ (ns_right_alternate_modifier, Qleft) && \
204         (([e modifierFlags] & NSRightAlternateKeyMask) \
205          == NSRightAlternateKeyMask) ? \
206            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
207      | (([e modifierFlags] & NSAlternateKeyMask) ?                 \
208            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
209      | (([e modifierFlags] & NSShiftKeyMask) ?     \
210            shift_modifier : 0)                        \
211      | (!EQ (ns_right_control_modifier, Qleft) && \
212         (([e modifierFlags] & NSRightControlKeyMask) \
213          == NSRightControlKeyMask) ? \
214            parse_solitary_modifier (ns_right_control_modifier) : 0) \
215      | (([e modifierFlags] & NSControlKeyMask) ?      \
216            parse_solitary_modifier (ns_control_modifier) : 0)     \
217      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
218            parse_solitary_modifier (ns_function_modifier) : 0)    \
219      | (!EQ (ns_right_command_modifier, Qleft) && \
220         (([e modifierFlags] & NSRightCommandKeyMask) \
221          == NSRightCommandKeyMask) ? \
222            parse_solitary_modifier (ns_right_command_modifier) : 0) \
223      | (([e modifierFlags] & NSCommandKeyMask) ?      \
224            parse_solitary_modifier (ns_command_modifier):0))
226 #define EV_UDMODIFIERS(e)                                      \
227     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
228      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
229      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
230      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
231      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
232      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
233      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
234      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
235      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
237 #define EV_BUTTON(e)                                                         \
238     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
239       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
240      [e buttonNumber] - 1)
242 /* Convert the time field to a timestamp in milliseconds. */
243 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
245 /* This is a piece of code which is common to all the event handling
246    methods.  Maybe it should even be a function.  */
247 #define EV_TRAILER(e)                                         \
248   {                                                           \
249   XSETFRAME (emacs_event->frame_or_window, emacsframe);       \
250   if (e) emacs_event->timestamp = EV_TIMESTAMP (e);           \
251   n_emacs_events_pending++;                                   \
252   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);     \
253   EVENT_INIT (*emacs_event);                                  \
254   ns_send_appdefined (-1);                                    \
255   }
257 void x_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
259 /* TODO: get rid of need for these forward declarations */
260 static void ns_condemn_scroll_bars (struct frame *f);
261 static void ns_judge_scroll_bars (struct frame *f);
262 void x_set_frame_alpha (struct frame *f);
264 /* FIXME: figure out what to do with underline_minimum_offset. */
267 /* ==========================================================================
269     Utilities
271    ========================================================================== */
274 static Lisp_Object
275 append2 (Lisp_Object list, Lisp_Object item)
276 /* --------------------------------------------------------------------------
277    Utility to append to a list
278    -------------------------------------------------------------------------- */
280   Lisp_Object array[2];
281   array[0] = list;
282   array[1] = Fcons (item, Qnil);
283   return Fnconc (2, &array[0]);
287 void
288 ns_init_paths (void)
289 /* --------------------------------------------------------------------------
290    Used to allow emacs to find its resources under Emacs.app
291    Called from emacs.c at startup.
292    -------------------------------------------------------------------------- */
294   NSBundle *bundle = [NSBundle mainBundle];
295   NSString *binDir = [bundle bundlePath], *resourceDir = [bundle resourcePath];
296   NSString *resourcePath, *resourcePaths;
297   NSRange range;
298   BOOL onWindows = NO; /* how do I determine this? */
299   NSString *pathSeparator = onWindows ? @";" : @":";
300   NSFileManager *fileManager = [NSFileManager defaultManager];
301   BOOL isDir;
302 /*NSLog (@"ns_init_paths: '%@'\n%@\n", [[NSBundle mainBundle] bundlePath], [[NSBundle mainBundle] resourcePath]); */
304   /* get bindir from base */
305   range = [resourceDir rangeOfString: @"Contents"];
306   if (range.location != NSNotFound)
307     {
308       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
309 #ifdef NS_IMPL_COCOA
310       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
311 #endif
312     }
314   /* the following based on Andrew Choi's init_mac_osx_environment () */
315   if (!getenv ("EMACSLOADPATH"))
316     {
317       NSArray *paths = [resourceDir stringsByAppendingPaths:
318                                   [NSArray arrayWithObjects:
319                                          @"site-lisp", @"lisp", @"leim", nil]];
320       NSEnumerator *pathEnum = [paths objectEnumerator];
321       resourcePaths = @"";
322       while (resourcePath = [pathEnum nextObject])
323         {
324           if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
325             if (isDir)
326               {
327                 if ([resourcePaths length] > 0)
328                   resourcePaths
329                     = [resourcePaths stringByAppendingString: pathSeparator];
330                 resourcePaths
331                   = [resourcePaths stringByAppendingString: resourcePath];
332               }
333         }
334       if ([resourcePaths length] > 0)
335         setenv ("EMACSLOADPATH", [resourcePaths UTF8String], 1);
336 /*NSLog (@"loadPath: '%@'\n", resourcePaths); */
337     }
339   if (!getenv ("EMACSPATH"))
340     {
341       NSArray *paths = [binDir stringsByAppendingPaths:
342                                   [NSArray arrayWithObjects: @"bin",
343                                                              @"lib-exec", nil]];
344       NSEnumerator *pathEnum = [paths objectEnumerator];
345       resourcePaths = @"";
346       while (resourcePath = [pathEnum nextObject])
347         {
348           if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
349             if (isDir)
350               {
351                 if ([resourcePaths length] > 0)
352                   resourcePaths
353                     = [resourcePaths stringByAppendingString: pathSeparator];
354                 resourcePaths
355                   = [resourcePaths stringByAppendingString: resourcePath];
356               }
357         }
358       if ([resourcePaths length] > 0)
359         setenv ("EMACSPATH", [resourcePaths UTF8String], 1);
360     }
362   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
363   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
364     {
365       if (isDir)
366         {
367           if (!getenv ("EMACSDATA"))
368             setenv ("EMACSDATA", [resourcePath UTF8String], 1);
369           if (!getenv ("EMACSDOC"))
370             setenv ("EMACSDOC", [resourcePath UTF8String], 1);
371         }
372     }
374   if (!getenv ("INFOPATH"))
375     {
376       resourcePath = [resourceDir stringByAppendingPathComponent: @"info"];
377       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
378         if (isDir)
379           setenv ("INFOPATH", [[resourcePath stringByAppendingString: @":"]
380                                              UTF8String], 1);
381       /* Note, extra colon needed to cause merge w/later user additions. */
382     }
386 static int
387 timeval_subtract (struct timeval *result, struct timeval x, struct timeval y)
388 /* --------------------------------------------------------------------------
389    Subtract the `struct timeval' values X and Y, storing the result in RESULT.
390    Return 1 if the difference is negative, otherwise 0.
391    -------------------------------------------------------------------------- */
393   /* Perform the carry for the later subtraction by updating y.
394      This is safer because on some systems
395      the tv_sec member is unsigned.  */
396   if (x.tv_usec < y.tv_usec)
397     {
398       int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
399       y.tv_usec -= 1000000 * nsec;
400       y.tv_sec += nsec;
401     }
402   if (x.tv_usec - y.tv_usec > 1000000)
403     {
404       int nsec = (y.tv_usec - x.tv_usec) / 1000000;
405       y.tv_usec += 1000000 * nsec;
406       y.tv_sec -= nsec;
407     }
409   /* Compute the time remaining to wait.  tv_usec is certainly positive.  */
410   result->tv_sec = x.tv_sec - y.tv_sec;
411   result->tv_usec = x.tv_usec - y.tv_usec;
413   /* Return indication of whether the result should be considered negative.  */
414   return x.tv_sec < y.tv_sec;
417 static void
418 ns_timeout (int usecs)
419 /* --------------------------------------------------------------------------
420      Blocking timer utility used by ns_ring_bell
421    -------------------------------------------------------------------------- */
423   struct timeval wakeup;
425   EMACS_GET_TIME (wakeup);
427   /* Compute time to wait until, propagating carry from usecs.  */
428   wakeup.tv_usec += usecs;
429   wakeup.tv_sec += (wakeup.tv_usec / 1000000);
430   wakeup.tv_usec %= 1000000;
432   /* Keep waiting until past the time wakeup.  */
433   while (1)
434     {
435       struct timeval timeout;
437       EMACS_GET_TIME (timeout);
439       /* In effect, timeout = wakeup - timeout.
440          Break if result would be negative.  */
441       if (timeval_subtract (&timeout, wakeup, timeout))
442         break;
444       /* Try to wait that long--but we might wake up sooner.  */
445       select (0, NULL, NULL, NULL, &timeout);
446     }
450 void
451 ns_release_object (void *obj)
452 /* --------------------------------------------------------------------------
453     Release an object (callable from C)
454    -------------------------------------------------------------------------- */
456     [(id)obj release];
460 void
461 ns_retain_object (void *obj)
462 /* --------------------------------------------------------------------------
463     Retain an object (callable from C)
464    -------------------------------------------------------------------------- */
466     [(id)obj retain];
470 void *
471 ns_alloc_autorelease_pool (void)
472 /* --------------------------------------------------------------------------
473      Allocate a pool for temporary objects (callable from C)
474    -------------------------------------------------------------------------- */
476   return [[NSAutoreleasePool alloc] init];
480 void
481 ns_release_autorelease_pool (void *pool)
482 /* --------------------------------------------------------------------------
483      Free a pool and temporary objects it refers to (callable from C)
484    -------------------------------------------------------------------------- */
486   ns_release_object (pool);
491 /* ==========================================================================
493     Focus (clipping) and screen update
495    ========================================================================== */
497 static NSRect
498 ns_resize_handle_rect (NSWindow *window)
500   NSRect r = [window frame];
501   r.origin.x = r.size.width - RESIZE_HANDLE_SIZE;
502   r.origin.y = 0;
503   r.size.width = r.size.height = RESIZE_HANDLE_SIZE;
504   return r;
508 static void
509 ns_update_begin (struct frame *f)
510 /* --------------------------------------------------------------------------
511    Prepare for a grouped sequence of drawing calls
512    external (RIF) call; whole frame, called before update_window_begin
513    -------------------------------------------------------------------------- */
515   NSView *view = FRAME_NS_VIEW (f);
516   NSTRACE (ns_update_begin);
518   ns_updating_frame = f;
519   [view lockFocus];
521 #ifdef NS_IMPL_GNUSTEP
522   uRect = NSMakeRect (0, 0, 0, 0);
523 #endif
527 static void
528 ns_update_window_begin (struct window *w)
529 /* --------------------------------------------------------------------------
530    Prepare for a grouped sequence of drawing calls
531    external (RIF) call; for one window, called after update_begin
532    -------------------------------------------------------------------------- */
534   struct frame *f = XFRAME (WINDOW_FRAME (w));
535  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
536   NSTRACE (ns_update_window_begin);
538   updated_window = w;
539   set_output_cursor (&w->cursor);
541   BLOCK_INPUT;
543   if (f == hlinfo->mouse_face_mouse_frame)
544     {
545       /* Don't do highlighting for mouse motion during the update.  */
546       hlinfo->mouse_face_defer = 1;
548         /* If the frame needs to be redrawn,
549            simply forget about any prior mouse highlighting.  */
550       if (FRAME_GARBAGED_P (f))
551         hlinfo->mouse_face_window = Qnil;
553       /* (further code for mouse faces ifdef'd out in other terms elided) */
554     }
556   UNBLOCK_INPUT;
560 static void
561 ns_update_window_end (struct window *w, int cursor_on_p,
562                       int mouse_face_overwritten_p)
563 /* --------------------------------------------------------------------------
564    Finished a grouped sequence of drawing calls
565    external (RIF) call; for one window called before update_end
566    -------------------------------------------------------------------------- */
568   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
570   /* note: this fn is nearly identical in all terms */
571   if (!w->pseudo_window_p)
572     {
573       BLOCK_INPUT;
575       if (cursor_on_p)
576         display_and_set_cursor (w, 1,
577                                 output_cursor.hpos, output_cursor.vpos,
578                                 output_cursor.x, output_cursor.y);
580       if (draw_window_fringes (w, 1))
581         x_draw_vertical_border (w);
583       UNBLOCK_INPUT;
584     }
586   /* If a row with mouse-face was overwritten, arrange for
587      frame_up_to_date to redisplay the mouse highlight.  */
588   if (mouse_face_overwritten_p)
589     {
590       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
591       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
592       hlinfo->mouse_face_window = Qnil;
593     }
595   updated_window = NULL;
596   NSTRACE (update_window_end);
600 static void
601 ns_update_end (struct frame *f)
602 /* --------------------------------------------------------------------------
603    Finished a grouped sequence of drawing calls
604    external (RIF) call; for whole frame, called after update_window_end
605    -------------------------------------------------------------------------- */
607   NSView *view = FRAME_NS_VIEW (f);
609 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
610     MOUSE_HL_INFO (f)->mouse_face_defer = 0;
612   BLOCK_INPUT;
614 #ifdef NS_IMPL_GNUSTEP
615   /* trigger flush only in the rectangle we tracked as being drawn */
616   [view unlockFocusNeedsFlush: NO];
617 /*fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", uRect.origin.x, uRect.origin.y, uRect.size.width, uRect.size.height); */
618   [view lockFocusInRect: uRect];
619 #endif
621   [view unlockFocus];
622   [[view window] flushWindow];
624   UNBLOCK_INPUT;
625   ns_updating_frame = NULL;
626   NSTRACE (ns_update_end);
630 static void
631 ns_flush (struct frame *f)
632 /* --------------------------------------------------------------------------
633    external (RIF) call
634    NS impl is no-op since currently we flush in ns_update_end and elsewhere
635    -------------------------------------------------------------------------- */
637     NSTRACE (ns_flush);
641 static void
642 ns_focus (struct frame *f, NSRect *r, int n)
643 /* --------------------------------------------------------------------------
644    Internal: Focus on given frame.  During small local updates this is used to
645      draw, however during large updates, ns_update_begin and ns_update_end are
646      called to wrap the whole thing, in which case these calls are stubbed out.
647      Except, on GNUstep, we accumulate the rectangle being drawn into, because
648      the back end won't do this automatically, and will just end up flushing
649      the entire window.
650    -------------------------------------------------------------------------- */
652 //  NSTRACE (ns_focus);
653 #ifdef NS_IMPL_GNUSTEP
654   NSRect u;
655     if (n == 2)
656       u = NSUnionRect (r[0], r[1]);
657     else if (r)
658       u = *r;
659 #endif
660 /* static int c =0;
661    fprintf (stderr, "focus: %d", c++);
662    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
663    fprintf (stderr, "\n"); */
665   if (f != ns_updating_frame)
666     {
667       NSView *view = FRAME_NS_VIEW (f);
668       if (view != focus_view)
669         {
670           if (focus_view != NULL)
671             {
672               [focus_view unlockFocus];
673               [[focus_view window] flushWindow];
674 /*debug_lock--; */
675             }
677           if (view)
678 #ifdef NS_IMPL_GNUSTEP
679             r ? [view lockFocusInRect: u] : [view lockFocus];
680 #else
681             [view lockFocus];
682 #endif
683           focus_view = view;
684 /*if (view) debug_lock++; */
685         }
686 #ifdef NS_IMPL_GNUSTEP
687       else
688         {
689           /* more than one rect being drawn into */
690           if (view && r)
691             {
692               [view unlockFocus]; /* add prev rect to redraw list */
693               [view lockFocusInRect: u]; /* focus for draw in new rect */
694             }
695         }
696 #endif
697     }
698 #ifdef NS_IMPL_GNUSTEP
699   else
700     {
701       /* in batch mode, but in GNUstep must still track rectangles explicitly */
702       uRect = (r ? NSUnionRect (uRect, u) : [FRAME_NS_VIEW (f) visibleRect]);
703     }
704 #endif
706   /* clipping */
707   if (r)
708     {
709       [[NSGraphicsContext currentContext] saveGraphicsState];
710       if (n == 2)
711         NSRectClipList (r, 2);
712       else
713         NSRectClip (*r);
714       gsaved = YES;
715     }
719 static void
720 ns_unfocus (struct frame *f)
721 /* --------------------------------------------------------------------------
722      Internal: Remove focus on given frame
723    -------------------------------------------------------------------------- */
725 //  NSTRACE (ns_unfocus);
727   if (gsaved)
728     {
729       [[NSGraphicsContext currentContext] restoreGraphicsState];
730       gsaved = NO;
731     }
733   if (f != ns_updating_frame)
734     {
735       if (focus_view != NULL)
736         {
737           [focus_view unlockFocus];
738           [[focus_view window] flushWindow];
739           focus_view = NULL;
740 /*debug_lock--; */
741         }
742     }
746 static void
747 ns_clip_to_row (struct window *w, struct glyph_row *row, int area, BOOL gc)
748 /* --------------------------------------------------------------------------
749      Internal (but parallels other terms): Focus drawing on given row
750    -------------------------------------------------------------------------- */
752   struct frame *f = XFRAME (WINDOW_FRAME (w));
753   NSRect clip_rect;
754   int window_x, window_y, window_width;
756   window_box (w, area, &window_x, &window_y, &window_width, 0);
758   clip_rect.origin.x = window_x - FRAME_INTERNAL_BORDER_WIDTH (f);
759   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
760   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
761   clip_rect.size.width = window_width + 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
762   clip_rect.size.height = row->visible_height;
764   /* allow a full-height row at the top when requested
765      (used to draw fringe all the way through internal border area) */
766   if (gc && clip_rect.origin.y < 5)
767     {
768       clip_rect.origin.y -= FRAME_INTERNAL_BORDER_WIDTH (f);
769       clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
770     }
772   /* likewise at bottom */
773   if (gc &&
774       FRAME_PIXEL_HEIGHT (f) - (clip_rect.origin.y + clip_rect.size.height) < 5)
775     clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
777   ns_focus (f, &clip_rect, 1);
781 static void
782 ns_ring_bell (struct frame *f)
783 /* --------------------------------------------------------------------------
784      "Beep" routine
785    -------------------------------------------------------------------------- */
787   NSTRACE (ns_ring_bell);
788   if (visible_bell)
789     {
790       NSAutoreleasePool *pool;
791       struct frame *frame = SELECTED_FRAME ();
792       NSView *view;
794       BLOCK_INPUT;
795       pool = [[NSAutoreleasePool alloc] init];
797       view = FRAME_NS_VIEW (frame);
798       if (view != nil)
799         {
800           NSRect r, surr;
801           NSPoint dim = NSMakePoint (128, 128);
803           r = [view bounds];
804           r.origin.x += (r.size.width - dim.x) / 2;
805           r.origin.y += (r.size.height - dim.y) / 2;
806           r.size.width = dim.x;
807           r.size.height = dim.y;
808           surr = NSInsetRect (r, -2, -2);
809           ns_focus (frame, &surr, 1);
810           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
811           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
812                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
813           NSRectFill (r);
814           [[view window] flushWindow];
815           ns_timeout (150000);
816           [[view window] restoreCachedImage];
817           [[view window] flushWindow];
818           ns_unfocus (frame);
819         }
820       [pool release];
821       UNBLOCK_INPUT;
822     }
823   else
824     {
825       NSBeep ();
826     }
830 static void
831 ns_reset_terminal_modes (struct terminal *terminal)
832 /*  Externally called as hook */
834   NSTRACE (ns_reset_terminal_modes);
838 static void
839 ns_set_terminal_modes (struct terminal *terminal)
840 /*  Externally called as hook */
842   NSTRACE (ns_set_terminal_modes);
847 /* ==========================================================================
849     Frame / window manager related functions
851    ========================================================================== */
854 static void
855 ns_raise_frame (struct frame *f)
856 /* --------------------------------------------------------------------------
857      Bring window to foreground and make it active
858    -------------------------------------------------------------------------- */
860   NSView *view = FRAME_NS_VIEW (f);
861   check_ns ();
862   BLOCK_INPUT;
863   FRAME_SAMPLE_VISIBILITY (f);
864   if (FRAME_VISIBLE_P (f))
865     {
866       [[view window] makeKeyAndOrderFront: NSApp];
867     }
868   UNBLOCK_INPUT;
872 static void
873 ns_lower_frame (struct frame *f)
874 /* --------------------------------------------------------------------------
875      Send window to back
876    -------------------------------------------------------------------------- */
878   NSView *view = FRAME_NS_VIEW (f);
879   check_ns ();
880   BLOCK_INPUT;
881   [[view window] orderBack: NSApp];
882   UNBLOCK_INPUT;
886 static void
887 ns_frame_raise_lower (struct frame *f, int raise)
888 /* --------------------------------------------------------------------------
889      External (hook)
890    -------------------------------------------------------------------------- */
892   NSTRACE (ns_frame_raise_lower);
894   if (raise)
895     ns_raise_frame (f);
896   else
897     ns_lower_frame (f);
901 static void
902 ns_frame_rehighlight (struct frame *frame)
903 /* --------------------------------------------------------------------------
904      External (hook): called on things like window switching within frame
905    -------------------------------------------------------------------------- */
907   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
908   struct frame *old_highlight = dpyinfo->x_highlight_frame;
910   NSTRACE (ns_frame_rehighlight);
911   if (dpyinfo->x_focus_frame)
912     {
913       dpyinfo->x_highlight_frame
914         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
915            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
916            : dpyinfo->x_focus_frame);
917       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
918         {
919           FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
920           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
921         }
922     }
923   else
924       dpyinfo->x_highlight_frame = 0;
926   if (dpyinfo->x_highlight_frame &&
927          dpyinfo->x_highlight_frame != old_highlight)
928     {
929       if (old_highlight)
930         {
931           x_update_cursor (old_highlight, 1);
932           x_set_frame_alpha (old_highlight);
933         }
934       if (dpyinfo->x_highlight_frame)
935         {
936           x_update_cursor (dpyinfo->x_highlight_frame, 1);
937           x_set_frame_alpha (dpyinfo->x_highlight_frame);
938         }
939     }
943 void
944 x_make_frame_visible (struct frame *f)
945 /* --------------------------------------------------------------------------
946      External: Show the window (X11 semantics)
947    -------------------------------------------------------------------------- */
949   NSTRACE (x_make_frame_visible);
950   /* XXX: at some points in past this was not needed, as the only place that
951      called this (frame.c:Fraise_frame ()) also called raise_lower;
952      if this ends up the case again, comment this out again. */
953   if (!FRAME_VISIBLE_P (f))
954     {
955       f->async_visible = 1;
956       ns_raise_frame (f);
957     }
961 void
962 x_make_frame_invisible (struct frame *f)
963 /* --------------------------------------------------------------------------
964      External: Hide the window (X11 semantics)
965    -------------------------------------------------------------------------- */
967   NSView * view = FRAME_NS_VIEW (f);
968   NSTRACE (x_make_frame_invisible);
969   check_ns ();
970   [[view window] orderOut: NSApp];
971   f->async_visible = 0;
972   f->async_iconified = 0;
976 void
977 x_iconify_frame (struct frame *f)
978 /* --------------------------------------------------------------------------
979      External: Iconify window
980    -------------------------------------------------------------------------- */
982   NSView * view = FRAME_NS_VIEW (f);
983   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
984   NSTRACE (x_iconify_frame);
985   check_ns ();
987   if (dpyinfo->x_highlight_frame == f)
988     dpyinfo->x_highlight_frame = 0;
990   if ([[view window] windowNumber] <= 0)
991     {
992       /* the window is still deferred.  Make it very small, bring it
993          on screen and order it out. */
994       NSRect s = { { 100, 100}, {0, 0} };
995       NSRect t;
996       t = [[view window] frame];
997       [[view window] setFrame: s display: NO];
998       [[view window] orderBack: NSApp];
999       [[view window] orderOut: NSApp];
1000       [[view window] setFrame: t display: NO];
1001     }
1002   [[view window] miniaturize: NSApp];
1006 void
1007 x_destroy_window (struct frame *f)
1008 /* --------------------------------------------------------------------------
1009      External: Delete the window
1010    -------------------------------------------------------------------------- */
1012   NSView *view = FRAME_NS_VIEW (f);
1013   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1014   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1015   NSTRACE (x_destroy_window);
1016   check_ns ();
1018   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1020   BLOCK_INPUT;
1022   free_frame_menubar (f);
1024   if (FRAME_FACE_CACHE (f))
1025     free_frame_faces (f);
1027   if (f == dpyinfo->x_focus_frame)
1028     dpyinfo->x_focus_frame = 0;
1029   if (f == dpyinfo->x_highlight_frame)
1030     dpyinfo->x_highlight_frame = 0;
1031   if (f == hlinfo->mouse_face_mouse_frame)
1032     {
1033       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
1034       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
1035       hlinfo->mouse_face_window = Qnil;
1036       hlinfo->mouse_face_deferred_gc = 0;
1037       hlinfo->mouse_face_mouse_frame = 0;
1038     }
1040   xfree (f->output_data.ns);
1042   [[view window] close];
1043   [view release];
1045   ns_window_num--;
1046   UNBLOCK_INPUT;
1050 void
1051 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1052 /* --------------------------------------------------------------------------
1053      External: Position the window
1054    -------------------------------------------------------------------------- */
1056   NSView *view = FRAME_NS_VIEW (f);
1057   NSArray *screens = [NSScreen screens];
1058   NSScreen *fscreen = [screens objectAtIndex: 0];
1059   NSScreen *screen = [[view window] screen];
1061   NSTRACE (x_set_offset);
1063   BLOCK_INPUT;
1065   f->left_pos = xoff;
1066   f->top_pos = yoff;
1068   if (view != nil && screen && fscreen)
1069     {
1070       f->left_pos = f->size_hint_flags & XNegative
1071         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1072         : f->left_pos;
1073       /* We use visibleFrame here to take menu bar into account.
1074          Ideally we should also adjust left/top with visibleFrame.origin.  */
1076       f->top_pos = f->size_hint_flags & YNegative
1077         ? ([screen visibleFrame].size.height + f->top_pos
1078            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1079            - FRAME_TOOLBAR_HEIGHT (f))
1080         : f->top_pos;
1081 #ifdef NS_IMPL_GNUSTEP
1082       if (f->left_pos < 100)
1083         f->left_pos = 100;  /* don't overlap menu */
1084 #endif
1085       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1086          menu bar.  */
1087       f->output_data.ns->dont_constrain = 0;
1088       [[view window] setFrameTopLeftPoint:
1089                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1090                                     SCREENMAXBOUND ([fscreen frame].size.height
1091                                                     - NS_TOP_POS (f)))];
1092       f->size_hint_flags &= ~(XNegative|YNegative);
1093     }
1095   UNBLOCK_INPUT;
1099 void
1100 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1101 /* --------------------------------------------------------------------------
1102      Adjust window pixel size based on given character grid size
1103      Impl is a bit more complex than other terms, need to do some
1104      internal clipping.
1105    -------------------------------------------------------------------------- */
1107   EmacsView *view = FRAME_NS_VIEW (f);
1108   EmacsToolbar *toolbar = [view toolbar];
1109   NSWindow *window = [view window];
1110   NSRect wr = [window frame];
1111   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1112   int pixelwidth, pixelheight;
1113   static int oldRows, oldCols, oldFontWidth, oldFontHeight;
1114   static int oldTB;
1115   static struct frame *oldF;
1117   NSTRACE (x_set_window_size);
1119   if (view == nil ||
1120       (f == oldF
1121        && rows == oldRows && cols == oldCols
1122        && oldFontWidth == FRAME_COLUMN_WIDTH (f)
1123        && oldFontHeight == FRAME_LINE_HEIGHT (f)
1124        && oldTB == tb))
1125     return;
1127 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1129   BLOCK_INPUT;
1131   check_frame_size (f, &rows, &cols);
1132   oldF = f;
1133   oldRows = rows;
1134   oldCols = cols;
1135   oldFontWidth = FRAME_COLUMN_WIDTH (f);
1136   oldFontHeight = FRAME_LINE_HEIGHT (f);
1137   oldTB = tb;
1139   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1140   compute_fringe_widths (f, 0);
1142   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1143   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1145   /* If we have a toolbar, take its height into account. */
1146   if (tb)
1147     /* NOTE: previously this would generate wrong result if toolbar not
1148              yet displayed and fixing toolbar_height=32 helped, but
1149              now (200903) seems no longer needed */
1150     FRAME_TOOLBAR_HEIGHT (f) =
1151       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1152         - FRAME_NS_TITLEBAR_HEIGHT (f);
1153   else
1154     FRAME_TOOLBAR_HEIGHT (f) = 0;
1156   wr.size.width = pixelwidth + f->border_width;
1157   wr.size.height = pixelheight + FRAME_NS_TITLEBAR_HEIGHT (f)
1158                   + FRAME_TOOLBAR_HEIGHT (f);
1160   /* Do not try to constrain to this screen.  We may have multiple
1161      screens, and want Emacs to span those.  Constraining to screen
1162      prevents that, and that is not nice to the user.  */
1163  if (f->output_data.ns->zooming)
1164    f->output_data.ns->zooming = 0;
1165  else
1166    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1168   [view setRows: rows andColumns: cols];
1169   [window setFrame: wr display: YES];
1171 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1173   /* This is a trick to compensate for Emacs' managing the scrollbar area
1174      as a fixed number of standard character columns.  Instead of leaving
1175      blank space for the extra, we chopped it off above.  Now for
1176      left-hand scrollbars, we shift all rendering to the left by the
1177      difference between the real width and Emacs' imagined one.  For
1178      right-hand bars, don't worry about it since the extra is never used.
1179      (Obviously doesn't work for vertically split windows tho..) */
1180   {
1181     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1182       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1183                      - NS_SCROLL_BAR_WIDTH (f), 0)
1184       : NSMakePoint (0, 0);
1185     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1186     [view setBoundsOrigin: origin];
1187   }
1189   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1190   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1191   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1192 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1194   mark_window_cursors_off (XWINDOW (f->root_window));
1195   cancel_mouse_face (f);
1197   UNBLOCK_INPUT;
1202 /* ==========================================================================
1204     Color management
1206    ========================================================================== */
1209 NSColor *
1210 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1212   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1213   if (idx < 1 || idx >= color_table->avail)
1214     return nil;
1215   return color_table->colors[idx];
1219 unsigned long
1220 ns_index_color (NSColor *color, struct frame *f)
1222   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1223   int idx;
1224   NSNumber *index;
1226   if (!color_table->colors)
1227     {
1228       color_table->size = NS_COLOR_CAPACITY;
1229       color_table->avail = 1; /* skip idx=0 as marker */
1230       color_table->colors
1231         = (NSColor **)xmalloc (color_table->size * sizeof (NSColor *));
1232       color_table->colors[0] = nil;
1233       color_table->empty_indices = [[NSMutableSet alloc] init];
1234     }
1236   /* do we already have this color ? */
1237   {
1238     int i;
1239     for (i = 1; i < color_table->avail; i++)
1240       {
1241         if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1242           {
1243             [color_table->colors[i] retain];
1244             return i;
1245           }
1246       }
1247   }
1249   if ([color_table->empty_indices count] > 0)
1250     {
1251       index = [color_table->empty_indices anyObject];
1252       [color_table->empty_indices removeObject: index];
1253       idx = [index unsignedIntValue];
1254     }
1255   else
1256     {
1257       if (color_table->avail == color_table->size)
1258         {
1259           color_table->size += NS_COLOR_CAPACITY;
1260           color_table->colors
1261             = (NSColor **)xrealloc (color_table->colors,
1262                                     color_table->size * sizeof (NSColor *));
1263         }
1264       idx = color_table->avail++;
1265     }
1267   color_table->colors[idx] = color;
1268   [color retain];
1269 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1270   return idx;
1274 void
1275 ns_free_indexed_color (unsigned long idx, struct frame *f)
1277   struct ns_color_table *color_table;
1278   NSColor *color;
1279   NSNumber *index;
1281   if (!f)
1282     return;
1284   color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1286   if (idx <= 0 || idx >= color_table->size) {
1287     message1("ns_free_indexed_color: Color index out of range.\n");
1288     return;
1289   }
1291   index = [NSNumber numberWithUnsignedInt: idx];
1292   if ([color_table->empty_indices containsObject: index]) {
1293     message1("ns_free_indexed_color: attempt to free already freed color.\n");
1294     return;
1295   }
1297   color = color_table->colors[idx];
1298   [color release];
1299   color_table->colors[idx] = nil;
1300   [color_table->empty_indices addObject: [NSNumber numberWithUnsignedInt: idx]];
1301 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1305 static int
1306 ns_get_color (const char *name, NSColor **col)
1307 /* --------------------------------------------------------------------------
1308      Parse a color name
1309    -------------------------------------------------------------------------- */
1310 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1311    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1312    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1314   NSColor *new = nil;
1315   static char hex[20];
1316   int scaling;
1317   float r = -1.0, g, b;
1318   NSString *nsname = [NSString stringWithUTF8String: name];
1320 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1321   BLOCK_INPUT;
1323   if ([nsname isEqualToString: @"ns_selection_color"])
1324     {
1325       nsname = ns_selection_color;
1326       name = [ns_selection_color UTF8String];
1327     }
1329   /* First, check for some sort of numeric specification. */
1330   hex[0] = '\0';
1332   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1333     {
1334       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1335       [scanner scanFloat: &r];
1336       [scanner scanFloat: &g];
1337       [scanner scanFloat: &b];
1338     }
1339   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1340     {
1341       strncpy (hex, name + 4, 19);
1342       hex[19] = '\0';
1343       scaling = (strlen(hex) - 2) / 3;
1344     }
1345   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1346     {
1347       int len = (strlen(name) - 1);
1348       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1349       int i;
1350       scaling = strlen(name+start) / 3;
1351       for (i=0; i<3; i++) {
1352         strncpy(hex + i * (scaling + 1), name + start + i * scaling, scaling);
1353         hex[(i+1) * (scaling + 1) - 1] = '/';
1354       }
1355       hex[3 * (scaling + 1) - 1] = '\0';
1356     }
1358   if (hex[0])
1359     {
1360       int rr, gg, bb;
1361       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1362       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1363         {
1364           r = rr / fscale;
1365           g = gg / fscale;
1366           b = bb / fscale;
1367         }
1368     }
1370   if (r >= 0.0)
1371     {
1372       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1373       UNBLOCK_INPUT;
1374       return 0;
1375     }
1377   /* Otherwise, color is expected to be from a list */
1378   {
1379     NSEnumerator *lenum, *cenum;
1380     NSString *name;
1381     NSColorList *clist;
1383 #ifdef NS_IMPL_GNUSTEP
1384     /* XXX: who is wrong, the requestor or the implementation? */
1385     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1386         == NSOrderedSame)
1387       nsname = @"highlightColor";
1388 #endif
1390     lenum = [[NSColorList availableColorLists] objectEnumerator];
1391     while ( (clist = [lenum nextObject]) && new == nil)
1392       {
1393         cenum = [[clist allKeys] objectEnumerator];
1394         while ( (name = [cenum nextObject]) && new == nil )
1395           {
1396             if ([name compare: nsname
1397                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1398               new = [clist colorWithKey: name];
1399           }
1400       }
1401   }
1403   if (new)
1404     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1405   UNBLOCK_INPUT;
1406   return new ? 0 : 1;
1410 static NSColor *
1411 ns_get_color_default (const char *name, NSColor *dflt)
1412 /* --------------------------------------------------------------------------
1413      Parse a color or use a default value
1414    -------------------------------------------------------------------------- */
1416   NSColor * col;
1418   if (ns_get_color (name, &col))
1419     return dflt;
1420   else
1421     return col;
1426 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1427 /* --------------------------------------------------------------------------
1428      Convert a Lisp string object to a NS color
1429    -------------------------------------------------------------------------- */
1431   NSTRACE (ns_lisp_to_color);
1432   if (STRINGP (color))
1433     return ns_get_color (SDATA (color), col);
1434   else if (SYMBOLP (color))
1435     return ns_get_color (SDATA (SYMBOL_NAME (color)), col);
1436   return 1;
1440 Lisp_Object
1441 ns_color_to_lisp (NSColor *col)
1442 /* --------------------------------------------------------------------------
1443      Convert a color to a lisp string with the RGB equivalent
1444    -------------------------------------------------------------------------- */
1446   CGFloat red, green, blue, alpha, gray;
1447   char buf[1024];
1448   const char *str;
1449   NSTRACE (ns_color_to_lisp);
1451   BLOCK_INPUT;
1452   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1454       if ((str =[[col colorNameComponent] UTF8String]))
1455         {
1456           UNBLOCK_INPUT;
1457           return build_string ((char *)str);
1458         }
1460     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1461         getRed: &red green: &green blue: &blue alpha: &alpha];
1462   if (red ==green && red ==blue)
1463     {
1464       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1465             getWhite: &gray alpha: &alpha];
1466       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1467                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1468       UNBLOCK_INPUT;
1469       return build_string (buf);
1470     }
1472   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1473             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1475   UNBLOCK_INPUT;
1476   return build_string (buf);
1480 void
1481 ns_query_color(void *col, XColor *color_def, int setPixel)
1482 /* --------------------------------------------------------------------------
1483          Get ARGB values out of NSColor col and put them into color_def.
1484          If setPixel, set the pixel to a concatenated version.
1485          and set color_def pixel to the resulting index.
1486    -------------------------------------------------------------------------- */
1488   CGFloat r, g, b, a;
1490   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1491   color_def->red   = r * 65535;
1492   color_def->green = g * 65535;
1493   color_def->blue  = b * 65535;
1495   if (setPixel == YES)
1496     color_def->pixel
1497       = ARGB_TO_ULONG((int)(a*255),
1498                       (int)(r*255), (int)(g*255), (int)(b*255));
1503 ns_defined_color (struct frame *f,
1504                   const char *name,
1505                   XColor *color_def,
1506                   int alloc,
1507                   char makeIndex)
1508 /* --------------------------------------------------------------------------
1509          Return 1 if named color found, and set color_def rgb accordingly.
1510          If makeIndex and alloc are nonzero put the color in the color_table,
1511          and set color_def pixel to the resulting index.
1512          If makeIndex is zero, set color_def pixel to ARGB.
1513          Return 0 if not found
1514    -------------------------------------------------------------------------- */
1516   NSColor *col;
1517   NSTRACE (ns_defined_color);
1519   BLOCK_INPUT;
1520   if (ns_get_color (name, &col) != 0) /* Color not found  */
1521     {
1522       UNBLOCK_INPUT;
1523       return 0;
1524     }
1525   if (makeIndex && alloc)
1526     color_def->pixel = ns_index_color (col, f);
1527   ns_query_color (col, color_def, !makeIndex);
1528   UNBLOCK_INPUT;
1529   return 1;
1533 unsigned long
1534 ns_get_rgb_color (struct frame *f, float r, float g, float b, float a)
1535 /* --------------------------------------------------------------------------
1536     return an autoreleased RGB color
1537    -------------------------------------------------------------------------- */
1539 /*static int c = 1; fprintf (stderr, "color request %d\n", c++); */
1540   if (r < 0.0) r = 0.0;
1541   else if (r > 1.0) r = 1.0;
1542   if (g < 0.0) g = 0.0;
1543   else if (g > 1.0) g = 1.0;
1544   if (b < 0.0) b = 0.0;
1545   else if (b > 1.0) b = 1.0;
1546   if (a < 0.0) a = 0.0;
1547   else if (a > 1.0) a = 1.0;
1548   return (unsigned long) ns_index_color(
1549     [NSColor colorWithCalibratedRed: r green: g blue: b alpha: a], f);
1553 void
1554 x_set_frame_alpha (struct frame *f)
1555 /* --------------------------------------------------------------------------
1556      change the entire-frame transparency
1557    -------------------------------------------------------------------------- */
1559   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1560   EmacsView *view = FRAME_NS_VIEW (f);
1561   double alpha = 1.0;
1562   double alpha_min = 1.0;
1564   if (dpyinfo->x_highlight_frame == f)
1565     alpha = f->alpha[0];
1566   else
1567     alpha = f->alpha[1];
1569   if (FLOATP (Vframe_alpha_lower_limit))
1570     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1571   else if (INTEGERP (Vframe_alpha_lower_limit))
1572     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1574   if (alpha < 0.0)
1575     return;
1576   else if (1.0 < alpha)
1577     alpha = 1.0;
1578   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1579     alpha = alpha_min;
1581 #ifdef NS_IMPL_COCOA
1582   [[view window] setAlphaValue: alpha];
1583 #endif
1587 /* ==========================================================================
1589     Mouse handling
1591    ========================================================================== */
1594 void
1595 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1596 /* --------------------------------------------------------------------------
1597      Programmatically reposition mouse pointer in pixel coordinates
1598    -------------------------------------------------------------------------- */
1600   NSTRACE (x_set_mouse_pixel_position);
1601   ns_raise_frame (f);
1602 #if 0
1603   /* FIXME: this does not work, and what about GNUstep? */
1604 #ifdef NS_IMPL_COCOA
1605   [FRAME_NS_VIEW (f) lockFocus];
1606   PSsetmouse ((float)pix_x, (float)pix_y);
1607   [FRAME_NS_VIEW (f) unlockFocus];
1608 #endif
1609 #endif
1613 void
1614 x_set_mouse_position (struct frame *f, int h, int v)
1615 /* --------------------------------------------------------------------------
1616      Programmatically reposition mouse pointer in character coordinates
1617    -------------------------------------------------------------------------- */
1619   int pix_x, pix_y;
1621   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1622   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1624   if (pix_x < 0) pix_x = 0;
1625   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1627   if (pix_y < 0) pix_y = 0;
1628   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1630   x_set_mouse_pixel_position (f, pix_x, pix_y);
1634 static int
1635 note_mouse_movement (struct frame *frame, float x, float y)
1636 /*   ------------------------------------------------------------------------
1637      Called by EmacsView on mouseMovement events.  Passes on
1638      to emacs mainstream code if we moved off of a rect of interest
1639      known as last_mouse_glyph.
1640      ------------------------------------------------------------------------ */
1642 //  NSTRACE (note_mouse_movement);
1644   XSETFRAME (last_mouse_motion_frame, frame);
1646   /* Note, this doesn't get called for enter/leave, since we don't have a
1647      position.  Those are taken care of in the corresponding NSView methods. */
1649   /* has movement gone beyond last rect we were tracking? */
1650   if (x < last_mouse_glyph.origin.x ||
1651       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1652       y < last_mouse_glyph.origin.y ||
1653       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1654     {
1655       ns_update_begin(frame);
1656       frame->mouse_moved = 1;
1657       note_mouse_highlight (frame, x, y);
1658       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1659       ns_update_end(frame);
1660       return 1;
1661     }
1663   return 0;
1667 static void
1668 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1669                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1670                    unsigned long *time)
1671 /* --------------------------------------------------------------------------
1672     External (hook): inform emacs about mouse position and hit parts.
1673     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1674     x & y should be position in the scrollbar (the whole bar, not the handle)
1675     and length of scrollbar respectively
1676    -------------------------------------------------------------------------- */
1678   id view;
1679   NSPoint position;
1680   int xchar, ychar;
1681   Lisp_Object frame, tail;
1682   struct frame *f;
1683   struct ns_display_info *dpyinfo;
1685   NSTRACE (ns_mouse_position);
1687   if (*fp == NULL)
1688     {
1689       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1690       return;
1691     }
1693   dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1695   BLOCK_INPUT;
1697   if (last_mouse_scroll_bar != nil && insist == 0)
1698     {
1699       /* TODO: we do not use this path at the moment because drag events will
1700            go directly to the EmacsScroller.  Leaving code in for now. */
1701       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1702                                               x: x y: y];
1703       if (time) *time = last_mouse_movement_time;
1704       last_mouse_scroll_bar = nil;
1705     }
1706   else
1707     {
1708       /* Clear the mouse-moved flag for every frame on this display.  */
1709       FOR_EACH_FRAME (tail, frame)
1710         if (FRAME_NS_P (XFRAME (frame))
1711             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1712           XFRAME (frame)->mouse_moved = 0;
1714       last_mouse_scroll_bar = nil;
1715       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1716         f = last_mouse_frame;
1717       else
1718         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1719                                     : SELECTED_FRAME ();
1721       if (f && f->output_data.ns)  /* TODO: 2nd check no longer needed? */
1722         {
1723           view = FRAME_NS_VIEW (*fp);
1725           position = [[view window] mouseLocationOutsideOfEventStream];
1726           position = [view convertPoint: position fromView: nil];
1727           remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1728 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1730           if (bar_window) *bar_window = Qnil;
1731           if (part) *part = 0; /*scroll_bar_handle; */
1733           if (x) XSETINT (*x, lrint (position.x));
1734           if (y) XSETINT (*y, lrint (position.y));
1735           if (time) *time = last_mouse_movement_time;
1736           *fp = f;
1737         }
1738     }
1740   UNBLOCK_INPUT;
1744 static void
1745 ns_frame_up_to_date (struct frame *f)
1746 /* --------------------------------------------------------------------------
1747     External (hook): Fix up mouse highlighting right after a full update.
1748     Some highlighting was deferred if GC was happening during
1749     note_mouse_highlight (), while other highlighting was deferred for update.
1750    -------------------------------------------------------------------------- */
1752   NSTRACE (ns_frame_up_to_date);
1754   if (FRAME_NS_P (f))
1755     {
1756       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1757       if ((hlinfo->mouse_face_deferred_gc || f ==hlinfo->mouse_face_mouse_frame)
1758       /*&& hlinfo->mouse_face_mouse_frame*/)
1759         {
1760           BLOCK_INPUT;
1761           ns_update_begin(f);
1762           if (hlinfo->mouse_face_mouse_frame)
1763             note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1764                                   hlinfo->mouse_face_mouse_x,
1765                                   hlinfo->mouse_face_mouse_y);
1766           hlinfo->mouse_face_deferred_gc = 0;
1767           ns_update_end(f);
1768           UNBLOCK_INPUT;
1769         }
1770     }
1774 void
1775 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1776 /* --------------------------------------------------------------------------
1777     External (RIF): set frame mouse pointer type.
1778    -------------------------------------------------------------------------- */
1780   NSTRACE (ns_define_frame_cursor);
1781   if (FRAME_POINTER_TYPE (f) != cursor)
1782     {
1783       EmacsView *view = FRAME_NS_VIEW (f);
1784       FRAME_POINTER_TYPE (f) = cursor;
1785       [[view window] invalidateCursorRectsForView: view];
1786       /* Redisplay assumes this function also draws the changed frame
1787          cursor, but this function doesn't, so do it explicitly.  */
1788       x_update_cursor (f, 1);
1789     }
1794 /* ==========================================================================
1796     Keyboard handling
1798    ========================================================================== */
1801 static unsigned
1802 ns_convert_key (unsigned code)
1803 /* --------------------------------------------------------------------------
1804     Internal call used by NSView-keyDown.
1805    -------------------------------------------------------------------------- */
1807   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1808                                 / sizeof (convert_ns_to_X_keysym[0]));
1809   unsigned keysym;
1810   /* An array would be faster, but less easy to read. */
1811   for (keysym = 0; keysym < last_keysym; keysym += 2)
1812     if (code == convert_ns_to_X_keysym[keysym])
1813       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1814   return 0;
1815 /* if decide to use keyCode and Carbon table, use this line:
1816      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1820 char *
1821 x_get_keysym_name (int keysym)
1822 /* --------------------------------------------------------------------------
1823     Called by keyboard.c.  Not sure if the return val is important, except
1824     that it be unique.
1825    -------------------------------------------------------------------------- */
1827   static char value[16];
1828   NSTRACE (x_get_keysym_name);
1829   sprintf (value, "%d", keysym);
1830   return value;
1835 /* ==========================================================================
1837     Block drawing operations
1839    ========================================================================== */
1842 static void
1843 ns_redraw_scroll_bars (struct frame *f)
1845   int i;
1846   id view;
1847   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1848   NSTRACE (ns_judge_scroll_bars);
1849   for (i =[subviews count]-1; i >= 0; i--)
1850     {
1851       view = [subviews objectAtIndex: i];
1852       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1853       [view display];
1854     }
1858 void
1859 ns_clear_frame (struct frame *f)
1860 /* --------------------------------------------------------------------------
1861       External (hook): Erase the entire frame
1862    -------------------------------------------------------------------------- */
1864   NSView *view = FRAME_NS_VIEW (f);
1865   NSRect r;
1867   NSTRACE (ns_clear_frame);
1868   if (ns_in_resize)
1869     return;
1871  /* comes on initial frame because we have
1872     after-make-frame-functions = select-frame */
1873  if (!FRAME_DEFAULT_FACE (f))
1874    return;
1876   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
1878   output_cursor.hpos = output_cursor.vpos = 0;
1879   output_cursor.x = -1;
1881   r = [view bounds];
1883   BLOCK_INPUT;
1884   ns_focus (f, &r, 1);
1885   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
1886   NSRectFill (r);
1887   ns_unfocus (f);
1889 #ifdef NS_IMPL_COCOA
1890   [[view window] display];  /* redraw resize handle */
1891 #endif
1893   /* as of 2006/11 or so this is now needed */
1894   ns_redraw_scroll_bars (f);
1895   UNBLOCK_INPUT;
1899 void
1900 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
1901 /* --------------------------------------------------------------------------
1902     External (RIF):  Clear section of frame
1903    -------------------------------------------------------------------------- */
1905   NSRect r = NSMakeRect (x, y, width, height);
1906   NSView *view = FRAME_NS_VIEW (f);
1907   struct face *face = FRAME_DEFAULT_FACE (f);
1909   if (!view || !face)
1910     return;
1912   NSTRACE (ns_clear_frame_area);
1914   r = NSIntersectionRect (r, [view frame]);
1915   ns_focus (f, &r, 1);
1916   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
1918 #ifdef NS_IMPL_COCOA
1919   {
1920     /* clip out the resize handle */
1921     NSWindow *window = [FRAME_NS_VIEW (f) window];
1922     NSRect ir
1923       = [view convertRect: ns_resize_handle_rect (window) fromView: nil];
1925     ir = NSIntersectionRect (r, ir);
1926     if (NSIsEmptyRect (ir))
1927       {
1928 #endif
1930   NSRectFill (r);
1932 #ifdef NS_IMPL_COCOA
1933       }
1934     else
1935       {
1936         NSRect r1 = r, r2 = r; /* upper and lower non-intersecting */
1937         r1.size.height -= ir.size.height;
1938         r2.origin.y += r1.size.height;
1939         r2.size.width -= ir.size.width;
1940         r2.size.height = ir.size.height;
1941         NSRectFill (r1);
1942         NSRectFill (r2);
1943       }
1944   }
1945 #endif
1947   ns_unfocus (f);
1948   return;
1952 static void
1953 ns_scroll_run (struct window *w, struct run *run)
1954 /* --------------------------------------------------------------------------
1955     External (RIF):  Insert or delete n lines at line vpos
1956    -------------------------------------------------------------------------- */
1958   struct frame *f = XFRAME (w->frame);
1959   int x, y, width, height, from_y, to_y, bottom_y;
1961   NSTRACE (ns_scroll_run);
1963   /* begin copy from other terms */
1964   /* Get frame-relative bounding box of the text display area of W,
1965      without mode lines.  Include in this box the left and right
1966      fringe of W.  */
1967   window_box (w, -1, &x, &y, &width, &height);
1969   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
1970   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
1971   bottom_y = y + height;
1973   if (to_y < from_y)
1974     {
1975       /* Scrolling up.  Make sure we don't copy part of the mode
1976          line at the bottom.  */
1977       if (from_y + run->height > bottom_y)
1978         height = bottom_y - from_y;
1979       else
1980         height = run->height;
1981     }
1982   else
1983     {
1984       /* Scolling down.  Make sure we don't copy over the mode line.
1985          at the bottom.  */
1986       if (to_y + run->height > bottom_y)
1987         height = bottom_y - to_y;
1988       else
1989         height = run->height;
1990     }
1991   /* end copy from other terms */
1993   if (height == 0)
1994       return;
1996   BLOCK_INPUT;
1998   updated_window = w;
1999   x_clear_cursor (w);
2001   {
2002     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2003     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2004     NSPoint dstOrigin = NSMakePoint (x, to_y);
2006     ns_focus (f, &dstRect, 1);
2007     NSCopyBits (0, srcRect , dstOrigin);
2008     ns_unfocus (f);
2009   }
2011   UNBLOCK_INPUT;
2015 static void
2016 ns_after_update_window_line (struct glyph_row *desired_row)
2017 /* --------------------------------------------------------------------------
2018     External (RIF): preparatory to fringe update after text was updated
2019    -------------------------------------------------------------------------- */
2021   struct window *w = updated_window;
2022   struct frame *f;
2023   int width, height;
2025   NSTRACE (ns_after_update_window_line);
2027   /* begin copy from other terms */
2028   xassert (w);
2030   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2031     desired_row->redraw_fringe_bitmaps_p = 1;
2033   /* When a window has disappeared, make sure that no rest of
2034      full-width rows stays visible in the internal border.
2035      Under NS this is drawn inside the fringes. */
2036   if (windows_or_buffers_changed
2037       && (f = XFRAME (w->frame),
2038           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2039           width != 0)
2040       && (height = desired_row->visible_height,
2041           height > 0))
2042     {
2043       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2045       /* Internal border is drawn below the tool bar.  */
2046       if (WINDOWP (f->tool_bar_window)
2047           && w == XWINDOW (f->tool_bar_window))
2048         y -= width;
2049       /* end copy from other terms */
2051       BLOCK_INPUT;
2052       if (!desired_row->full_width_p)
2053         {
2054           int x1 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2055             + WINDOW_LEFT_FRINGE_WIDTH (w);
2056           int x2 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2057             + FRAME_PIXEL_WIDTH (f) - NS_SCROLL_BAR_WIDTH (f)
2058             - WINDOW_RIGHT_FRINGE_WIDTH (w)
2059             - FRAME_INTERNAL_BORDER_WIDTH (f);
2060           ns_clear_frame_area (f, x1, y, width, height);
2061           ns_clear_frame_area (f, x2, y, width, height);
2062         }
2063       UNBLOCK_INPUT;
2064     }
2068 static void
2069 ns_shift_glyphs_for_insert (struct frame *f,
2070                            int x, int y, int width, int height,
2071                            int shift_by)
2072 /* --------------------------------------------------------------------------
2073     External (RIF): copy an area horizontally, don't worry about clearing src
2074    -------------------------------------------------------------------------- */
2076   NSRect srcRect = NSMakeRect (x, y, width, height);
2077   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2078   NSPoint dstOrigin = dstRect.origin;
2080   NSTRACE (ns_shift_glyphs_for_insert);
2082   ns_focus (f, &dstRect, 1);
2083   NSCopyBits (0, srcRect, dstOrigin);
2084   ns_unfocus (f);
2089 /* ==========================================================================
2091     Character encoding and metrics
2093    ========================================================================== */
2096 static inline void
2097 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2098 /* --------------------------------------------------------------------------
2099      External (RIF); compute left/right overhang of whole string and set in s
2100    -------------------------------------------------------------------------- */
2102   struct face *face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2103   struct font *font = s->font; /*face->font; */
2105   if (s->char2b)
2106     {
2107       struct font_metrics metrics;
2108       unsigned int codes[2];
2109       codes[0] = *(s->char2b);
2110       codes[1] = *(s->char2b + s->nchars - 1);
2112       font->driver->text_extents (font, codes, 2, &metrics);
2113       s->left_overhang = -metrics.lbearing;
2114       s->right_overhang
2115         = metrics.rbearing > metrics.width
2116         ? metrics.rbearing - metrics.width : 0;
2117     }
2118   else
2119     {
2120       s->left_overhang = 0;
2121       s->right_overhang = ((struct nsfont_info *)font)->ital ?
2122         FONT_HEIGHT (font) * 0.2 : 0;
2123     }
2128 /* ==========================================================================
2130     Fringe and cursor drawing
2132    ========================================================================== */
2135 extern int max_used_fringe_bitmap;
2136 static void
2137 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2138                       struct draw_fringe_bitmap_params *p)
2139 /* --------------------------------------------------------------------------
2140     External (RIF); fringe-related
2141    -------------------------------------------------------------------------- */
2143   struct frame *f = XFRAME (WINDOW_FRAME (w));
2144   struct face *face = p->face;
2145   int rowY;
2146   static EmacsImage **bimgs = NULL;
2147   static int nBimgs = 0;
2148   /* NS-specific: move internal border inside fringe */
2149   int x = p->bx < 0 ? p->x : p->bx;
2150   int wd = p->bx < 0 ? p->wd : p->nx;
2151   BOOL fringeOnVeryLeft
2152     = x - WINDOW_LEFT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w)
2153       - FRAME_INTERNAL_BORDER_WIDTH (f) < 10;
2154   BOOL fringeOnVeryRight
2155     = FRAME_PIXEL_WIDTH (f) - x - wd - FRAME_INTERNAL_BORDER_WIDTH (f)
2156       - WINDOW_RIGHT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w) < 10;
2157   int xAdjust = FRAME_INTERNAL_BORDER_WIDTH (f) *
2158     (fringeOnVeryLeft ? -1 : (fringeOnVeryRight ? 1 : 0));
2160   /* grow bimgs if needed */
2161   if (nBimgs < max_used_fringe_bitmap)
2162     {
2163       EmacsImage **newBimgs
2164         = xmalloc (max_used_fringe_bitmap * sizeof (EmacsImage *));
2165       memset (newBimgs, 0, max_used_fringe_bitmap * sizeof (EmacsImage *));
2167       if (nBimgs)
2168         {
2169           memcpy (newBimgs, bimgs, nBimgs * sizeof (EmacsImage *));
2170           xfree (bimgs);
2171         }
2173       bimgs = newBimgs;
2174       nBimgs = max_used_fringe_bitmap;
2175     }
2177   /* Must clip because of partially visible lines.  */
2178   rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2179   ns_clip_to_row (w, row, -1, YES);
2181   if (p->bx >= 0 && !p->overlay_p)
2182     {
2183       int yAdjust = rowY - FRAME_INTERNAL_BORDER_WIDTH (f) < 5 ?
2184         -FRAME_INTERNAL_BORDER_WIDTH (f) : 0;
2185       int yIncr = FRAME_PIXEL_HEIGHT (f) - (p->by+yAdjust + p->ny) < 5 ?
2186         FRAME_INTERNAL_BORDER_WIDTH (f) : 0
2187         + (yAdjust ? FRAME_INTERNAL_BORDER_WIDTH (f) : 0);
2188       NSRect r = NSMakeRect (p->bx+xAdjust, p->by+yAdjust, p->nx, p->ny+yIncr);
2189       NSRectClip (r);
2190       [ns_lookup_indexed_color(face->background, f) set];
2191       NSRectFill (r);
2192     }
2194   if (p->which)
2195     {
2196       NSRect r = NSMakeRect (p->x+xAdjust, p->y, p->wd, p->h);
2197       NSPoint pt = r.origin;
2198       EmacsImage *img = bimgs[p->which - 1];
2200       if (!img)
2201         {
2202           unsigned short *bits = p->bits + p->dh;
2203           int len = 8 * p->h/8;
2204           int i;
2205           unsigned char *cbits = xmalloc (len);
2207           for (i =0; i<len; i++)
2208             cbits[i] = ~(bits[i] & 0xff);
2209           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2210                                            flip: NO];
2211           bimgs[p->which - 1] = img;
2212           xfree (cbits);
2213         }
2215       NSRectClip (r);
2216       /* Since we composite the bitmap instead of just blitting it, we need
2217          to erase the whole background. */
2218       [ns_lookup_indexed_color(face->background, f) set];
2219       NSRectFill (r);
2220       pt.y += p->h;
2221       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2222       [img compositeToPoint: pt operation: NSCompositeSourceOver];
2223     }
2224   ns_unfocus (f);
2228 void
2229 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2230                        int x, int y, int cursor_type, int cursor_width,
2231                        int on_p, int active_p)
2232 /* --------------------------------------------------------------------------
2233      External call (RIF): draw cursor.
2234      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2235    -------------------------------------------------------------------------- */
2237   NSRect r, s;
2238   int fx, fy, h, cursor_height;
2239   struct frame *f = WINDOW_XFRAME (w);
2240   struct glyph *phys_cursor_glyph;
2241   int overspill;
2242   struct glyph *cursor_glyph;
2243   struct face *face;
2244   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2246   /* If cursor is out of bounds, don't draw garbage.  This can happen
2247      in mini-buffer windows when switching between echo area glyphs
2248      and mini-buffer.  */
2250   NSTRACE (dumpcursor);
2252   if (!on_p)
2253     return;
2255   w->phys_cursor_type = cursor_type;
2256   w->phys_cursor_on_p = on_p;
2258   if (cursor_type == NO_CURSOR)
2259     {
2260       w->phys_cursor_width = 0;
2261       return;
2262     }
2264   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2265     {
2266       if (glyph_row->exact_window_width_line_p
2267           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2268         {
2269           glyph_row->cursor_in_fringe_p = 1;
2270           draw_fringe_bitmap (w, glyph_row, 0);
2271         }
2272       return;
2273     }
2275   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2276      (other terminals do it the other way round).  We must set
2277      w->phys_cursor_width to the cursor width.  For bar cursors, that
2278      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2279   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2281   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2282      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2283   if (cursor_type == BAR_CURSOR)
2284     {
2285       if (cursor_width < 1)
2286         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2287       w->phys_cursor_width = cursor_width;
2288     }
2289   /* If we have an HBAR, "cursor_width" MAY specify height. */
2290   else if (cursor_type == HBAR_CURSOR)
2291     {
2292       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2293       fy += h - cursor_height;
2294       h = cursor_height;
2295     }
2297   r.origin.x = fx, r.origin.y = fy;
2298   r.size.height = h;
2299   r.size.width = w->phys_cursor_width;
2301   /* FIXME: if we overwrite the internal border area, it does not get erased;
2302      fix by truncating cursor, but better would be to erase properly */
2303   overspill = r.origin.x + r.size.width -
2304     WINDOW_TEXT_TO_FRAME_PIXEL_X (w, WINDOW_BOX_RIGHT_EDGE_X (w)
2305       - WINDOW_TOTAL_FRINGE_WIDTH (w) - FRAME_INTERNAL_BORDER_WIDTH (f));
2306   if (overspill > 0)
2307     r.size.width -= overspill;
2309   /* TODO: only needed in rare cases with last-resort font in HELLO..
2310      should we do this more efficiently? */
2311   ns_clip_to_row (w, glyph_row, -1, NO); /* do ns_focus(f, &r, 1); if remove */
2314   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2315   if (face && NS_FACE_BACKGROUND (face)
2316       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2317     {
2318       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2319       hollow_color = FRAME_CURSOR_COLOR (f);
2320     }
2321   else
2322     [FRAME_CURSOR_COLOR (f) set];
2324 #ifdef NS_IMPL_COCOA
2325   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2326            atomic.  Cleaner ways of doing this should be investigated.
2327            One way would be to set a global variable DRAWING_CURSOR
2328            when making the call to draw_phys..(), don't focus in that
2329            case, then move the ns_unfocus() here after that call. */
2330   NSDisableScreenUpdates ();
2331 #endif
2333   switch (cursor_type)
2334     {
2335     case NO_CURSOR:
2336       break;
2337     case FILLED_BOX_CURSOR:
2338       NSRectFill (r);
2339       break;
2340     case HOLLOW_BOX_CURSOR:
2341       NSRectFill (r);
2342       [hollow_color set];
2343       NSRectFill (NSInsetRect (r, 1, 1));
2344       [FRAME_CURSOR_COLOR (f) set];
2345       break;
2346     case HBAR_CURSOR:
2347       NSRectFill (r);
2348       break;
2349     case BAR_CURSOR:
2350       s = r;
2351       /* If the character under cursor is R2L, draw the bar cursor
2352          on the right of its glyph, rather than on the left.  */
2353       cursor_glyph = get_phys_cursor_glyph (w);
2354       if ((cursor_glyph->resolved_level & 1) != 0)
2355         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2357       NSRectFill (s);
2358       break;
2359     }
2360   ns_unfocus (f);
2362   /* draw the character under the cursor */
2363   if (cursor_type != NO_CURSOR)
2364     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2366 #ifdef NS_IMPL_COCOA
2367   NSEnableScreenUpdates ();
2368 #endif
2373 static void
2374 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2375 /* --------------------------------------------------------------------------
2376      External (RIF): Draw a vertical line.
2377    -------------------------------------------------------------------------- */
2379   struct frame *f = XFRAME (WINDOW_FRAME (w));
2380   struct face *face;
2381   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2383   NSTRACE (ns_draw_vertical_window_border);
2385   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2386   if (face)
2387       [ns_lookup_indexed_color(face->foreground, f) set];
2389   ns_focus (f, &r, 1);
2390   NSRectFill(r);
2391   ns_unfocus (f);
2395 void
2396 show_hourglass (struct atimer *timer)
2398   if (hourglass_shown_p)
2399     return;
2401   BLOCK_INPUT;
2403   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2405   hourglass_shown_p = 1;
2406   UNBLOCK_INPUT;
2410 void
2411 hide_hourglass (void)
2413   if (!hourglass_shown_p)
2414     return;
2416   BLOCK_INPUT;
2418   /* TODO: remove NSProgressIndicator from all frames */
2420   hourglass_shown_p = 0;
2421   UNBLOCK_INPUT;
2426 /* ==========================================================================
2428     Glyph drawing operations
2430    ========================================================================== */
2433 static inline NSRect
2434 ns_fix_rect_ibw (NSRect r, int fibw, int frame_pixel_width)
2435 /* --------------------------------------------------------------------------
2436     Under NS we draw internal borders inside fringes, and want full-width
2437     rendering to go all the way to edge.  This function makes that correction.
2438    -------------------------------------------------------------------------- */
2440   if (r.origin.y <= fibw+1)
2441     {
2442       r.size.height += r.origin.y;
2443       r.origin.y = 0;
2444     }
2445   if (r.origin.x <= fibw+1)
2446     {
2447       r.size.width += r.origin.x;
2448       r.origin.x = 0;
2449     }
2450   if (frame_pixel_width - (r.origin.x+r.size.width) <= fibw+1)
2451     r.size.width += fibw;
2453   return r;
2457 static int
2458 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2459 /* --------------------------------------------------------------------------
2460     Wrapper utility to account for internal border width on full-width lines,
2461     and allow top full-width rows to hit the frame top.  nr should be pointer
2462     to two successive NSRects.  Number of rects actually used is returned.
2463    -------------------------------------------------------------------------- */
2465   int n = get_glyph_string_clip_rects (s, nr, 2);
2466   if (s->row->full_width_p)
2467     {
2468       *nr = ns_fix_rect_ibw (*nr, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2469                             FRAME_PIXEL_WIDTH (s->f));
2470       if (n == 2)
2471         *nr = ns_fix_rect_ibw (*(nr+1), FRAME_INTERNAL_BORDER_WIDTH (s->f),
2472                               FRAME_PIXEL_WIDTH (s->f));
2473     }
2474   return n;
2478 static void
2479 ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char right_p)
2480 /* --------------------------------------------------------------------------
2481     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2482     Note we can't just use an NSDrawRect command, because of the possibility
2483     of some sides not being drawn, and because the rect will be filled.
2484    -------------------------------------------------------------------------- */
2486   NSRect s = r;
2487   [col set];
2489   /* top, bottom */
2490   s.size.height = thickness;
2491   NSRectFill (s);
2492   s.origin.y += r.size.height - thickness;
2493   NSRectFill (s);
2495   s.size.height = r.size.height;
2496   s.origin.y = r.origin.y;
2498   /* left, right (optional) */
2499   s.size.width = thickness;
2500   if (left_p)
2501     NSRectFill (s);
2502   if (right_p)
2503     {
2504       s.origin.x += r.size.width - thickness;
2505       NSRectFill (s);
2506     }
2510 static void
2511 ns_draw_relief (NSRect r, int thickness, char raised_p,
2512                char top_p, char bottom_p, char left_p, char right_p,
2513                struct glyph_string *s)
2514 /* --------------------------------------------------------------------------
2515     Draw a relief rect inside r, optionally leaving some sides open.
2516     Note we can't just use an NSDrawBezel command, because of the possibility
2517     of some sides not being drawn, and because the rect will be filled.
2518    -------------------------------------------------------------------------- */
2520   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2521   NSColor *newBaseCol = nil;
2522   NSRect sr = r;
2524   NSTRACE (ns_draw_relief);
2526   /* set up colors */
2528   if (s->face->use_box_color_for_shadows_p)
2529     {
2530       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2531     }
2532 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2533            && s->img->pixmap
2534            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2535        {
2536          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2537        } */
2538   else
2539     {
2540       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2541     }
2543   if (newBaseCol == nil)
2544     newBaseCol = [NSColor grayColor];
2546   if (newBaseCol != baseCol)  /* TODO: better check */
2547     {
2548       [baseCol release];
2549       baseCol = [newBaseCol retain];
2550       [lightCol release];
2551       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2552       [darkCol release];
2553       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2554     }
2556   [(raised_p ? lightCol : darkCol) set];
2558   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2560   /* top */
2561   sr.size.height = thickness;
2562   if (top_p) NSRectFill (sr);
2564   /* left */
2565   sr.size.height = r.size.height;
2566   sr.size.width = thickness;
2567   if (left_p) NSRectFill (sr);
2569   [(raised_p ? darkCol : lightCol) set];
2571   /* bottom */
2572   sr.size.width = r.size.width;
2573   sr.size.height = thickness;
2574   sr.origin.y += r.size.height - thickness;
2575   if (bottom_p) NSRectFill (sr);
2577   /* right */
2578   sr.size.height = r.size.height;
2579   sr.origin.y = r.origin.y;
2580   sr.size.width = thickness;
2581   sr.origin.x += r.size.width - thickness;
2582   if (right_p) NSRectFill (sr);
2586 static void
2587 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2588 /* --------------------------------------------------------------------------
2589       Function modeled after x_draw_glyph_string_box ().
2590       Sets up parameters for drawing.
2591    -------------------------------------------------------------------------- */
2593   int right_x, last_x;
2594   char left_p, right_p;
2595   struct glyph *last_glyph;
2596   NSRect r;
2597   int thickness;
2598   struct face *face;
2600   if (s->hl == DRAW_MOUSE_FACE)
2601     {
2602       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2603       if (!face)
2604         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2605     }
2606   else
2607     face = s->face;
2609   thickness = face->box_line_width;
2611   NSTRACE (ns_dumpglyphs_box_or_relief);
2613   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2614             ? WINDOW_RIGHT_EDGE_X (s->w)
2615             : window_box_right (s->w, s->area));
2616   last_glyph = (s->cmp || s->img
2617                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2619   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2620               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2622   left_p = (s->first_glyph->left_box_line_p
2623             || (s->hl == DRAW_MOUSE_FACE
2624                 && (s->prev == NULL || s->prev->hl != s->hl)));
2625   right_p = (last_glyph->right_box_line_p
2626              || (s->hl == DRAW_MOUSE_FACE
2627                  && (s->next == NULL || s->next->hl != s->hl)));
2629   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2631   /* expand full-width row over internal borders */
2632   if (s->row->full_width_p)
2633     r = ns_fix_rect_ibw (r, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2634                         FRAME_PIXEL_WIDTH (s->f));
2636   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2637   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2638     {
2639       ns_draw_box (r, abs (thickness),
2640                    ns_lookup_indexed_color (face->box_color, s->f),
2641                   left_p, right_p);
2642     }
2643   else
2644     {
2645       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2646                      1, 1, left_p, right_p, s);
2647     }
2651 static void
2652 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2653 /* --------------------------------------------------------------------------
2654       Modeled after x_draw_glyph_string_background, which draws BG in
2655       certain cases.  Others are left to the text rendering routine.
2656    -------------------------------------------------------------------------- */
2658   NSTRACE (ns_maybe_dumpglyphs_background);
2660   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2661     {
2662       int box_line_width = max (s->face->box_line_width, 0);
2663       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2664           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2665         {
2666           struct face *face;
2667           if (s->hl == DRAW_MOUSE_FACE)
2668             {
2669               face = FACE_FROM_ID (s->f,
2670                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2671               if (!face)
2672                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2673             }
2674           else
2675             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2676           if (!face->stipple)
2677             [(NS_FACE_BACKGROUND (face) != 0
2678               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2679               : FRAME_BACKGROUND_COLOR (s->f)) set];
2680           else
2681             {
2682               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2683               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2684             }
2686           if (s->hl != DRAW_CURSOR)
2687             {
2688               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2689                                     s->background_width,
2690                                     s->height-2*box_line_width);
2692               /* expand full-width row over internal borders */
2693               if (s->row->full_width_p)
2694                 {
2695                   int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2696                   if (r.origin.y <= fibw+1 + box_line_width)
2697                     {
2698                       r.size.height += r.origin.y;
2699                       r.origin.y = 0;
2700                     }
2701                   if (r.origin.x <= fibw+1)
2702                     {
2703                       r.size.width += 2*r.origin.x;
2704                       r.origin.x = 0;
2705                     }
2706                   if (FRAME_PIXEL_WIDTH (s->f) - (r.origin.x + r.size.width)
2707                       <= fibw+1)
2708                     r.size.width += fibw;
2709                 }
2711               NSRectFill (r);
2712             }
2714           s->background_filled_p = 1;
2715         }
2716     }
2720 static void
2721 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2722 /* --------------------------------------------------------------------------
2723       Renders an image and associated borders.
2724    -------------------------------------------------------------------------- */
2726   EmacsImage *img = s->img->pixmap;
2727   int box_line_vwidth = max (s->face->box_line_width, 0);
2728   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2729   int bg_x, bg_y, bg_height;
2730   int th;
2731   char raised_p;
2732   NSRect br;
2733   struct face *face;
2735   NSTRACE (ns_dumpglyphs_image);
2737   if (s->face->box != FACE_NO_BOX
2738       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2739     x += abs (s->face->box_line_width);
2741   bg_x = x;
2742   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2743   bg_height = s->height;
2744   /* other terms have this, but was causing problems w/tabbar mode */
2745   /* - 2 * box_line_vwidth; */
2747   if (s->slice.x == 0) x += s->img->hmargin;
2748   if (s->slice.y == 0) y += s->img->vmargin;
2750   /* Draw BG: if we need larger area than image itself cleared, do that,
2751      otherwise, since we composite the image under NS (instead of mucking
2752      with its background color), we must clear just the image area. */
2753   if (s->hl == DRAW_MOUSE_FACE)
2754     {
2755       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2756       if (!face)
2757        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2758     }
2759   else
2760     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2762   if (s->hl == DRAW_CURSOR)
2763       [FRAME_CURSOR_COLOR (s->f) set];
2764   else
2765     [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2767   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2768       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2769     {
2770       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
2771       s->background_filled_p = 1;
2772     }
2773   else
2774     {
2775       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
2776     }
2778   /* expand full-width row over internal borders */
2779   if (s->row->full_width_p)
2780     {
2781       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2782       if (br.origin.y <= fibw+1 + box_line_vwidth)
2783         {
2784           br.size.height += br.origin.y;
2785           br.origin.y = 0;
2786         }
2787       if (br.origin.x <= fibw+1 + box_line_vwidth)
2788         {
2789           br.size.width += br.origin.x;
2790           br.origin.x = 0;
2791         }
2792       if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) <= fibw+1)
2793         br.size.width += fibw;
2794     }
2796   NSRectFill (br);
2798   /* Draw the image.. do we need to draw placeholder if img ==nil? */
2799   if (img != nil)
2800     [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
2801                 operation: NSCompositeSourceOver];
2803   /* Draw relief, if requested */
2804   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
2805     {
2806       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
2807         {
2808           th = tool_bar_button_relief >= 0 ?
2809             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
2810           raised_p = (s->hl == DRAW_IMAGE_RAISED);
2811         }
2812       else
2813         {
2814           th = abs (s->img->relief);
2815           raised_p = (s->img->relief > 0);
2816         }
2818       r.origin.x = x - th;
2819       r.origin.y = y - th;
2820       r.size.width = s->slice.width + 2*th-1;
2821       r.size.height = s->slice.height + 2*th-1;
2822       ns_draw_relief (r, th, raised_p,
2823                       s->slice.y == 0,
2824                       s->slice.y + s->slice.height == s->img->height,
2825                       s->slice.x == 0,
2826                       s->slice.x + s->slice.width == s->img->width, s);
2827     }
2829   /* If there is no mask, the background won't be seen,
2830      so draw a rectangle on the image for the cursor.
2831      Do this for all images, getting trancparency right is not reliable.  */
2832   if (s->hl == DRAW_CURSOR)
2833     {
2834       int thickness = abs (s->img->relief);
2835       if (thickness == 0) thickness = 1;
2836       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
2837     }
2841 static void
2842 ns_dumpglyphs_stretch (struct glyph_string *s)
2844   NSRect r[2];
2845   int n, i;
2846   struct face *face;
2848   if (!s->background_filled_p)
2849     {
2850       n = ns_get_glyph_string_clip_rect (s, r);
2851       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
2853       for (i=0; i<n; i++)
2854         {
2855           if (!s->row->full_width_p)
2856             {
2857               /* truncate to avoid overwriting fringe and/or scrollbar */
2858               int overrun = max (0, (s->x + s->background_width)
2859                                   - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
2860                                     - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
2861               r[i].size.width -= overrun;
2863               /* XXX: Try to work between problem where a stretch glyph on
2864                  a partially-visible bottom row will clear part of the
2865                  modeline, and another where list-buffers headers and similar
2866                  rows erroneously have visible_height set to 0.  Not sure
2867                  where this is coming from as other terms seem not to show. */
2868               r[i].size.height = min (s->height, s->row->visible_height);
2869             }
2871           /* expand full-width rows over internal borders */
2872           else
2873             {
2874               r[i] = ns_fix_rect_ibw (r[i], FRAME_INTERNAL_BORDER_WIDTH (s->f),
2875                                       FRAME_PIXEL_WIDTH (s->f));
2876             }
2878           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
2879              overwriting cursor (usually when cursor on a tab) */
2880           if (s->hl == DRAW_CURSOR)
2881             {
2882               r[i].origin.x += s->width;
2883               r[i].size.width -= s->width;
2884             }
2885         }
2887       ns_focus (s->f, r, n);
2889       if (s->hl == DRAW_MOUSE_FACE)
2890        {
2891          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2892          if (!face)
2893            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2894        }
2895       else
2896        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2898       [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2900       NSRectFill (r[0]);
2901       NSRectFill (r[1]);
2902       ns_unfocus (s->f);
2903       s->background_filled_p = 1;
2904     }
2908 static void
2909 ns_draw_glyph_string (struct glyph_string *s)
2910 /* --------------------------------------------------------------------------
2911       External (RIF): Main draw-text call.
2912    -------------------------------------------------------------------------- */
2914   /* TODO (optimize): focus for box and contents draw */
2915   NSRect r[2];
2916   int n;
2917   char box_drawn_p = 0;
2919   NSTRACE (ns_draw_glyph_string);
2921   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
2922     {
2923       int width;
2924       struct glyph_string *next;
2926       for (width = 0, next = s->next;
2927            next && width < s->right_overhang;
2928            width += next->width, next = next->next)
2929         if (next->first_glyph->type != IMAGE_GLYPH)
2930           {
2931             if (next->first_glyph->type != STRETCH_GLYPH)
2932               {
2933                 n = ns_get_glyph_string_clip_rect (s->next, r);
2934                 ns_focus (s->f, r, n);
2935                 ns_maybe_dumpglyphs_background (s->next, 1);
2936                 ns_unfocus (s->f);
2937               }
2938             else
2939               {
2940                 ns_dumpglyphs_stretch (s->next);
2941               }
2942             next->num_clips = 0;
2943           }
2944     }
2946   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
2947         && (s->first_glyph->type == CHAR_GLYPH
2948             || s->first_glyph->type == COMPOSITE_GLYPH))
2949     {
2950       n = ns_get_glyph_string_clip_rect (s, r);
2951       ns_focus (s->f, r, n);
2952       ns_maybe_dumpglyphs_background (s, 1);
2953       ns_dumpglyphs_box_or_relief (s);
2954       ns_unfocus (s->f);
2955       box_drawn_p = 1;
2956     }
2958   switch (s->first_glyph->type)
2959     {
2961     case IMAGE_GLYPH:
2962       n = ns_get_glyph_string_clip_rect (s, r);
2963       ns_focus (s->f, r, n);
2964       ns_dumpglyphs_image (s, r[0]);
2965       ns_unfocus (s->f);
2966       break;
2968     case STRETCH_GLYPH:
2969       ns_dumpglyphs_stretch (s);
2970       break;
2972     case CHAR_GLYPH:
2973     case COMPOSITE_GLYPH:
2974       n = ns_get_glyph_string_clip_rect (s, r);
2975       ns_focus (s->f, r, n);
2977       if (s->for_overlaps || (s->cmp_from > 0
2978                               && ! s->first_glyph->u.cmp.automatic))
2979         s->background_filled_p = 1;
2980       else
2981         ns_maybe_dumpglyphs_background
2982           (s, s->first_glyph->type == COMPOSITE_GLYPH);
2984       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
2985                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
2986                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
2987                       NS_DUMPGLYPH_NORMAL));
2988       ns_tmp_font = (struct nsfont_info *)s->face->font;
2989       if (ns_tmp_font == NULL)
2990           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
2992       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
2993         {
2994           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
2995           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
2996           NS_FACE_FOREGROUND (s->face) = tmp;
2997         }
2999       ns_tmp_font->font.driver->draw
3000         (s, 0, s->nchars, s->x, s->y,
3001          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3002          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
3004       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3005         {
3006           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3007           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3008           NS_FACE_FOREGROUND (s->face) = tmp;
3009         }
3011       ns_unfocus (s->f);
3012       break;
3014     case GLYPHLESS_GLYPH:
3015       n = ns_get_glyph_string_clip_rect (s, r);
3016       ns_focus (s->f, r, n);
3018       if (s->for_overlaps || (s->cmp_from > 0
3019                               && ! s->first_glyph->u.cmp.automatic))
3020         s->background_filled_p = 1;
3021       else
3022         ns_maybe_dumpglyphs_background
3023           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3024       /* ... */
3025       /* Not yet implemented.  */
3026       /* ... */
3027       ns_unfocus (s->f);
3028       break;
3030     default:
3031       abort ();
3032     }
3034   /* Draw box if not done already. */
3035   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3036     {
3037       n = ns_get_glyph_string_clip_rect (s, r);
3038       ns_focus (s->f, r, n);
3039       ns_dumpglyphs_box_or_relief (s);
3040       ns_unfocus (s->f);
3041     }
3043   s->num_clips = 0;
3048 /* ==========================================================================
3050     Event loop
3052    ========================================================================== */
3055 static void
3056 ns_send_appdefined (int value)
3057 /* --------------------------------------------------------------------------
3058     Internal: post an appdefined event which EmacsApp-sendEvent will
3059               recognize and take as a command to halt the event loop.
3060    -------------------------------------------------------------------------- */
3062   /*NSTRACE (ns_send_appdefined); */
3064   /* Only post this event if we haven't already posted one.  This will end
3065        the [NXApp run] main loop after having processed all events queued at
3066        this moment.  */
3067   if (send_appdefined)
3068     {
3069       NSEvent *nxev;
3071       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3072       send_appdefined = NO;
3074       /* Don't need wakeup timer any more */
3075       if (timed_entry)
3076         {
3077           [timed_entry invalidate];
3078           [timed_entry release];
3079           timed_entry = nil;
3080         }
3082       /* Ditto for file descriptor poller */
3083       if (fd_entry)
3084         {
3085           [fd_entry invalidate];
3086           [fd_entry release];
3087           fd_entry = nil;
3088         }
3090       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3091                                 location: NSMakePoint (0, 0)
3092                            modifierFlags: 0
3093                                timestamp: 0
3094                             windowNumber: [[NSApp mainWindow] windowNumber]
3095                                  context: [NSApp context]
3096                                  subtype: 0
3097                                    data1: value
3098                                    data2: 0];
3100       /* Post an application defined event on the event queue.  When this is
3101          received the [NXApp run] will return, thus having processed all
3102          events which are currently queued.  */
3103       [NSApp postEvent: nxev atStart: NO];
3104     }
3108 static int
3109 ns_read_socket (struct terminal *terminal, int expected,
3110                 struct input_event *hold_quit)
3111 /* --------------------------------------------------------------------------
3112      External (hook): Post an event to ourself and keep reading events until
3113      we read it back again.  In effect process all events which were waiting.
3114      From 21+ we have to manage the event buffer ourselves.
3115    -------------------------------------------------------------------------- */
3117   struct input_event ev;
3118   int nevents;
3120 /* NSTRACE (ns_read_socket); */
3122   if (interrupt_input_blocked)
3123     {
3124       interrupt_input_pending = 1;
3125 #ifdef SYNC_INPUT
3126       pending_signals = 1;
3127 #endif
3128       return -1;
3129     }
3131   interrupt_input_pending = 0;
3132 #ifdef SYNC_INPUT
3133   pending_signals = pending_atimers;
3134 #endif
3136   BLOCK_INPUT;
3137   n_emacs_events_pending = 0;
3138   EVENT_INIT (ev);
3139   emacs_event = &ev;
3140   q_event_ptr = hold_quit;
3142   /* we manage autorelease pools by allocate/reallocate each time around
3143      the loop; strict nesting is occasionally violated but seems not to
3144      matter.. earlier methods using full nesting caused major memory leaks */
3145   [outerpool release];
3146   outerpool = [[NSAutoreleasePool alloc] init];
3148   /* If have pending open-file requests, attend to the next one of those. */
3149   if (ns_pending_files && [ns_pending_files count] != 0
3150       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3151     {
3152       [ns_pending_files removeObjectAtIndex: 0];
3153     }
3154   /* Deal with pending service requests. */
3155   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3156     && [(EmacsApp *)
3157          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3158                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3159     {
3160       [ns_pending_service_names removeObjectAtIndex: 0];
3161       [ns_pending_service_args removeObjectAtIndex: 0];
3162     }
3163   else
3164     {
3165       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3166          to ourself, otherwise [NXApp run] will never exit.  */
3167       send_appdefined = YES;
3169       /* If called via ns_select, this is called once with expected=1,
3170          because we expect either the timeout or file descriptor activity.
3171          In this case the first event through will either be real input or
3172          one of these.  read_avail_input() then calls once more with expected=0
3173          and in that case we need to return quickly if there is nothing.
3174          If we're being called outside of that, it's also OK to return quickly
3175          after one iteration through the event loop, since other terms do
3176          this and emacs expects it. */
3177       if (!(inNsSelect && expected))
3178         {
3179           /* Post an application defined event on the event queue.  When this is
3180              received the [NXApp run] will return, thus having processed all
3181              events which are currently queued, if any.  */
3182           ns_send_appdefined (-1);
3183         }
3185       [NSApp run];
3186     }
3188   nevents = n_emacs_events_pending;
3189   n_emacs_events_pending = 0;
3190   emacs_event = q_event_ptr = NULL;
3191   UNBLOCK_INPUT;
3193   return nevents;
3198 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3199            fd_set *exceptfds, struct timeval *timeout)
3200 /* --------------------------------------------------------------------------
3201      Replacement for select, checking for events
3202    -------------------------------------------------------------------------- */
3204   int result;
3205   double time;
3206   NSEvent *ev;
3207 /*  NSTRACE (ns_select); */
3209   if (NSApp == nil || inNsSelect == 1 /* || ([NSApp isActive] == NO &&
3210                       [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil
3211  inMode:NSDefaultRunLoopMode dequeue:NO] == nil) */)
3212     return select (nfds, readfds, writefds, exceptfds, timeout);
3214   /* Save file descriptor set, which gets overwritten in calls to select ()
3215      Note, this is called from process.c, and only readfds is ever set */
3216   if (readfds)
3217     {
3218       memcpy (&select_readfds, readfds, sizeof (fd_set));
3219       select_nfds = nfds;
3220     }
3221   else
3222     select_nfds = 0;
3224     /* Try an initial select for pending data on input files */
3225   select_timeout.tv_sec = select_timeout.tv_usec = 0;
3226   result = select (nfds, readfds, writefds, exceptfds, &select_timeout);
3227   if (result)
3228     return result;
3230   /* if (!timeout || timed_entry || fd_entry)
3231        fprintf (stderr, "assertion failed: timeout null or timed_entry/fd_entry non-null in ns_select\n"); */
3233     /* set a timeout and run the main AppKit event loop while continuing
3234        to monitor the files */
3235   time = ((double) timeout->tv_sec) + ((double) timeout->tv_usec)/1000000.0;
3236   timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3237                                            target: NSApp
3238                                          selector: @selector (timeout_handler:)
3239                                          userInfo: 0
3240                                           repeats: YES] /* for safe removal */
3241                                                          retain];
3243   /* set a periodic task to try the select () again */
3244   fd_entry = [[NSTimer scheduledTimerWithTimeInterval: 0.1
3245                                                target: NSApp
3246                                              selector: @selector (fd_handler:)
3247                                              userInfo: 0
3248                                               repeats: YES]
3249                retain];
3251   /* Let Application dispatch events until it receives an event of the type
3252      NX_APPDEFINED, which should only be sent by timeout_handler.
3253      We tell read_avail_input() that input is "expected" because we do expect
3254      either the timeout or fd handler to fire, and if they don't, the original
3255      call from process.c that got us here expects us to wait until some input
3256      comes. */
3257   inNsSelect = 1;
3258   gobble_input (1);
3259   ev = last_appdefined_event;
3260   inNsSelect = 0;
3262   if (ev)
3263     {
3264       int t;
3265       if ([ev type] != NSApplicationDefined)
3266         abort ();
3268       t = [ev data1];
3269       last_appdefined_event = 0;
3271       if (t == -2)
3272         {
3273           /* The NX_APPDEFINED event we received was a timeout. */
3274           return 0;
3275         }
3276       else if (t == -1)
3277         {
3278           /* The NX_APPDEFINED event we received was the result of
3279              at least one real input event arriving.  */
3280           errno = EINTR;
3281           return -1;
3282         }
3283       else
3284         {
3285           /* Received back from select () in fd_handler; copy the results */
3286           if (readfds)
3287             memcpy (readfds, &select_readfds, sizeof (fd_set));
3288           return t;
3289         }
3290     }
3291   /* never reached, shut compiler up */
3292   return 0;
3297 /* ==========================================================================
3299     Scrollbar handling
3301    ========================================================================== */
3304 static void
3305 ns_set_vertical_scroll_bar (struct window *window,
3306                            int portion, int whole, int position)
3307 /* --------------------------------------------------------------------------
3308       External (hook): Update or add scrollbar
3309    -------------------------------------------------------------------------- */
3311   Lisp_Object win;
3312   NSRect r, v;
3313   struct frame *f = XFRAME (WINDOW_FRAME (window));
3314   EmacsView *view = FRAME_NS_VIEW (f);
3315   int window_y, window_height;
3316   BOOL barOnVeryLeft, barOnVeryRight;
3317   int top, left, height, width, sb_width, sb_left;
3318   EmacsScroller *bar;
3319 static int count = 0;
3321   /* optimization; display engine sends WAY too many of these.. */
3322   if (!NILP (window->vertical_scroll_bar))
3323     {
3324       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3325       if ([bar checkSamePosition: position portion: portion whole: whole])
3326         {
3327           if (view->scrollbarsNeedingUpdate == 0)
3328             {
3329               if (!windows_or_buffers_changed)
3330                   return;
3331             }
3332           else
3333             view->scrollbarsNeedingUpdate--;
3334         }
3335     }
3337   NSTRACE (ns_set_vertical_scroll_bar);
3339   /* Get dimensions.  */
3340   window_box (window, -1, 0, &window_y, 0, &window_height);
3341   top = window_y;
3342   height = window_height;
3343   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3344   left = WINDOW_SCROLL_BAR_AREA_X (window);
3346   if (top < 5) /* top scrollbar adjustment */
3347     {
3348       top -= FRAME_INTERNAL_BORDER_WIDTH (f);
3349       height += FRAME_INTERNAL_BORDER_WIDTH (f);
3350     }
3352   /* allow for displaying a skinnier scrollbar than char area allotted */
3353   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3354     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3356   barOnVeryLeft = left < 5;
3357   barOnVeryRight = FRAME_PIXEL_WIDTH (f) - left - width < 5;
3358   sb_left = left + FRAME_INTERNAL_BORDER_WIDTH (f)
3359       * (barOnVeryLeft ? -1 : (barOnVeryRight ? 1 : 0));
3361   r = NSMakeRect (sb_left, top, sb_width, height);
3362   /* the parent view is flipped, so we need to flip y value */
3363   v = [view frame];
3364   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3366   XSETWINDOW (win, window);
3367   BLOCK_INPUT;
3369   /* we want at least 5 lines to display a scrollbar */
3370   if (WINDOW_TOTAL_LINES (window) < 5)
3371     {
3372       if (!NILP (window->vertical_scroll_bar))
3373         {
3374           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3375           [bar removeFromSuperview];
3376           window->vertical_scroll_bar = Qnil;
3377         }
3378       ns_clear_frame_area (f, sb_left, top, width, height);
3379       UNBLOCK_INPUT;
3380       return;
3381     }
3383   if (NILP (window->vertical_scroll_bar))
3384     {
3385       ns_clear_frame_area (f, sb_left, top, width, height);
3386       bar = [[EmacsScroller alloc] initFrame: r window: win];
3387       window->vertical_scroll_bar = make_save_value (bar, 0);
3388     }
3389   else
3390     {
3391       NSRect oldRect;
3392       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3393       oldRect = [bar frame];
3394       r.size.width = oldRect.size.width;
3395       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3396         {
3397           if (oldRect.origin.x != r.origin.x)
3398               ns_clear_frame_area (f, sb_left, top, width, height);
3399           [bar setFrame: r];
3400         }
3401     }
3403   [bar setPosition: position portion: portion whole: whole];
3404   UNBLOCK_INPUT;
3408 static void
3409 ns_condemn_scroll_bars (struct frame *f)
3410 /* --------------------------------------------------------------------------
3411      External (hook): arrange for all frame's scrollbars to be removed
3412      at next call to judge_scroll_bars, except for those redeemed.
3413    -------------------------------------------------------------------------- */
3415   int i;
3416   id view;
3417   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3419   NSTRACE (ns_condemn_scroll_bars);
3421   for (i =[subviews count]-1; i >= 0; i--)
3422     {
3423       view = [subviews objectAtIndex: i];
3424       if ([view isKindOfClass: [EmacsScroller class]])
3425         [view condemn];
3426     }
3430 static void
3431 ns_redeem_scroll_bar (struct window *window)
3432 /* --------------------------------------------------------------------------
3433      External (hook): arrange to spare this window's scrollbar
3434      at next call to judge_scroll_bars.
3435    -------------------------------------------------------------------------- */
3437   id bar;
3438   NSTRACE (ns_redeem_scroll_bar);
3439   if (!NILP (window->vertical_scroll_bar))
3440     {
3441       bar =XNS_SCROLL_BAR (window->vertical_scroll_bar);
3442       [bar reprieve];
3443     }
3447 static void
3448 ns_judge_scroll_bars (struct frame *f)
3449 /* --------------------------------------------------------------------------
3450      External (hook): destroy all scrollbars on frame that weren't
3451      redeemed after call to condemn_scroll_bars.
3452    -------------------------------------------------------------------------- */
3454   int i;
3455   id view;
3456   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3457   NSTRACE (ns_judge_scroll_bars);
3458   for (i =[subviews count]-1; i >= 0; i--)
3459     {
3460       view = [subviews objectAtIndex: i];
3461       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3462       [view judge];
3463     }
3467 void
3468 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
3470   /* XXX irrelevant under NS */
3475 /* ==========================================================================
3477     Initialization
3479    ========================================================================== */
3482 x_display_pixel_height (struct ns_display_info *dpyinfo)
3484   NSScreen *screen = [NSScreen mainScreen];
3485   return [screen frame].size.height;
3489 x_display_pixel_width (struct ns_display_info *dpyinfo)
3491   NSScreen *screen = [NSScreen mainScreen];
3492   return [screen frame].size.width;
3496 static Lisp_Object ns_string_to_lispmod (const char *s)
3497 /* --------------------------------------------------------------------------
3498      Convert modifier name to lisp symbol
3499    -------------------------------------------------------------------------- */
3501   if (!strncmp (SDATA (SYMBOL_NAME (Qmeta)), s, 10))
3502     return Qmeta;
3503   else if (!strncmp (SDATA (SYMBOL_NAME (Qsuper)), s, 10))
3504     return Qsuper;
3505   else if (!strncmp (SDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3506     return Qcontrol;
3507   else if (!strncmp (SDATA (SYMBOL_NAME (Qalt)), s, 10))
3508     return Qalt;
3509   else if (!strncmp (SDATA (SYMBOL_NAME (Qhyper)), s, 10))
3510     return Qhyper;
3511   else if (!strncmp (SDATA (SYMBOL_NAME (Qnone)), s, 10))
3512     return Qnone;
3513   else
3514     return Qnil;
3518 static Lisp_Object ns_mod_to_lisp (int m)
3519 /* --------------------------------------------------------------------------
3520      Convert modifier code (see lisp.h) to lisp symbol
3521    -------------------------------------------------------------------------- */
3523   if (m == CHAR_META)
3524     return Qmeta;
3525   else if (m == CHAR_SUPER)
3526     return Qsuper;
3527   else if (m == CHAR_CTL)
3528     return Qcontrol;
3529   else if (m == CHAR_ALT)
3530     return Qalt;
3531   else if (m == CHAR_HYPER)
3532     return Qhyper;
3533   else /* if (m == 0) */
3534     return Qnone;
3538 static void
3539 ns_default (const char *parameter, Lisp_Object *result,
3540            Lisp_Object yesval, Lisp_Object noval,
3541            BOOL is_float, BOOL is_modstring)
3542 /* --------------------------------------------------------------------------
3543       Check a parameter value in user's preferences
3544    -------------------------------------------------------------------------- */
3546   const char *value;
3548   if ( (value =[[[NSUserDefaults standardUserDefaults]
3549                    stringForKey: [NSString stringWithUTF8String: parameter]]
3550                 UTF8String]) )
3551     {
3552       double f;
3553       char *pos;
3554       if (strcasecmp (value, "YES") == 0)
3555         *result = yesval;
3556       else if (strcasecmp (value, "NO") == 0)
3557         *result = noval;
3558       else if (is_float && (f = strtod (value, &pos), pos != value))
3559         *result = make_float (f);
3560       else if (is_modstring && value)
3561         *result = ns_string_to_lispmod (value);
3562       else fprintf (stderr,
3563                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3564     }
3568 void
3569 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3570 /* --------------------------------------------------------------------------
3571       Initialize global info and storage for display.
3572    -------------------------------------------------------------------------- */
3574     NSScreen *screen = [NSScreen mainScreen];
3575     NSWindowDepth depth = [screen depth];
3576     Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
3578     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3579     dpyinfo->resy = 72.27;
3580     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3581                                                   NSColorSpaceFromDepth (depth)]
3582                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3583                                                  NSColorSpaceFromDepth (depth)];
3584     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3585     dpyinfo->image_cache = make_image_cache ();
3586     dpyinfo->color_table
3587       = (struct ns_color_table *)xmalloc (sizeof (struct ns_color_table));
3588     dpyinfo->color_table->colors = NULL;
3589     dpyinfo->root_window = 42; /* a placeholder.. */
3591     hlinfo->mouse_face_mouse_frame = NULL;
3592     hlinfo->mouse_face_deferred_gc = 0;
3593     hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
3594     hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
3595     hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
3596     hlinfo->mouse_face_window = hlinfo->mouse_face_overlay = Qnil;
3597     hlinfo->mouse_face_hidden = 0;
3599     hlinfo->mouse_face_mouse_x = hlinfo->mouse_face_mouse_y = 0;
3600     hlinfo->mouse_face_defer = 0;
3602     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3604     dpyinfo->n_fonts = 0;
3605     dpyinfo->smallest_font_height = 1;
3606     dpyinfo->smallest_char_width = 1;
3610 /* This and next define (many of the) public functions in this file. */
3611 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3612          with using despite presence in the "system dependent" redisplay
3613          interface.  In addition, many of the ns_ methods have code that is
3614          shared with all terms, indicating need for further refactoring. */
3615 extern frame_parm_handler ns_frame_parm_handlers[];
3616 static struct redisplay_interface ns_redisplay_interface =
3618   ns_frame_parm_handlers,
3619   x_produce_glyphs,
3620   x_write_glyphs,
3621   x_insert_glyphs,
3622   x_clear_end_of_line,
3623   ns_scroll_run,
3624   ns_after_update_window_line,
3625   ns_update_window_begin,
3626   ns_update_window_end,
3627   x_cursor_to,
3628   ns_flush,
3629   0, /* flush_display_optional */
3630   x_clear_window_mouse_face,
3631   x_get_glyph_overhangs,
3632   x_fix_overlapping_area,
3633   ns_draw_fringe_bitmap,
3634   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3635   0, /* destroy_fringe_bitmap */
3636   ns_compute_glyph_string_overhangs,
3637   ns_draw_glyph_string, /* interface to nsfont.m */
3638   ns_define_frame_cursor,
3639   ns_clear_frame_area,
3640   ns_draw_window_cursor,
3641   ns_draw_vertical_window_border,
3642   ns_shift_glyphs_for_insert
3646 static void
3647 ns_delete_display (struct ns_display_info *dpyinfo)
3649   /* TODO... */
3653 /* This function is called when the last frame on a display is deleted. */
3654 static void
3655 ns_delete_terminal (struct terminal *terminal)
3657   struct ns_display_info *dpyinfo = terminal->display_info.ns;
3658   int i;
3660   /* Protect against recursive calls.  delete_frame in
3661      delete_terminal calls us back when it deletes our last frame.  */
3662   if (!terminal->name)
3663     return;
3665   BLOCK_INPUT;
3667   x_destroy_all_bitmaps (dpyinfo);
3668   ns_delete_display (dpyinfo);
3669   UNBLOCK_INPUT;
3673 static struct terminal *
3674 ns_create_terminal (struct ns_display_info *dpyinfo)
3675 /* --------------------------------------------------------------------------
3676       Set up use of NS before we make the first connection.
3677    -------------------------------------------------------------------------- */
3679   struct terminal *terminal;
3681   NSTRACE (ns_create_terminal);
3683   terminal = create_terminal ();
3685   terminal->type = output_ns;
3686   terminal->display_info.ns = dpyinfo;
3687   dpyinfo->terminal = terminal;
3689   terminal->rif = &ns_redisplay_interface;
3691   terminal->clear_frame_hook = ns_clear_frame;
3692   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
3693   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
3694   terminal->ring_bell_hook = ns_ring_bell;
3695   terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
3696   terminal->set_terminal_modes_hook = ns_set_terminal_modes;
3697   terminal->update_begin_hook = ns_update_begin;
3698   terminal->update_end_hook = ns_update_end;
3699   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
3700   terminal->read_socket_hook = ns_read_socket;
3701   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
3702   terminal->mouse_position_hook = ns_mouse_position;
3703   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
3704   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
3706   terminal->fullscreen_hook = 0; /* see XTfullscreen_hook */
3708   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
3709   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
3710   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
3711   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
3713   terminal->delete_frame_hook = x_destroy_window;
3714   terminal->delete_terminal_hook = ns_delete_terminal;
3716   terminal->scroll_region_ok = 1;
3717   terminal->char_ins_del_ok = 1;
3718   terminal->line_ins_del_ok = 1;
3719   terminal->fast_clear_end_of_line = 1;
3720   terminal->memory_below_frame = 0;
3722   return terminal;
3726 struct ns_display_info *
3727 ns_term_init (Lisp_Object display_name)
3728 /* --------------------------------------------------------------------------
3729      Start the Application and get things rolling.
3730    -------------------------------------------------------------------------- */
3732   struct terminal *terminal;
3733   struct ns_display_info *dpyinfo;
3734   static int ns_initialized = 0;
3735   Lisp_Object tmp;
3737   NSTRACE (ns_term_init);
3739   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
3740   /*GSDebugAllocationActive (YES); */
3741   BLOCK_INPUT;
3742   handling_signal = 0;
3744   if (!ns_initialized)
3745     {
3746       baud_rate = 38400;
3747       Fset_input_interrupt_mode (Qnil);
3748       ns_initialized = 1;
3749     }
3751   ns_pending_files = [[NSMutableArray alloc] init];
3752   ns_pending_service_names = [[NSMutableArray alloc] init];
3753   ns_pending_service_args = [[NSMutableArray alloc] init];
3755   /* Start app and create the main menu, window, view.
3756      Needs to be here because ns_initialize_display_info () uses AppKit classes.
3757      The view will then ask the NSApp to stop and return to Emacs. */
3758   [EmacsApp sharedApplication];
3759   if (NSApp == nil)
3760     return NULL;
3761   [NSApp setDelegate: NSApp];
3763   /* debugging: log all notifications */
3764   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
3765                                          selector: @selector (logNotification:)
3766                                              name: nil object: nil]; */
3768   dpyinfo = (struct ns_display_info *)xmalloc (sizeof (struct ns_display_info));
3769   memset (dpyinfo, 0, sizeof (struct ns_display_info));
3771   ns_initialize_display_info (dpyinfo);
3772   terminal = ns_create_terminal (dpyinfo);
3774   terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
3775   init_kboard (terminal->kboard);
3776   KVAR (terminal->kboard, Vwindow_system) = Qns;
3777   terminal->kboard->next_kboard = all_kboards;
3778   all_kboards = terminal->kboard;
3779   /* Don't let the initial kboard remain current longer than necessary.
3780      That would cause problems if a file loaded on startup tries to
3781      prompt in the mini-buffer.  */
3782   if (current_kboard == initial_kboard)
3783     current_kboard = terminal->kboard;
3784   terminal->kboard->reference_count++;
3786   dpyinfo->next = x_display_list;
3787   x_display_list = dpyinfo;
3789   /* Put it on ns_display_name_list */
3790   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
3791                                 ns_display_name_list);
3792   dpyinfo->name_list_element = XCAR (ns_display_name_list);
3794   /* Set the name of the terminal. */
3795   terminal->name = (char *) xmalloc (SBYTES (display_name) + 1);
3796   strncpy (terminal->name, SDATA (display_name), SBYTES (display_name));
3797   terminal->name[SBYTES (display_name)] = 0;
3799   UNBLOCK_INPUT;
3801   if (!inhibit_x_resources)
3802     {
3803       ns_default ("GSFontAntiAlias", &ns_antialias_text,
3804                  Qt, Qnil, NO, NO);
3805       tmp = Qnil;
3806       /* this is a standard variable */
3807       ns_default ("AppleAntiAliasingThreshold", &tmp,
3808                  make_float (10.0), make_float (6.0), YES, NO);
3809       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
3810     }
3812   ns_selection_color = [[NSUserDefaults standardUserDefaults]
3813                          stringForKey: @"AppleHighlightColor"];
3814   if (ns_selection_color == nil)
3815     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
3817   {
3818     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
3820     if ( cl == nil )
3821       {
3822         Lisp_Object color_file, color_map, color;
3823         int r,g,b;
3824         unsigned long c;
3825         char *name;
3827         color_file = Fexpand_file_name (build_string ("rgb.txt"),
3828                          Fsymbol_value (intern ("data-directory")));
3829         if (NILP (Ffile_readable_p (color_file)))
3830           fatal ("Could not find %s.\n", SDATA (color_file));
3832         color_map = Fx_load_color_file (color_file);
3833         if (NILP (color_map))
3834           fatal ("Could not read %s.\n", SDATA (color_file));
3836         cl = [[NSColorList alloc] initWithName: @"Emacs"];
3837         for ( ; CONSP (color_map); color_map = XCDR (color_map))
3838           {
3839             color = XCAR (color_map);
3840             name = SDATA (XCAR (color));
3841             c = XINT (XCDR (color));
3842             [cl setColor:
3843                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
3844                                             green: GREEN_FROM_ULONG (c) / 255.0
3845                                              blue: BLUE_FROM_ULONG (c) / 255.0
3846                                             alpha: 1.0]
3847                   forKey: [NSString stringWithUTF8String: name]];
3848           }
3849         [cl writeToFile: nil];
3850       }
3851   }
3853   {
3854     char c[128];
3855 #ifdef NS_IMPL_GNUSTEP
3856     strncpy (c, gnustep_base_version, sizeof (c));
3857 #else
3858     /*PSnextrelease (128, c); */
3859     snprintf (c, sizeof (c), "%g", NSAppKitVersionNumber);
3860 #endif
3861     Vwindow_system_version = build_string (c);
3862   }
3864   delete_keyboard_wait_descriptor (0);
3866   ns_app_name = [[NSProcessInfo processInfo] processName];
3868 /* Set up OS X app menu */
3869 #ifdef NS_IMPL_COCOA
3870   {
3871     NSMenu *appMenu;
3872     NSMenuItem *item;
3873     /* set up the application menu */
3874     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
3875     [svcsMenu setAutoenablesItems: NO];
3876     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
3877     [appMenu setAutoenablesItems: NO];
3878     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
3879     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
3881     [appMenu insertItemWithTitle: @"About Emacs"
3882                           action: @selector (orderFrontStandardAboutPanel:)
3883                    keyEquivalent: @""
3884                          atIndex: 0];
3885     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
3886     [appMenu insertItemWithTitle: @"Preferences..."
3887                           action: @selector (showPreferencesWindow:)
3888                    keyEquivalent: @","
3889                          atIndex: 2];
3890     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
3891     item = [appMenu insertItemWithTitle: @"Services"
3892                                  action: @selector (menuDown:)
3893                           keyEquivalent: @""
3894                                 atIndex: 4];
3895     [appMenu setSubmenu: svcsMenu forItem: item];
3896     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
3897     [appMenu insertItemWithTitle: @"Hide Emacs"
3898                           action: @selector (hide:)
3899                    keyEquivalent: @"h"
3900                          atIndex: 6];
3901     item =  [appMenu insertItemWithTitle: @"Hide Others"
3902                           action: @selector (hideOtherApplications:)
3903                    keyEquivalent: @"h"
3904                          atIndex: 7];
3905     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
3906     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
3907     [appMenu insertItemWithTitle: @"Quit Emacs"
3908                           action: @selector (terminate:)
3909                    keyEquivalent: @"q"
3910                          atIndex: 9];
3912     item = [mainMenu insertItemWithTitle: ns_app_name
3913                                   action: @selector (menuDown:)
3914                            keyEquivalent: @""
3915                                  atIndex: 0];
3916     [mainMenu setSubmenu: appMenu forItem: item];
3917     [dockMenu insertItemWithTitle: @"New Frame"
3918                            action: @selector (newFrame:)
3919                     keyEquivalent: @""
3920                           atIndex: 0];
3922     [NSApp setMainMenu: mainMenu];
3923     [NSApp setAppleMenu: appMenu];
3924     [NSApp setServicesMenu: svcsMenu];
3925     /* Needed at least on Cocoa, to get dock menu to show windows */
3926     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
3927   }
3928 #endif /* MAC OS X menu setup */
3930   [NSApp run];
3932   return dpyinfo;
3936 void
3937 ns_term_shutdown (int sig)
3939   /* code not reached in emacs.c after this is called by shut_down_emacs: */
3940   if (STRINGP (Vauto_save_list_file_name))
3941     unlink (SDATA (Vauto_save_list_file_name));
3943   if (sig == 0 || sig == SIGTERM)
3944     {
3945       [NSApp terminate: NSApp];
3946     }
3947   else // force a stack trace to happen
3948     {
3949       abort();
3950     }
3954 /* ==========================================================================
3956     EmacsApp implementation
3958    ========================================================================== */
3961 @implementation EmacsApp
3963 - (void)logNotification: (NSNotification *)notification
3965   const char *name = [[notification name] UTF8String];
3966   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
3967       && !strstr (name, "WindowNumber"))
3968     NSLog (@"notification: '%@'", [notification name]);
3972 - (void)sendEvent: (NSEvent *)theEvent
3973 /* --------------------------------------------------------------------------
3974      Called when NSApp is running for each event received.  Used to stop
3975      the loop when we choose, since there's no way to just run one iteration.
3976    -------------------------------------------------------------------------- */
3978   int type = [theEvent type];
3979   NSWindow *window = [theEvent window];
3980 /*  NSTRACE (sendEvent); */
3981 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
3983   if (type == NSCursorUpdate && window == nil)
3984     {
3985       fprintf (stderr, "Dropping external cursor update event.\n");
3986       return;
3987     }
3989 #ifdef NS_IMPL_COCOA
3990   /* pass mouse down in resize handle and subsequent drags directly to
3991      EmacsWindow so we can generate continuous redisplays */
3992   if (ns_in_resize)
3993     {
3994       if (type == NSLeftMouseDragged)
3995         {
3996           [window mouseDragged: theEvent];
3997           return;
3998         }
3999       else if (type == NSLeftMouseUp)
4000         {
4001           [window mouseUp: theEvent];
4002           return;
4003         }
4004     }
4005   else if (type == NSLeftMouseDown)
4006     {
4007       NSRect r = ns_resize_handle_rect (window);
4008       if (NSPointInRect ([theEvent locationInWindow], r))
4009         {
4010           ns_in_resize = YES;
4011           [window mouseDown: theEvent];
4012           return;
4013         }
4014     }
4015 #endif
4017   if (type == NSApplicationDefined)
4018     {
4019       /* Events posted by ns_send_appdefined interrupt the run loop here.
4020          But, if a modal window is up, an appdefined can still come through,
4021          (e.g., from a makeKeyWindow event) but stopping self also stops the
4022          modal loop. Just defer it until later. */
4023       if ([NSApp modalWindow] == nil)
4024         {
4025           last_appdefined_event = theEvent;
4026           [self stop: self];
4027         }
4028       else
4029         {
4030           send_appdefined = YES;
4031         }
4032     }
4034   [super sendEvent: theEvent];
4038 - (void)showPreferencesWindow: (id)sender
4040   struct frame *emacsframe = SELECTED_FRAME ();
4041   NSEvent *theEvent = [NSApp currentEvent];
4043   if (!emacs_event)
4044     return;
4045   emacs_event->kind = NS_NONKEY_EVENT;
4046   emacs_event->code = KEY_NS_SHOW_PREFS;
4047   emacs_event->modifiers = 0;
4048   EV_TRAILER (theEvent);
4052 - (void)newFrame: (id)sender
4054   struct frame *emacsframe = SELECTED_FRAME ();
4055   NSEvent *theEvent = [NSApp currentEvent];
4057   if (!emacs_event)
4058     return;
4059   emacs_event->kind = NS_NONKEY_EVENT;
4060   emacs_event->code = KEY_NS_NEW_FRAME;
4061   emacs_event->modifiers = 0;
4062   EV_TRAILER (theEvent);
4066 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4067 - (BOOL) openFile: (NSString *)fileName
4069   struct frame *emacsframe = SELECTED_FRAME ();
4070   NSEvent *theEvent = [NSApp currentEvent];
4072   if (!emacs_event)
4073     return NO;
4075   emacs_event->kind = NS_NONKEY_EVENT;
4076   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4077   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4078   ns_input_line = Qnil; /* can be start or cons start,end */
4079   emacs_event->modifiers =0;
4080   EV_TRAILER (theEvent);
4082   return YES;
4086 /* **************************************************************************
4088       EmacsApp delegate implementation
4090    ************************************************************************** */
4092 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4093 /* --------------------------------------------------------------------------
4094      When application is loaded, terminate event loop in ns_term_init
4095    -------------------------------------------------------------------------- */
4097   NSTRACE (applicationDidFinishLaunching);
4098   [NSApp setServicesProvider: NSApp];
4099   ns_send_appdefined (-2);
4103 /* Termination sequences:
4104     C-x C-c:
4105     Cmd-Q:
4106     MenuBar | File | Exit:
4107     Select Quit from App menubar:
4108         -terminate
4109         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4110         ns_term_shutdown()
4112     Select Quit from Dock menu:
4113     Logout attempt:
4114         -appShouldTerminate
4115           Cancel -> Nothing else
4116           Accept ->
4118           -terminate
4119           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4120           ns_term_shutdown()
4124 - (void) terminate: (id)sender
4126   struct frame *emacsframe = SELECTED_FRAME ();
4128   if (!emacs_event)
4129     return;
4131   emacs_event->kind = NS_NONKEY_EVENT;
4132   emacs_event->code = KEY_NS_POWER_OFF;
4133   emacs_event->arg = Qt; /* mark as non-key event */
4134   EV_TRAILER ((id)nil);
4138 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4140   int ret;
4142   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4143     return NSTerminateNow;
4145     ret = NSRunAlertPanel(ns_app_name,
4146                           [NSString stringWithUTF8String:"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?"],
4147                           @"Save Buffers and Exit", @"Cancel", nil);
4149     if (ret == NSAlertDefaultReturn)
4150         return NSTerminateNow;
4151     else if (ret == NSAlertAlternateReturn)
4152         return NSTerminateCancel;
4153     return NSTerminateNow;  /* just in case */
4157 /*   Notification from the Workspace to open a file */
4158 - (BOOL)application: sender openFile: (NSString *)file
4160   [ns_pending_files addObject: file];
4161   return YES;
4165 /*   Open a file as a temporary file */
4166 - (BOOL)application: sender openTempFile: (NSString *)file
4168   [ns_pending_files addObject: file];
4169   return YES;
4173 /*   Notification from the Workspace to open a file noninteractively (?) */
4174 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4176   [ns_pending_files addObject: file];
4177   return YES;
4181 /*   Notification from the Workspace to open multiple files */
4182 - (void)application: sender openFiles: (NSArray *)fileList
4184   NSEnumerator *files = [fileList objectEnumerator];
4185   NSString *file;
4186   while ((file = [files nextObject]) != nil)
4187     [ns_pending_files addObject: file];
4189   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4194 /* Handle dock menu requests.  */
4195 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4197   return dockMenu;
4201 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4202 - (void)applicationWillBecomeActive: (NSNotification *)notification
4204   //ns_app_active=YES;
4206 - (void)applicationDidBecomeActive: (NSNotification *)notification
4208   //ns_app_active=YES;
4210 - (void)applicationDidResignActive: (NSNotification *)notification
4212   //ns_app_active=NO;
4213   ns_send_appdefined (-1);
4218 /* ==========================================================================
4220     EmacsApp aux handlers for managing event loop
4222    ========================================================================== */
4225 - (void)timeout_handler: (NSTimer *)timedEntry
4226 /* --------------------------------------------------------------------------
4227      The timeout specified to ns_select has passed.
4228    -------------------------------------------------------------------------- */
4230   /*NSTRACE (timeout_handler); */
4231   ns_send_appdefined (-2);
4234 - (void)fd_handler: (NSTimer *) fdEntry
4235 /* --------------------------------------------------------------------------
4236      Check data waiting on file descriptors and terminate if so
4237    -------------------------------------------------------------------------- */
4239   int result;
4240   /* NSTRACE (fd_handler); */
4242   if (select_nfds == 0)
4243     return;
4245   memcpy (&t_readfds, &select_readfds, sizeof (fd_set));
4247   select_timeout.tv_sec = select_timeout.tv_usec = 0;
4248   result = select (select_nfds, &t_readfds, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
4249                   &select_timeout);
4250   if (result)
4251     {
4252       memcpy (&select_readfds, &t_readfds, sizeof (fd_set));
4253       ns_send_appdefined (result);
4254     }
4259 /* ==========================================================================
4261     Service provision
4263    ========================================================================== */
4265 /* called from system: queue for next pass through event loop */
4266 - (void)requestService: (NSPasteboard *)pboard
4267               userData: (NSString *)userData
4268                  error: (NSString **)error
4270   [ns_pending_service_names addObject: userData];
4271   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4272       SDATA (ns_string_from_pasteboard (pboard))]];
4276 /* called from ns_read_socket to clear queue */
4277 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4279   struct frame *emacsframe = SELECTED_FRAME ();
4280   NSEvent *theEvent = [NSApp currentEvent];
4282   if (!emacs_event)
4283     return NO;
4285   emacs_event->kind = NS_NONKEY_EVENT;
4286   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4287   ns_input_spi_name = build_string ([name UTF8String]);
4288   ns_input_spi_arg = build_string ([arg UTF8String]);
4289   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4290   EV_TRAILER (theEvent);
4292   return YES;
4296 @end  /* EmacsApp */
4300 /* ==========================================================================
4302     EmacsView implementation
4304    ========================================================================== */
4307 @implementation EmacsView
4309 /* needed to inform when window closed from LISP */
4310 - (void) setWindowClosing: (BOOL)closing
4312   windowClosing = closing;
4316 - (void)dealloc
4318   NSTRACE (EmacsView_dealloc);
4319   [toolbar release];
4320   [super dealloc];
4324 /* called on font panel selection */
4325 - (void)changeFont: (id)sender
4327   NSEvent *e =[[self window] currentEvent];
4328   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4329   id newFont;
4330   float size;
4332   NSTRACE (changeFont);
4333   if (!emacs_event)
4334     return;
4336   if (newFont = [sender convertFont:
4337                            ((struct nsfont_info *)face->font)->nsfont])
4338     {
4339       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4341       emacs_event->kind = NS_NONKEY_EVENT;
4342       emacs_event->modifiers = 0;
4343       emacs_event->code = KEY_NS_CHANGE_FONT;
4345       size = [newFont pointSize];
4346       ns_input_fontsize = make_number (lrint (size));
4347       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4348       EV_TRAILER (e);
4349     }
4353 - (BOOL)acceptsFirstResponder
4355   NSTRACE (acceptsFirstResponder);
4356   return YES;
4360 - (void)resetCursorRects
4362   NSRect visible = [self visibleRect];
4363   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4364   NSTRACE (resetCursorRects);
4366   if (currentCursor == nil)
4367     currentCursor = [NSCursor arrowCursor];
4369   if (!NSIsEmptyRect (visible))
4370     [self addCursorRect: visible cursor: currentCursor];
4371   [currentCursor setOnMouseEntered: YES];
4376 /*****************************************************************************/
4377 /* Keyboard handling. */
4378 #define NS_KEYLOG 0
4380 - (void)keyDown: (NSEvent *)theEvent
4382   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4383   int code;
4384   unsigned fnKeysym = 0;
4385   int flags;
4386   static NSMutableArray *nsEvArray;
4387   static BOOL firstTime = YES;
4388   int left_is_none;
4390   NSTRACE (keyDown);
4392   /* Rhapsody and OS X give up and down events for the arrow keys */
4393   if (ns_fake_keydown == YES)
4394     ns_fake_keydown = NO;
4395   else if ([theEvent type] != NSKeyDown)
4396     return;
4398   if (!emacs_event)
4399     return;
4401  if (![[self window] isKeyWindow]
4402      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4403      /* we must avoid an infinite loop here. */
4404      && (EmacsView *)[[theEvent window] delegate] != self)
4405    {
4406      /* XXX: There is an occasional condition in which, when Emacs display
4407          updates a different frame from the current one, and temporarily
4408          selects it, then processes some interrupt-driven input
4409          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4410          for some reason that window has its first responder set to the NSView
4411          most recently updated (I guess), which is not the correct one. */
4412      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4413      return;
4414    }
4416   if (nsEvArray == nil)
4417     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4419   [NSCursor setHiddenUntilMouseMoves: YES];
4421   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4422     {
4423       clear_mouse_face (hlinfo);
4424       hlinfo->mouse_face_hidden = 1;
4425     }
4427   if (!processingCompose)
4428     {
4429       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4430         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4431       /* (Carbon way: [theEvent keyCode]) */
4433       /* is it a "function key"? */
4434       fnKeysym = ns_convert_key (code);
4435       if (fnKeysym)
4436         {
4437           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4438              because Emacs treats Delete and KP-Delete same (in simple.el). */
4439           if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4440             code = 0xFF08; /* backspace */
4441           else
4442             code = fnKeysym;
4443         }
4445       /* are there modifiers? */
4446       emacs_event->modifiers = 0;
4447       flags = [theEvent modifierFlags];
4449       if (flags & NSHelpKeyMask)
4450           emacs_event->modifiers |= hyper_modifier;
4452       if (flags & NSShiftKeyMask)
4453         emacs_event->modifiers |= shift_modifier;
4455       if ((flags & NSRightCommandKeyMask) == NSRightCommandKeyMask)
4456         emacs_event->modifiers |= parse_solitary_modifier
4457           (EQ (ns_right_command_modifier, Qleft)
4458            ? ns_command_modifier
4459            : ns_right_command_modifier);
4461       if ((flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask)
4462         {
4463           emacs_event->modifiers |= parse_solitary_modifier
4464             (ns_command_modifier);
4466           /* if super (default), take input manager's word so things like
4467              dvorak / qwerty layout work */
4468           if (EQ (ns_command_modifier, Qsuper)
4469               && !fnKeysym
4470               && [[theEvent characters] length] != 0)
4471             {
4472               /* XXX: the code we get will be unshifted, so if we have
4473                  a shift modifier, must convert ourselves */
4474               if (!(flags & NSShiftKeyMask))
4475                 code = [[theEvent characters] characterAtIndex: 0];
4476 #if 0
4477               /* this is ugly and also requires linking w/Carbon framework
4478                  (for LMGetKbdType) so for now leave this rare (?) case
4479                  undealt with.. in future look into CGEvent methods */
4480               else
4481                 {
4482                   long smv = GetScriptManagerVariable (smKeyScript);
4483                   Handle uchrHandle = GetResource
4484                     ('uchr', GetScriptVariable (smv, smScriptKeys));
4485                   UInt32 dummy = 0;
4486                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
4487                                  [[theEvent characters] characterAtIndex: 0],
4488                                  kUCKeyActionDisplay,
4489                                  (flags & ~NSCommandKeyMask) >> 8,
4490                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
4491                                  &dummy, 1, &dummy, &code);
4492                   code &= 0xFF;
4493                 }
4494 #endif
4495             }
4496         }
4498       if ((flags & NSRightControlKeyMask) == NSRightControlKeyMask)
4499           emacs_event->modifiers |= parse_solitary_modifier
4500               (EQ (ns_right_control_modifier, Qleft)
4501                ? ns_control_modifier
4502                : ns_right_control_modifier);
4504       if ((flags & NSLeftControlKeyMask) == NSLeftControlKeyMask)
4505         emacs_event->modifiers |= parse_solitary_modifier
4506           (ns_control_modifier);
4508       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
4509           emacs_event->modifiers |=
4510             parse_solitary_modifier (ns_function_modifier);
4512       left_is_none = NILP (ns_alternate_modifier)
4513         || EQ (ns_alternate_modifier, Qnone);
4515       if ((flags & NSRightAlternateKeyMask) == NSRightAlternateKeyMask)
4516         {
4517           if ((NILP (ns_right_alternate_modifier)
4518                || EQ (ns_right_alternate_modifier, Qnone)
4519                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
4520               && !fnKeysym)
4521             {   /* accept pre-interp alt comb */
4522               if ([[theEvent characters] length] > 0)
4523                 code = [[theEvent characters] characterAtIndex: 0];
4524               /*HACK: clear lone shift modifier to stop next if from firing */
4525               if (emacs_event->modifiers == shift_modifier)
4526                 emacs_event->modifiers = 0;
4527             }
4528           else
4529             emacs_event->modifiers |= parse_solitary_modifier
4530               (EQ (ns_right_alternate_modifier, Qleft)
4531                ? ns_alternate_modifier
4532                : ns_right_alternate_modifier);
4533         }
4535       if ((flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask) /* default = meta */
4536         {
4537           if (left_is_none && !fnKeysym)
4538             {   /* accept pre-interp alt comb */
4539               if ([[theEvent characters] length] > 0)
4540                 code = [[theEvent characters] characterAtIndex: 0];
4541               /*HACK: clear lone shift modifier to stop next if from firing */
4542               if (emacs_event->modifiers == shift_modifier)
4543                 emacs_event->modifiers = 0;
4544             }
4545           else
4546               emacs_event->modifiers |=
4547                 parse_solitary_modifier (ns_alternate_modifier);
4548         }
4550   if (NS_KEYLOG)
4551     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
4552              code, fnKeysym, flags, emacs_event->modifiers);
4554       /* if it was a function key or had modifiers, pass it directly to emacs */
4555       if (fnKeysym || (emacs_event->modifiers
4556                        && (emacs_event->modifiers != shift_modifier)
4557                        && [[theEvent charactersIgnoringModifiers] length] > 0))
4558 /*[[theEvent characters] length] */
4559         {
4560           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4561           if (code < 0x20)
4562             code |= (1<<28)|(3<<16);
4563           else if (code == 0x7f)
4564             code |= (1<<28)|(3<<16);
4565           else if (!fnKeysym)
4566             emacs_event->kind = code > 0xFF
4567               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4569           emacs_event->code = code;
4570           EV_TRAILER (theEvent);
4571           return;
4572         }
4573     }
4575   /* if we get here we should send the key for input manager processing */
4576   if (firstTime && [[NSInputManager currentInputManager]
4577                      wantsToDelayTextChangeNotifications] == NO)
4578     fprintf (stderr,
4579           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
4580   firstTime = NO;
4582   if (NS_KEYLOG && !processingCompose)
4583     fprintf (stderr, "keyDown: Begin compose sequence.\n");
4585   processingCompose = YES;
4586   [nsEvArray addObject: theEvent];
4587   [self interpretKeyEvents: nsEvArray];
4588   [nsEvArray removeObject: theEvent];
4592 #ifdef NS_IMPL_COCOA
4593 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
4594    decided not to send key-down for.
4595    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
4596    This only applies on Tiger and earlier.
4597    If it matches one of these, send it on to keyDown. */
4598 -(void)keyUp: (NSEvent *)theEvent
4600   int flags = [theEvent modifierFlags];
4601   int code = [theEvent keyCode];
4602   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
4603       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
4604     {
4605       if (NS_KEYLOG)
4606         fprintf (stderr, "keyUp: passed test");
4607       ns_fake_keydown = YES;
4608       [self keyDown: theEvent];
4609     }
4611 #endif
4614 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
4617 /* <NSTextInput>: called when done composing;
4618    NOTE: also called when we delete over working text, followed immed.
4619          by doCommandBySelector: deleteBackward: */
4620 - (void)insertText: (id)aString
4622   int code;
4623   int len = [(NSString *)aString length];
4624   int i;
4626   if (NS_KEYLOG)
4627     NSLog (@"insertText '%@'\tlen = %d", aString, len);
4628   processingCompose = NO;
4630   if (!emacs_event)
4631     return;
4633   /* first, clear any working text */
4634   if (workingText != nil)
4635     [self deleteWorkingText];
4637   /* now insert the string as keystrokes */
4638   for (i =0; i<len; i++)
4639     {
4640       code = [aString characterAtIndex: i];
4641       /* TODO: still need this? */
4642       if (code == 0x2DC)
4643         code = '~'; /* 0x7E */
4644       emacs_event->modifiers = 0;
4645       emacs_event->kind
4646         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4647       emacs_event->code = code;
4648       EV_TRAILER ((id)nil);
4649     }
4653 /* <NSTextInput>: inserts display of composing characters */
4654 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
4656   NSString *str = [aString respondsToSelector: @selector (string)] ?
4657     [aString string] : aString;
4658   if (NS_KEYLOG)
4659     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
4660            selRange.length, selRange.location);
4662   if (workingText != nil)
4663     [self deleteWorkingText];
4664   if ([str length] == 0)
4665     return;
4667   if (!emacs_event)
4668     return;
4670   processingCompose = YES;
4671   workingText = [str copy];
4672   ns_working_text = build_string ([workingText UTF8String]);
4674   emacs_event->kind = NS_TEXT_EVENT;
4675   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
4676   EV_TRAILER ((id)nil);
4680 /* delete display of composing characters [not in <NSTextInput>] */
4681 - (void)deleteWorkingText
4683   if (workingText == nil)
4684     return;
4685   if (NS_KEYLOG)
4686     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
4687   [workingText release];
4688   workingText = nil;
4689   processingCompose = NO;
4691   if (!emacs_event)
4692     return;
4694   emacs_event->kind = NS_TEXT_EVENT;
4695   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
4696   EV_TRAILER ((id)nil);
4700 - (BOOL)hasMarkedText
4702   return workingText != nil;
4706 - (NSRange)markedRange
4708   NSRange rng = workingText != nil
4709     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
4710   if (NS_KEYLOG)
4711     NSLog (@"markedRange request");
4712   return rng;
4716 - (void)unmarkText
4718   if (NS_KEYLOG)
4719     NSLog (@"unmark (accept) text");
4720   [self deleteWorkingText];
4721   processingCompose = NO;
4725 /* used to position char selection windows, etc. */
4726 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
4728   NSRect rect;
4729   NSPoint pt;
4730   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
4731   if (NS_KEYLOG)
4732     NSLog (@"firstRectForCharRange request");
4734   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
4735   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
4736   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
4737   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
4738                                        +FRAME_LINE_HEIGHT (emacsframe));
4740   pt = [self convertPoint: pt toView: nil];
4741   pt = [[self window] convertBaseToScreen: pt];
4742   rect.origin = pt;
4743   return rect;
4747 - (long)conversationIdentifier
4749   return (long)self;
4753 - (void)doCommandBySelector: (SEL)aSelector
4755   if (NS_KEYLOG)
4756     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
4758   if (aSelector == @selector (deleteBackward:))
4759     {
4760       /* happens when user backspaces over an ongoing composition:
4761          throw a 'delete' into the event queue */
4762       if (!emacs_event)
4763         return;
4764       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4765       emacs_event->code = 0xFF08;
4766       EV_TRAILER ((id)nil);
4767     }
4770 - (NSArray *)validAttributesForMarkedText
4772   static NSArray *arr = nil;
4773   if (arr == nil) arr = [NSArray new];
4774  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
4775   return arr;
4778 - (NSRange)selectedRange
4780   if (NS_KEYLOG)
4781     NSLog (@"selectedRange request");
4782   return NSMakeRange (NSNotFound, 0);
4785 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
4787   if (NS_KEYLOG)
4788     NSLog (@"characterIndexForPoint request");
4789   return 0;
4792 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
4794   static NSAttributedString *str = nil;
4795   if (str == nil) str = [NSAttributedString new];
4796   if (NS_KEYLOG)
4797     NSLog (@"attributedSubstringFromRange request");
4798   return str;
4801 /* End <NSTextInput> impl. */
4802 /*****************************************************************************/
4805 /* This is what happens when the user presses a mouse button.  */
4806 - (void)mouseDown: (NSEvent *)theEvent
4808   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
4809   Lisp_Object window;
4811   NSTRACE (mouseDown);
4813   [self deleteWorkingText];
4815   if (!emacs_event)
4816     return;
4818   last_mouse_frame = emacsframe;
4819   /* appears to be needed to prevent spurious movement events generated on
4820      button clicks */
4821   last_mouse_frame->mouse_moved = 0;
4823   if ([theEvent type] == NSScrollWheel)
4824     {
4825       float delta = [theEvent deltaY];
4826       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
4827       if (delta == 0)
4828         return;
4829       emacs_event->kind = WHEEL_EVENT;
4830       emacs_event->code = 0;
4831       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
4832         ((delta > 0) ? up_modifier : down_modifier);
4833     }
4834   else
4835     {
4836       emacs_event->kind = MOUSE_CLICK_EVENT;
4837       emacs_event->code = EV_BUTTON (theEvent);
4838       emacs_event->modifiers = EV_MODIFIERS (theEvent)
4839                              | EV_UDMODIFIERS (theEvent);
4840     }
4841   XSETINT (emacs_event->x, lrint (p.x));
4842   XSETINT (emacs_event->y, lrint (p.y));
4843   EV_TRAILER (theEvent);
4847 - (void)rightMouseDown: (NSEvent *)theEvent
4849   NSTRACE (rightMouseDown);
4850   [self mouseDown: theEvent];
4854 - (void)otherMouseDown: (NSEvent *)theEvent
4856   NSTRACE (otherMouseDown);
4857   [self mouseDown: theEvent];
4861 - (void)mouseUp: (NSEvent *)theEvent
4863   NSTRACE (mouseUp);
4864   [self mouseDown: theEvent];
4868 - (void)rightMouseUp: (NSEvent *)theEvent
4870   NSTRACE (rightMouseUp);
4871   [self mouseDown: theEvent];
4875 - (void)otherMouseUp: (NSEvent *)theEvent
4877   NSTRACE (otherMouseUp);
4878   [self mouseDown: theEvent];
4882 - (void) scrollWheel: (NSEvent *)theEvent
4884   NSTRACE (scrollWheel);
4885   [self mouseDown: theEvent];
4889 /* Tell emacs the mouse has moved. */
4890 - (void)mouseMoved: (NSEvent *)e
4892   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4893   Lisp_Object frame;
4895 //  NSTRACE (mouseMoved);
4897   last_mouse_movement_time = EV_TIMESTAMP (e);
4898   last_mouse_motion_position
4899     = [self convertPoint: [e locationInWindow] fromView: nil];
4901   /* update any mouse face */
4902   if (hlinfo->mouse_face_hidden)
4903     {
4904       hlinfo->mouse_face_hidden = 0;
4905       clear_mouse_face (hlinfo);
4906     }
4908   /* tooltip handling */
4909   previous_help_echo_string = help_echo_string;
4910   help_echo_string = Qnil;
4912   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
4913                             last_mouse_motion_position.y))
4914     help_echo_string = previous_help_echo_string;
4916   XSETFRAME (frame, emacsframe);
4917   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
4918     {
4919       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
4920          (note_mouse_highlight), which is called through the
4921          note_mouse_movement () call above */
4922       gen_help_event (help_echo_string, frame, help_echo_window,
4923                       help_echo_object, help_echo_pos);
4924     }
4925   else
4926     {
4927       help_echo_string = Qnil;
4928       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
4929     }
4931   if (emacsframe->mouse_moved && send_appdefined)
4932     ns_send_appdefined (-1);
4936 - (void)mouseDragged: (NSEvent *)e
4938   NSTRACE (mouseDragged);
4939   [self mouseMoved: e];
4943 - (void)rightMouseDragged: (NSEvent *)e
4945   NSTRACE (rightMouseDragged);
4946   [self mouseMoved: e];
4950 - (void)otherMouseDragged: (NSEvent *)e
4952   NSTRACE (otherMouseDragged);
4953   [self mouseMoved: e];
4957 - (BOOL)windowShouldClose: (id)sender
4959   NSEvent *e =[[self window] currentEvent];
4961   NSTRACE (windowShouldClose);
4962   windowClosing = YES;
4963   if (!emacs_event)
4964     return NO;
4965   emacs_event->kind = DELETE_WINDOW_EVENT;
4966   emacs_event->modifiers = 0;
4967   emacs_event->code = 0;
4968   EV_TRAILER (e);
4969   /* Don't close this window, let this be done from lisp code.  */
4970   return NO;
4974 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
4975 /* normalize frame to gridded text size */
4977   NSTRACE (windowWillResize);
4978 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
4980   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
4981 #ifdef NS_IMPL_GNUSTEP
4982                                         frameSize.width + 3);
4983 #else
4984                                         frameSize.width);
4985 #endif
4986   if (cols < MINWIDTH)
4987     cols = MINWIDTH;
4989   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, frameSize.height
4990 #ifdef NS_IMPL_GNUSTEP
4991       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + 3
4992         - FRAME_TOOLBAR_HEIGHT (emacsframe));
4993 #else
4994       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
4995         - FRAME_TOOLBAR_HEIGHT (emacsframe));
4996 #endif
4997   if (rows < MINHEIGHT)
4998     rows = MINHEIGHT;
4999 #ifdef NS_IMPL_COCOA
5000   {
5001     /* this sets window title to have size in it; the wm does this under GS */
5002     NSRect r = [[self window] frame];
5003     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5004       {
5005         if (old_title != 0)
5006           {
5007             xfree (old_title);
5008             old_title = 0;
5009           }
5010       }
5011     else
5012       {
5013         char *size_title;
5014         NSWindow *window = [self window];
5015         if (old_title == 0)
5016           {
5017             const char *t = [[[self window] title] UTF8String];
5018             char *pos = strstr (t, "  â€”  ");
5019             if (pos)
5020               *pos = '\0';
5021             old_title = (char *) xmalloc (strlen (t) + 1);
5022             strcpy (old_title, t);
5023           }
5024         size_title = xmalloc (strlen (old_title) + 40);
5025         sprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5026         [window setTitle: [NSString stringWithUTF8String: size_title]];
5027         [window display];
5028         xfree (size_title);
5029       }
5030   }
5031 #endif /* NS_IMPL_COCOA */
5032 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5034   return frameSize;
5038 - (void)windowDidResize: (NSNotification *)notification
5040   NSWindow *theWindow = [notification object];
5042 #ifdef NS_IMPL_GNUSTEP
5043    /* in GNUstep, at least currently, it's possible to get a didResize
5044       without getting a willResize.. therefore we need to act as if we got
5045       the willResize now */
5046   NSSize sz = [theWindow frame].size;
5047   sz = [self windowWillResize: theWindow toSize: sz];
5048 #endif /* NS_IMPL_GNUSTEP */
5050   NSTRACE (windowDidResize);
5051 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5053 #ifdef NS_IMPL_COCOA
5054   if (old_title != 0)
5055     {
5056       xfree (old_title);
5057       old_title = 0;
5058     }
5059 #endif /* NS_IMPL_COCOA */
5061   /* Avoid loop under GNUstep due to call at beginning of this function.
5062      (x_set_window_size causes a resize which causes
5063      a "windowDidResize" which calls x_set_window_size).  */
5064 #ifndef NS_IMPL_GNUSTEP
5065   if (cols > 0 && rows > 0)
5066     x_set_window_size (emacsframe, 0, cols, rows);
5067 #endif
5069   ns_send_appdefined (-1);
5073 - (void)windowDidBecomeKey: (NSNotification *)notification
5074 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5076   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5077   struct frame *old_focus = dpyinfo->x_focus_frame;
5079   NSTRACE (windowDidBecomeKey);
5081   if (emacsframe != old_focus)
5082     dpyinfo->x_focus_frame = emacsframe;
5084   ns_frame_rehighlight (emacsframe);
5086   if (emacs_event)
5087     {
5088       emacs_event->kind = FOCUS_IN_EVENT;
5089       EV_TRAILER ((id)nil);
5090     }
5094 - (void)windowDidResignKey: (NSNotification *)notification
5095 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5097   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5098   NSTRACE (windowDidResignKey);
5100   if (dpyinfo->x_focus_frame == emacsframe)
5101     dpyinfo->x_focus_frame = 0;
5103   ns_frame_rehighlight (emacsframe);
5105   /* FIXME: for some reason needed on second and subsequent clicks away
5106             from sole-frame Emacs to get hollow box to show */
5107   if (!windowClosing && [[self window] isVisible] == YES)
5108     {
5109       x_update_cursor (emacsframe, 1);
5110       x_set_frame_alpha (emacsframe);
5111     }
5113   if (emacs_event)
5114     {
5115       [self deleteWorkingText];
5116       emacs_event->kind = FOCUS_IN_EVENT;
5117       EV_TRAILER ((id)nil);
5118     }
5122 - (void)windowWillMiniaturize: sender
5124   NSTRACE (windowWillMiniaturize);
5128 - (BOOL)isFlipped
5130   return YES;
5134 - (BOOL)isOpaque
5136   return NO;
5140 - initFrameFromEmacs: (struct frame *)f
5142   NSRect r, wr;
5143   Lisp_Object tem;
5144   NSWindow *win;
5145   NSButton *toggleButton;
5146   int vbextra = NS_SCROLL_BAR_WIDTH (f);
5147   NSSize sz;
5148   NSColor *col;
5149   NSString *name;
5151   NSTRACE (initFrameFromEmacs);
5153   windowClosing = NO;
5154   processingCompose = NO;
5155   scrollbarsNeedingUpdate = 0;
5157 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5159   ns_userRect = NSMakeRect (0, 0, 0, 0);
5160   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5161                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5162   [self initWithFrame: r];
5163   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5165   FRAME_NS_VIEW (f) = self;
5166   emacsframe = f;
5167   old_title = 0;
5169   win = [[EmacsWindow alloc]
5170             initWithContentRect: r
5171                       styleMask: (NSResizableWindowMask |
5172                                   NSMiniaturizableWindowMask |
5173                                   NSClosableWindowMask)
5174                         backing: NSBackingStoreBuffered
5175                           defer: YES];
5177   wr = [win frame];
5178   f->border_width = wr.size.width - r.size.width;
5179   FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5181   [win setAcceptsMouseMovedEvents: YES];
5182   [win setDelegate: self];
5183   [win useOptimizedDrawing: YES];
5185   sz.width = FRAME_COLUMN_WIDTH (f);
5186   sz.height = FRAME_LINE_HEIGHT (f);
5187   [win setResizeIncrements: sz];
5189   [[win contentView] addSubview: self];
5191   if (ns_drag_types)
5192     [self registerForDraggedTypes: ns_drag_types];
5194   tem = f->name;
5195   name = [NSString stringWithUTF8String:
5196                    NILP (tem) ? (unsigned char *)"Emacs" : SDATA (tem)];
5197   [win setTitle: name];
5199   /* toolbar support */
5200   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5201                          [NSString stringWithFormat: @"Emacs Frame %d",
5202                                    ns_window_num]];
5203   [win setToolbar: toolbar];
5204   [toolbar setVisible: NO];
5205 #ifdef NS_IMPL_COCOA
5206   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5207   [toggleButton setTarget: self];
5208   [toggleButton setAction: @selector (toggleToolbar: )];
5209 #endif
5210   FRAME_TOOLBAR_HEIGHT (f) = 0;
5212   tem = f->icon_name;
5213   if (!NILP (tem))
5214     [win setMiniwindowTitle:
5215            [NSString stringWithUTF8String: SDATA (tem)]];
5217   {
5218     NSScreen *screen = [win screen];
5220     if (screen != 0)
5221       [win setFrameTopLeftPoint: NSMakePoint
5222            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5223             IN_BOUND (-SCREENMAX,
5224                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5225   }
5227   [win makeFirstResponder: self];
5229   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5230                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5231   [win setBackgroundColor: col];
5232   if ([col alphaComponent] != 1.0)
5233     [win setOpaque: NO];
5235   [self allocateGState];
5237   ns_window_num++;
5238   return self;
5242 - (void)windowDidMove: sender
5244   NSWindow *win = [self window];
5245   NSRect r = [win frame];
5246   NSArray *screens = [NSScreen screens];
5247   NSScreen *screen = [screens objectAtIndex: 0];
5249   NSTRACE (windowDidMove);
5251   if (!emacsframe->output_data.ns)
5252     return;
5253   if (screen != nil)
5254     {
5255       emacsframe->left_pos = r.origin.x;
5256       emacsframe->top_pos =
5257         [screen frame].size.height - (r.origin.y + r.size.height);
5258     }
5262 /* Called AFTER method below, but before our windowWillResize call there leads
5263    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5264    location so set_window_size moves the frame. */
5265 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5267   emacsframe->output_data.ns->zooming = 1;
5268   return YES;
5272 /* Override to do something slightly nonstandard, but nice.  First click on
5273    zoom button will zoom vertically.  Second will zoom completely.  Third
5274    returns to original. */
5275 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5276                         defaultFrame:(NSRect)defaultFrame
5278   NSRect result = [sender frame];
5280   NSTRACE (windowWillUseStandardFrame);
5282   if (abs (defaultFrame.size.height - result.size.height)
5283       > FRAME_LINE_HEIGHT (emacsframe))
5284     {
5285       /* first click */
5286       ns_userRect = result;
5287       result.size.height = defaultFrame.size.height;
5288       result.origin.y = defaultFrame.origin.y;
5289     }
5290   else
5291     {
5292       if (abs (defaultFrame.size.width - result.size.width)
5293           > FRAME_COLUMN_WIDTH (emacsframe))
5294         result = defaultFrame;  /* second click */
5295       else
5296         {
5297           /* restore */
5298           result = ns_userRect.size.height ? ns_userRect : result;
5299           ns_userRect = NSMakeRect (0, 0, 0, 0);
5300         }
5301     }
5303   [self windowWillResize: sender toSize: result.size];
5304   return result;
5308 - (void)windowDidDeminiaturize: sender
5310   NSTRACE (windowDidDeminiaturize);
5311   if (!emacsframe->output_data.ns)
5312     return;
5313   emacsframe->async_iconified = 0;
5314   emacsframe->async_visible   = 1;
5315   windows_or_buffers_changed++;
5317   if (emacs_event)
5318     {
5319       emacs_event->kind = ICONIFY_EVENT;
5320       EV_TRAILER ((id)nil);
5321     }
5325 - (void)windowDidExpose: sender
5327   NSTRACE (windowDidExpose);
5328   if (!emacsframe->output_data.ns)
5329     return;
5330   emacsframe->async_visible = 1;
5331   SET_FRAME_GARBAGED (emacsframe);
5333   if (send_appdefined)
5334     ns_send_appdefined (-1);
5338 - (void)windowDidMiniaturize: sender
5340   NSTRACE (windowDidMiniaturize);
5341   if (!emacsframe->output_data.ns)
5342     return;
5344   emacsframe->async_iconified = 1;
5345   emacsframe->async_visible = 0;
5347   if (emacs_event)
5348     {
5349       emacs_event->kind = ICONIFY_EVENT;
5350       EV_TRAILER ((id)nil);
5351     }
5355 - (void)mouseEntered: (NSEvent *)theEvent
5357   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5358   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5359   NSTRACE (mouseEntered);
5361   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5365 - (void)mouseExited: (NSEvent *)theEvent
5367   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5368   NSRect r;
5369   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
5371   NSTRACE (mouseExited);
5373   if (!hlinfo)
5374     return;
5376   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5378   if (emacsframe == hlinfo->mouse_face_mouse_frame)
5379     {
5380       clear_mouse_face (hlinfo);
5381       hlinfo->mouse_face_mouse_frame = 0;
5382     }
5386 - menuDown: sender
5388   NSTRACE (menuDown);
5389   if (context_menu_value == -1)
5390     context_menu_value = [sender tag];
5391   else
5392     find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
5393                                   emacsframe->menu_bar_vector,
5394                                   (void *)[sender tag]);
5395   ns_send_appdefined (-1);
5396   return self;
5400 - (EmacsToolbar *)toolbar
5402   return toolbar;
5406 /* this gets called on toolbar button click */
5407 - toolbarClicked: (id)item
5409   NSEvent *theEvent;
5410   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
5412   NSTRACE (toolbarClicked);
5414   if (!emacs_event)
5415     return self;
5417   /* send first event (for some reason two needed) */
5418   theEvent = [[self window] currentEvent];
5419   emacs_event->kind = TOOL_BAR_EVENT;
5420   XSETFRAME (emacs_event->arg, emacsframe);
5421   EV_TRAILER (theEvent);
5423   emacs_event->kind = TOOL_BAR_EVENT;
5424 /*   XSETINT (emacs_event->code, 0); */
5425   emacs_event->arg = AREF (emacsframe->tool_bar_items,
5426                           idx + TOOL_BAR_ITEM_KEY);
5427   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5428   EV_TRAILER (theEvent);
5429   return self;
5433 - toggleToolbar: (id)sender
5435   if (!emacs_event)
5436     return self;
5438   emacs_event->kind = NS_NONKEY_EVENT;
5439   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
5440   EV_TRAILER ((id)nil);
5441   return self;
5445 - (void)drawRect: (NSRect)rect
5447   int x = NSMinX (rect), y = NSMinY (rect);
5448   int width = NSWidth (rect), height = NSHeight (rect);
5450   NSTRACE (drawRect);
5452   if (!emacsframe || !emacsframe->output_data.ns || ns_in_resize)
5453     return;
5455   ns_clear_frame_area (emacsframe, x, y, width, height);
5456   expose_frame (emacsframe, x, y, width, height);
5458   /*
5459     drawRect: may be called (at least in OS X 10.5) for invisible
5460     views as well for some reason.  Thus, do not infer visibility
5461     here.
5463     emacsframe->async_visible = 1;
5464     emacsframe->async_iconified = 0;
5465   */
5469 /* NSDraggingDestination protocol methods.  Actually this is not really a
5470    protocol, but a category of Object.  O well...  */
5472 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
5474   NSTRACE (draggingEntered);
5475   return NSDragOperationGeneric;
5479 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
5481   return YES;
5485 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
5487   id pb;
5488   int x, y;
5489   NSString *type;
5490   NSEvent *theEvent = [[self window] currentEvent];
5491   NSPoint position;
5493   NSTRACE (performDragOperation);
5495   if (!emacs_event)
5496     return NO;
5498   position = [self convertPoint: [sender draggingLocation] fromView: nil];
5499   x = lrint (position.x);  y = lrint (position.y);
5501   pb = [sender draggingPasteboard];
5502   type = [pb availableTypeFromArray: ns_drag_types];
5503   if (type == 0)
5504     {
5505       return NO;
5506     }
5507   else if ([type isEqualToString: NSFilenamesPboardType])
5508     {
5509       NSArray *files;
5510       NSEnumerator *fenum;
5511       NSString *file;
5513       if (!(files = [pb propertyListForType: type]))
5514         return NO;
5516       fenum = [files objectEnumerator];
5517       while ( (file = [fenum nextObject]) )
5518         {
5519           emacs_event->kind = NS_NONKEY_EVENT;
5520           emacs_event->code = KEY_NS_DRAG_FILE;
5521           XSETINT (emacs_event->x, x);
5522           XSETINT (emacs_event->y, y);
5523           ns_input_file = append2 (ns_input_file,
5524                                    build_string ([file UTF8String]));
5525           emacs_event->modifiers = EV_MODIFIERS (theEvent);
5526           EV_TRAILER (theEvent);
5527         }
5528       return YES;
5529     }
5530   else if ([type isEqualToString: NSURLPboardType])
5531     {
5532       NSString *file;
5533       NSURL *fileURL;
5535       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
5536           [fileURL isFileURL] == NO)
5537         return NO;
5539       file = [fileURL path];
5540       emacs_event->kind = NS_NONKEY_EVENT;
5541       emacs_event->code = KEY_NS_DRAG_FILE;
5542       XSETINT (emacs_event->x, x);
5543       XSETINT (emacs_event->y, y);
5544       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
5545       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5546       EV_TRAILER (theEvent);
5547       return YES;
5548     }
5549   else if ([type isEqualToString: NSStringPboardType]
5550            || [type isEqualToString: NSTabularTextPboardType])
5551     {
5552       NSString *data;
5554       if (! (data = [pb stringForType: type]))
5555         return NO;
5557       emacs_event->kind = NS_NONKEY_EVENT;
5558       emacs_event->code = KEY_NS_DRAG_TEXT;
5559       XSETINT (emacs_event->x, x);
5560       XSETINT (emacs_event->y, y);
5561       ns_input_text = build_string ([data UTF8String]);
5562       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5563       EV_TRAILER (theEvent);
5564       return YES;
5565     }
5566   else if ([type isEqualToString: NSColorPboardType])
5567     {
5568       NSColor *c = [NSColor colorFromPasteboard: pb];
5569       emacs_event->kind = NS_NONKEY_EVENT;
5570       emacs_event->code = KEY_NS_DRAG_COLOR;
5571       XSETINT (emacs_event->x, x);
5572       XSETINT (emacs_event->y, y);
5573       ns_input_color = ns_color_to_lisp (c);
5574       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5575       EV_TRAILER (theEvent);
5576       return YES;
5577     }
5578   else if ([type isEqualToString: NSFontPboardType])
5579     {
5580       /* impl based on GNUstep NSTextView.m */
5581       NSData *data = [pb dataForType: NSFontPboardType];
5582       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
5583       NSFont *font = [dict objectForKey: NSFontAttributeName];
5584       char fontSize[10];
5586       if (font == nil)
5587         return NO;
5589       emacs_event->kind = NS_NONKEY_EVENT;
5590       emacs_event->code = KEY_NS_CHANGE_FONT;
5591       XSETINT (emacs_event->x, x);
5592       XSETINT (emacs_event->y, y);
5593       ns_input_font = build_string ([[font fontName] UTF8String]);
5594       snprintf (fontSize, 10, "%f", [font pointSize]);
5595       ns_input_fontsize = build_string (fontSize);
5596       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5597       EV_TRAILER (theEvent);
5598       return YES;
5599     }
5600   else
5601     {
5602       error ("Invalid data type in dragging pasteboard.");
5603       return NO;
5604     }
5608 - validRequestorForSendType: (NSString *)typeSent
5609                  returnType: (NSString *)typeReturned
5611   NSTRACE (validRequestorForSendType);
5612   if ([ns_send_types indexOfObjectIdenticalTo: typeSent] != NSNotFound &&
5613       [ns_return_types indexOfObjectIdenticalTo: typeSent] != NSNotFound)
5614     return self;
5616   return [super validRequestorForSendType: typeSent
5617                                returnType: typeReturned];
5621 /* The next two methods are part of NSServicesRequests informal protocol,
5622    supposedly called when a services menu item is chosen from this app.
5623    But this should not happen because we override the services menu with our
5624    own entries which call ns-perform-service.
5625    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
5626    So let's at least stub them out until further investigation can be done. */
5628 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
5630   /* we could call ns_string_from_pasteboard(pboard) here but then it should
5631      be written into the buffer in place of the existing selection..
5632      ordinary service calls go through functions defined in ns-win.el */
5633   return NO;
5636 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
5638   /* supposed to write for as many of types as we are able */
5639   return NO;
5643 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
5644    (gives a miniaturized version of the window); currently we use the latter for
5645    frames whose active buffer doesn't correspond to any file
5646    (e.g., '*scratch*') */
5647 - setMiniwindowImage: (BOOL) setMini
5649   id image = [[self window] miniwindowImage];
5650   NSTRACE (setMiniwindowImage);
5652   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
5653      about "AppleDockIconEnabled" notwithstanding, however the set message
5654      below has its effect nonetheless. */
5655   if (image != emacsframe->output_data.ns->miniimage)
5656     {
5657       if (image && [image isKindOfClass: [EmacsImage class]])
5658         [image release];
5659       [[self window] setMiniwindowImage:
5660                        setMini ? emacsframe->output_data.ns->miniimage : nil];
5661     }
5663   return self;
5667 - (void) setRows: (int) r andColumns: (int) c
5669   rows = r;
5670   cols = c;
5673 @end  /* EmacsView */
5677 /* ==========================================================================
5679     EmacsWindow implementation
5681    ========================================================================== */
5683 @implementation EmacsWindow
5685 /* If we have multiple monitors, one above the other, we don't want to
5686    restrict the height to just one monitor.  So we override this.  */
5687 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
5689   /* When making the frame visible for the first time, we want to
5690      constrain.  Other times not.  */
5691   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
5692   if (f->output_data.ns->dont_constrain)
5693     return frameRect;
5695   f->output_data.ns->dont_constrain = 1;
5696   return [super constrainFrameRect:frameRect toScreen:screen];
5700 /* called only on resize clicks by special case in EmacsApp-sendEvent */
5701 - (void)mouseDown: (NSEvent *)theEvent
5703   if (ns_in_resize)
5704     {
5705       NSSize size = [[theEvent window] frame].size;
5706       grabOffset = [theEvent locationInWindow];
5707       grabOffset.x = size.width - grabOffset.x;
5708     }
5709   else
5710     [super mouseDown: theEvent];
5714 /* stop resizing */
5715 - (void)mouseUp: (NSEvent *)theEvent
5717   if (ns_in_resize)
5718     {
5719       struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
5720       ns_in_resize = NO;
5721       ns_set_name_as_filename (f);
5722       [self display];
5723       ns_send_appdefined (-1);
5724     }
5725   else
5726     [super mouseUp: theEvent];
5730 /* send resize events */
5731 - (void)mouseDragged: (NSEvent *)theEvent
5733   if (ns_in_resize)
5734     {
5735       NSPoint p = [theEvent locationInWindow];
5736       NSSize size, vettedSize, origSize = [self frame].size;
5738       size.width = p.x + grabOffset.x;
5739       size.height = origSize.height - p.y + grabOffset.y;
5741       if (size.width == origSize.width && size.height == origSize.height)
5742         return;
5744       vettedSize = [[self delegate] windowWillResize: self toSize: size];
5745       [[NSNotificationCenter defaultCenter]
5746             postNotificationName: NSWindowDidResizeNotification
5747                           object: self];
5748     }
5749   else
5750     [super mouseDragged: theEvent];
5753 @end /* EmacsWindow */
5756 /* ==========================================================================
5758     EmacsScroller implementation
5760    ========================================================================== */
5763 @implementation EmacsScroller
5765 /* for repeat button push */
5766 #define SCROLL_BAR_FIRST_DELAY 0.5
5767 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
5769 + (CGFloat) scrollerWidth
5771   /* TODO: if we want to allow variable widths, this is the place to do it,
5772            however neither GNUstep nor Cocoa support it very well */
5773   return [NSScroller scrollerWidth];
5777 - initFrame: (NSRect )r window: (Lisp_Object)nwin
5779   NSTRACE (EmacsScroller_initFrame);
5781   r.size.width = [EmacsScroller scrollerWidth];
5782   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
5783   [self setContinuous: YES];
5784   [self setEnabled: YES];
5786   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
5787      locked against the top and bottom edges, and right edge on OS X, where
5788      scrollers are on right. */
5789 #ifdef NS_IMPL_GNUSTEP
5790   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
5791 #else
5792   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
5793 #endif
5795   win = nwin;
5796   condemned = NO;
5797   pixel_height = NSHeight (r);
5798   if (pixel_height == 0) pixel_height = 1;
5799   min_portion = 20 / pixel_height;
5801   frame = XFRAME (XWINDOW (win)->frame);
5802   if (FRAME_LIVE_P (frame))
5803     {
5804       int i;
5805       EmacsView *view = FRAME_NS_VIEW (frame);
5806       NSView *sview = [[view window] contentView];
5807       NSArray *subs = [sview subviews];
5809       /* disable optimization stopping redraw of other scrollbars */
5810       view->scrollbarsNeedingUpdate = 0;
5811       for (i =[subs count]-1; i >= 0; i--)
5812         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
5813           view->scrollbarsNeedingUpdate++;
5814       [sview addSubview: self];
5815     }
5817 /*  [self setFrame: r]; */
5819   return self;
5823 - (void)setFrame: (NSRect)newRect
5825   NSTRACE (EmacsScroller_setFrame);
5826 /*  BLOCK_INPUT; */
5827   pixel_height = NSHeight (newRect);
5828   if (pixel_height == 0) pixel_height = 1;
5829   min_portion = 20 / pixel_height;
5830   [super setFrame: newRect];
5831   [self display];
5832 /*  UNBLOCK_INPUT; */
5836 - (void)dealloc
5838   NSTRACE (EmacsScroller_dealloc);
5839   if (!NILP (win))
5840     XWINDOW (win)->vertical_scroll_bar = Qnil;
5841   [super dealloc];
5845 - condemn
5847   NSTRACE (condemn);
5848   condemned =YES;
5849   return self;
5853 - reprieve
5855   NSTRACE (reprieve);
5856   condemned =NO;
5857   return self;
5861 - judge
5863   NSTRACE (judge);
5864   if (condemned)
5865     {
5866       EmacsView *view;
5867       BLOCK_INPUT;
5868       /* ensure other scrollbar updates after deletion */
5869       view = (EmacsView *)FRAME_NS_VIEW (frame);
5870       if (view != nil)
5871         view->scrollbarsNeedingUpdate++;
5872       [self removeFromSuperview];
5873       [self release];
5874       UNBLOCK_INPUT;
5875     }
5876   return self;
5880 - (void)resetCursorRects
5882   NSRect visible = [self visibleRect];
5883   NSTRACE (resetCursorRects);
5885   if (!NSIsEmptyRect (visible))
5886     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
5887   [[NSCursor arrowCursor] setOnMouseEntered: YES];
5891 - (int) checkSamePosition: (int) position portion: (int) portion
5892                     whole: (int) whole
5894   return em_position ==position && em_portion ==portion && em_whole ==whole
5895     && portion != whole; /* needed for resize empty buf */
5899 - setPosition: (int)position portion: (int)portion whole: (int)whole
5901   NSTRACE (setPosition);
5903   em_position = position;
5904   em_portion = portion;
5905   em_whole = whole;
5907   if (portion >= whole)
5908     [self setFloatValue: 0.0 knobProportion: 1.0];
5909   else
5910     {
5911       float pos, por;
5912       portion = max ((float)whole*min_portion/pixel_height, portion);
5913       pos = (float)position / (whole - portion);
5914       por = (float)portion/whole;
5915       [self setFloatValue: pos knobProportion: por];
5916     }
5917   return self;
5920 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
5921      drag events will go directly to the EmacsScroller.  Leaving in for now. */
5922 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
5923                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
5925   *part = last_hit_part;
5926   *window = win;
5927   XSETINT (*y, pixel_height);
5928   if ([self floatValue] > 0.999)
5929     XSETINT (*x, pixel_height);
5930   else
5931     XSETINT (*x, pixel_height * [self floatValue]);
5935 /* set up emacs_event */
5936 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
5938   if (!emacs_event)
5939     return;
5941   emacs_event->part = last_hit_part;
5942   emacs_event->code = 0;
5943   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
5944   emacs_event->frame_or_window = win;
5945   emacs_event->timestamp = EV_TIMESTAMP (e);
5946   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
5947   emacs_event->arg = Qnil;
5948   XSETINT (emacs_event->x, loc * pixel_height);
5949   XSETINT (emacs_event->y, pixel_height-20);
5951   n_emacs_events_pending++;
5952   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
5953   EVENT_INIT (*emacs_event);
5954   ns_send_appdefined (-1);
5958 /* called manually thru timer to implement repeated button action w/hold-down */
5959 - repeatScroll: (NSTimer *)scrollEntry
5961   NSEvent *e = [[self window] currentEvent];
5962   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
5963   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
5965   /* clear timer if need be */
5966   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
5967     {
5968         [scroll_repeat_entry invalidate];
5969         [scroll_repeat_entry release];
5970         scroll_repeat_entry = nil;
5972         if (inKnob)
5973           return self;
5975         scroll_repeat_entry
5976           = [[NSTimer scheduledTimerWithTimeInterval:
5977                         SCROLL_BAR_CONTINUOUS_DELAY
5978                                             target: self
5979                                           selector: @selector (repeatScroll:)
5980                                           userInfo: 0
5981                                            repeats: YES]
5982               retain];
5983     }
5985   [self sendScrollEventAtLoc: 0 fromEvent: e];
5986   return self;
5990 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
5991    mouseDragged events without going into a modal loop. */
5992 - (void)mouseDown: (NSEvent *)e
5994   NSRect sr, kr;
5995   /* hitPart is only updated AFTER event is passed on */
5996   NSScrollerPart part = [self testPart: [e locationInWindow]];
5997   double inc = 0.0, loc, kloc, pos;
5998   int edge = 0;
6000   NSTRACE (EmacsScroller_mouseDown);
6002   switch (part)
6003     {
6004     case NSScrollerDecrementPage:
6005         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
6006     case NSScrollerIncrementPage:
6007         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
6008     case NSScrollerDecrementLine:
6009       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
6010     case NSScrollerIncrementLine:
6011       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
6012     case NSScrollerKnob:
6013       last_hit_part = scroll_bar_handle; break;
6014     case NSScrollerKnobSlot:  /* GNUstep-only */
6015       last_hit_part = scroll_bar_move_ratio; break;
6016     default:  /* NSScrollerNoPart? */
6017       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
6018                (long) part);
6019       return;
6020     }
6022   if (inc != 0.0)
6023     {
6024       pos = 0;      /* ignored */
6026       /* set a timer to repeat, as we can't let superclass do this modally */
6027       scroll_repeat_entry
6028         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
6029                                             target: self
6030                                           selector: @selector (repeatScroll:)
6031                                           userInfo: 0
6032                                            repeats: YES]
6033             retain];
6034     }
6035   else
6036     {
6037       /* handle, or on GNUstep possibly slot */
6038       NSEvent *fake_event;
6040       /* compute float loc in slot and mouse offset on knob */
6041       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6042                       toView: nil];
6043       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6044       if (loc <= 0.0)
6045         {
6046           loc = 0.0;
6047           edge = -1;
6048         }
6049       else if (loc >= NSHeight (sr))
6050         {
6051           loc = NSHeight (sr);
6052           edge = 1;
6053         }
6055       if (edge)
6056         kloc = 0.5 * edge;
6057       else
6058         {
6059           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
6060                           toView: nil];
6061           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
6062         }
6063       last_mouse_offset = kloc;
6065       /* if knob, tell emacs a location offset by knob pos
6066          (to indicate top of handle) */
6067       if (part == NSScrollerKnob)
6068           pos = (loc - last_mouse_offset) / NSHeight (sr);
6069       else
6070         /* else this is a slot click on GNUstep: go straight there */
6071         pos = loc / NSHeight (sr);
6073       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
6074       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
6075                                       location: [e locationInWindow]
6076                                  modifierFlags: [e modifierFlags]
6077                                      timestamp: [e timestamp]
6078                                   windowNumber: [e windowNumber]
6079                                        context: [e context]
6080                                    eventNumber: [e eventNumber]
6081                                     clickCount: [e clickCount]
6082                                       pressure: [e pressure]];
6083       [super mouseUp: fake_event];
6084     }
6086   if (part != NSScrollerKnob)
6087     [self sendScrollEventAtLoc: pos fromEvent: e];
6091 /* Called as we manually track scroller drags, rather than superclass. */
6092 - (void)mouseDragged: (NSEvent *)e
6094     NSRect sr;
6095     double loc, pos;
6096     int edge = 0;
6098     NSTRACE (EmacsScroller_mouseDragged);
6100       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6101                       toView: nil];
6102       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6104       if (loc <= 0.0)
6105         {
6106           loc = 0.0;
6107           edge = -1;
6108         }
6109       else if (loc >= NSHeight (sr) + last_mouse_offset)
6110         {
6111           loc = NSHeight (sr) + last_mouse_offset;
6112           edge = 1;
6113         }
6115       pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
6116       [self sendScrollEventAtLoc: pos fromEvent: e];
6120 - (void)mouseUp: (NSEvent *)e
6122   if (scroll_repeat_entry)
6123     {
6124       [scroll_repeat_entry invalidate];
6125       [scroll_repeat_entry release];
6126       scroll_repeat_entry = nil;
6127     }
6128   last_hit_part = 0;
6132 /* treat scrollwheel events in the bar as though they were in the main window */
6133 - (void) scrollWheel: (NSEvent *)theEvent
6135   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
6136   [view mouseDown: theEvent];
6139 @end  /* EmacsScroller */
6144 /* ==========================================================================
6146    Font-related functions; these used to be in nsfaces.m
6148    ========================================================================== */
6151 Lisp_Object
6152 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
6154   struct font *font = XFONT_OBJECT (font_object);
6156   if (fontset < 0)
6157     fontset = fontset_from_font (font_object);
6158   FRAME_FONTSET (f) = fontset;
6160   if (FRAME_FONT (f) == font)
6161     /* This font is already set in frame F.  There's nothing more to
6162        do.  */
6163     return font_object;
6165   FRAME_FONT (f) = font;
6167   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
6168   FRAME_COLUMN_WIDTH (f) = font->average_width;
6169   FRAME_SPACE_WIDTH (f) = font->space_width;
6170   FRAME_LINE_HEIGHT (f) = font->height;
6172   compute_fringe_widths (f, 1);
6174   /* Compute the scroll bar width in character columns.  */
6175   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6176     {
6177       int wid = FRAME_COLUMN_WIDTH (f);
6178       FRAME_CONFIG_SCROLL_BAR_COLS (f)
6179         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
6180     }
6181   else
6182     {
6183       int wid = FRAME_COLUMN_WIDTH (f);
6184       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6185     }
6187   /* Now make the frame display the given font.  */
6188   if (FRAME_NS_WINDOW (f) != 0)
6189         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6191   return font_object;
6195 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
6196 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
6197          in 1.43. */
6199 const char *
6200 ns_xlfd_to_fontname (const char *xlfd)
6201 /* --------------------------------------------------------------------------
6202     Convert an X font name (XLFD) to an NS font name.
6203     Only family is used.
6204     The string returned is temporarily allocated.
6205    -------------------------------------------------------------------------- */
6207   char *name = xmalloc (180);
6208   int i, len;
6209   const char *ret;
6211   if (!strncmp (xlfd, "--", 2))
6212     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
6213   else
6214     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
6216   /* stopgap for malformed XLFD input */
6217   if (strlen (name) == 0)
6218     strcpy (name, "Monaco");
6220   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
6221      also uppercase after '-' or ' ' */
6222   name[0] = toupper (name[0]);
6223   for (len =strlen (name), i =0; i<len; i++)
6224     {
6225       if (name[i] == '$')
6226         {
6227           name[i] = '-';
6228           if (i+1<len)
6229             name[i+1] = toupper (name[i+1]);
6230         }
6231       else if (name[i] == '_')
6232         {
6233           name[i] = ' ';
6234           if (i+1<len)
6235             name[i+1] = toupper (name[i+1]);
6236         }
6237     }
6238 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
6239   ret = [[NSString stringWithUTF8String: name] UTF8String];
6240   xfree (name);
6241   return ret;
6245 void
6246 syms_of_nsterm (void)
6248   NSTRACE (syms_of_nsterm);
6250   ns_antialias_threshold = 10.0;
6252   /* from 23+ we need to tell emacs what modifiers there are.. */
6253   DEFSYM (Qmodifier_value, "modifier-value");
6254   DEFSYM (Qalt, "alt");
6255   DEFSYM (Qhyper, "hyper");
6256   DEFSYM (Qmeta, "meta");
6257   DEFSYM (Qsuper, "super");
6258   DEFSYM (Qcontrol, "control");
6259   DEFSYM (Qnone, "none");
6260   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
6261   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
6262   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
6263   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
6264   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
6266   DEFVAR_LISP ("ns-input-file", ns_input_file,
6267               "The file specified in the last NS event.");
6268   ns_input_file =Qnil;
6270   DEFVAR_LISP ("ns-input-text", ns_input_text,
6271               "The data received in the last NS text drag event.");
6272   ns_input_text =Qnil;
6274   DEFVAR_LISP ("ns-working-text", ns_working_text,
6275               "String for visualizing working composition sequence.");
6276   ns_working_text =Qnil;
6278   DEFVAR_LISP ("ns-input-font", ns_input_font,
6279               "The font specified in the last NS event.");
6280   ns_input_font =Qnil;
6282   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
6283               "The fontsize specified in the last NS event.");
6284   ns_input_fontsize =Qnil;
6286   DEFVAR_LISP ("ns-input-line", ns_input_line,
6287                "The line specified in the last NS event.");
6288   ns_input_line =Qnil;
6290   DEFVAR_LISP ("ns-input-color", ns_input_color,
6291                "The color specified in the last NS event.");
6292   ns_input_color =Qnil;
6294   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
6295                "The service name specified in the last NS event.");
6296   ns_input_spi_name =Qnil;
6298   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
6299                "The service argument specified in the last NS event.");
6300   ns_input_spi_arg =Qnil;
6302   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
6303                "This variable describes the behavior of the alternate or option key.\n\
6304 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6305 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6306 at all, allowing it to be used at a lower level for accented character entry.");
6307   ns_alternate_modifier = Qmeta;
6309   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
6310                "This variable describes the behavior of the right alternate or option key.\n\
6311 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6312 Set to left means be the same key as `ns-alternate-modifier'.\n\
6313 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6314 at all, allowing it to be used at a lower level for accented character entry.");
6315   ns_right_alternate_modifier = Qleft;
6317   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
6318                "This variable describes the behavior of the command key.\n\
6319 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6320   ns_command_modifier = Qsuper;
6322   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
6323                "This variable describes the behavior of the right command key.\n\
6324 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6325 Set to left means be the same key as `ns-command-modifier'.\n\
6326 Set to none means that the command / option key is not interpreted by Emacs\n\
6327 at all, allowing it to be used at a lower level for accented character entry.");
6328   ns_right_command_modifier = Qleft;
6330   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
6331                "This variable describes the behavior of the control key.\n\
6332 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6333   ns_control_modifier = Qcontrol;
6335   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
6336                "This variable describes the behavior of the right control key.\n\
6337 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6338 Set to left means be the same key as `ns-control-modifier'.\n\
6339 Set to none means that the control / option key is not interpreted by Emacs\n\
6340 at all, allowing it to be used at a lower level for accented character entry.");
6341   ns_right_control_modifier = Qleft;
6343   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
6344                "This variable describes the behavior of the function key (on laptops).\n\
6345 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6346 Set to none means that the function key is not interpreted by Emacs at all,\n\
6347 allowing it to be used at a lower level for accented character entry.");
6348   ns_function_modifier = Qnone;
6350   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
6351                "Non-nil (the default) means to render text antialiased. Only has an effect on OS X Panther and above.");
6352   ns_antialias_text = Qt;
6354   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
6355                "Whether to confirm application quit using dialog.");
6356   ns_confirm_quit = Qnil;
6358   staticpro (&ns_display_name_list);
6359   ns_display_name_list = Qnil;
6361   staticpro (&last_mouse_motion_frame);
6362   last_mouse_motion_frame = Qnil;
6364   /* TODO: move to common code */
6365   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
6366                doc: /* If not nil, Emacs uses toolkit scroll bars.  */);
6367 #ifdef USE_TOOLKIT_SCROLL_BARS
6368   Vx_toolkit_scroll_bars = Qt;
6369 #else
6370   Vx_toolkit_scroll_bars = Qnil;
6371 #endif
6373   /* these are unsupported but we need the declarations to avoid whining
6374      messages from cus-start.el */
6375   DEFVAR_BOOL ("x-use-underline-position-properties",
6376                x_use_underline_position_properties,
6377      doc: /* NOT SUPPORTED UNDER NS.
6378 *Non-nil means make use of UNDERLINE_POSITION font properties.
6379 A value of nil means ignore them.  If you encounter fonts with bogus
6380 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
6381 to 4.1, set this to nil.
6383 NOTE: Not supported on Mac yet.  */);
6384   x_use_underline_position_properties = 0;
6386   DEFVAR_BOOL ("x-underline-at-descent-line",
6387                x_underline_at_descent_line,
6388      doc: /* NOT SUPPORTED UNDER NS.
6389 *Non-nil means to draw the underline at the same place as the descent line.
6390 A value of nil means to draw the underline according to the value of the
6391 variable `x-use-underline-position-properties', which is usually at the
6392 baseline level.  The default value is nil.  */);
6393   x_underline_at_descent_line = 0;
6395   /* Tell emacs about this window system. */
6396   Fprovide (intern ("ns"), Qnil);