merge trunk
[emacs.git] / src / nsterm.m
blob2eb84607562184c5fbb91712ec8727b30daf8f42
1 /* NeXT/Open/GNUstep / MacOSX communication module.
2    Copyright (C) 1989, 1993, 1994, 2005, 2006, 2008, 2009, 2010
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 /* Lisp communications */
139 Lisp_Object ns_input_file, ns_input_font, ns_input_fontsize, ns_input_line;
140 Lisp_Object ns_input_color, ns_input_text, ns_working_text;
141 Lisp_Object ns_input_spi_name, ns_input_spi_arg;
142 Lisp_Object Vx_toolkit_scroll_bars;
143 static Lisp_Object Qmodifier_value;
144 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper, Qnone;
145 extern Lisp_Object Qcursor_color, Qcursor_type, Qns;
147 /* Specifies which emacs modifier should be generated when NS receives
148    the Alternate modifer.  May be Qnone or any of the modifier lisp symbols. */
149 Lisp_Object ns_alternate_modifier;
151 /* Specifies which emacs modifier should be generated when NS receives
152    the Command modifer.  May be any of the modifier lisp symbols. */
153 Lisp_Object ns_command_modifier;
155 /* Specifies which emacs modifier should be generated when NS receives
156    the Control modifer.  May be any of the modifier lisp symbols. */
157 Lisp_Object ns_control_modifier;
159 /* Specifies which emacs modifier should be generated when NS receives
160    the Function modifer (laptops).  May be any of the modifier lisp symbols. */
161 Lisp_Object ns_function_modifier;
163 /* Control via default 'GSFontAntiAlias' on OS X and GNUstep. */
164 Lisp_Object ns_antialias_text;
166 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
167    the maximum font size to NOT antialias.  On GNUstep there is currently
168    no way to control this behavior. */
169 float ns_antialias_threshold;
171 /* Used to pick up AppleHighlightColor on OS X */
172 NSString *ns_selection_color;
174 /* Confirm on exit. */
175 Lisp_Object ns_confirm_quit;
177 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
178 NSString *ns_app_name = @"Emacs";  /* default changed later */
180 /* Display variables */
181 struct ns_display_info *x_display_list; /* Chain of existing displays */
182 Lisp_Object ns_display_name_list;
183 long context_menu_value = 0;
185 /* display update */
186 NSPoint last_mouse_motion_position;
187 static NSRect last_mouse_glyph;
188 static unsigned long last_mouse_movement_time = 0;
189 static Lisp_Object last_mouse_motion_frame;
190 static EmacsScroller *last_mouse_scroll_bar = nil;
191 static struct frame *ns_updating_frame;
192 static NSView *focus_view = NULL;
193 static int ns_window_num =0;
194 static NSRect uRect;
195 static BOOL gsaved = NO;
196 BOOL ns_in_resize = NO;
197 static BOOL ns_fake_keydown = NO;
198 int ns_tmp_flags; /* FIXME */
199 struct nsfont_info *ns_tmp_font; /* FIXME */
200 /*static int debug_lock = 0; */
202 /* event loop */
203 static BOOL send_appdefined = YES;
204 static NSEvent *last_appdefined_event = 0;
205 static NSTimer *timed_entry = 0;
206 static NSTimer *fd_entry = nil;
207 static NSTimer *scroll_repeat_entry = nil;
208 static fd_set select_readfds, t_readfds;
209 static struct timeval select_timeout;
210 static int select_nfds;
211 static NSAutoreleasePool *outerpool;
212 static struct input_event *emacs_event = NULL;
213 static struct input_event *q_event_ptr = NULL;
214 static int n_emacs_events_pending = 0;
215 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
216   *ns_pending_service_args;
217 static BOOL inNsSelect = 0;
219 /* Convert modifiers in a NeXTSTEP event to emacs style modifiers.  */
220 #define NS_FUNCTION_KEY_MASK 0x800000
221 #define EV_MODIFIERS(e)                               \
222     ((([e modifierFlags] & NSHelpKeyMask) ?           \
223            hyper_modifier : 0)                        \
224      | (([e modifierFlags] & NSAlternateKeyMask) ?    \
225            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
226      | (([e modifierFlags] & NSShiftKeyMask) ?        \
227            shift_modifier : 0)                        \
228      | (([e modifierFlags] & NSControlKeyMask) ?      \
229            parse_solitary_modifier (ns_control_modifier) : 0)     \
230      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
231            parse_solitary_modifier (ns_function_modifier) : 0)    \
232      | (([e modifierFlags] & NSCommandKeyMask) ?      \
233            parse_solitary_modifier (ns_command_modifier):0))
235 #define EV_UDMODIFIERS(e)                                      \
236     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
237      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
238      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
239      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
240      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
241      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
242      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
243      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
244      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
246 #define EV_BUTTON(e)                                                         \
247     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
248       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
249      [e buttonNumber] - 1)
251 /* Convert the time field to a timestamp in milliseconds. */
252 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
254 /* This is a piece of code which is common to all the event handling
255    methods.  Maybe it should even be a function.  */
256 #define EV_TRAILER(e)                                         \
257   {                                                           \
258   XSETFRAME (emacs_event->frame_or_window, emacsframe);       \
259   if (e) emacs_event->timestamp = EV_TIMESTAMP (e);           \
260   n_emacs_events_pending++;                                   \
261   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);     \
262   EVENT_INIT (*emacs_event);                                  \
263   ns_send_appdefined (-1);                                    \
264   }
266 void x_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
268 /* TODO: get rid of need for these forward declarations */
269 static void ns_condemn_scroll_bars (struct frame *f);
270 static void ns_judge_scroll_bars (struct frame *f);
271 void x_set_frame_alpha (struct frame *f);
273 /* unused variables needed for compatibility reasons */
274 int x_use_underline_position_properties, x_underline_at_descent_line;
275 /* FIXME: figure out what to do with underline_minimum_offset. */
278 /* ==========================================================================
280     Utilities
282    ========================================================================== */
285 static Lisp_Object
286 append2 (Lisp_Object list, Lisp_Object item)
287 /* --------------------------------------------------------------------------
288    Utility to append to a list
289    -------------------------------------------------------------------------- */
291   Lisp_Object array[2];
292   array[0] = list;
293   array[1] = Fcons (item, Qnil);
294   return Fnconc (2, &array[0]);
298 void
299 ns_init_paths (void)
300 /* --------------------------------------------------------------------------
301    Used to allow emacs to find its resources under Emacs.app
302    Called from emacs.c at startup.
303    -------------------------------------------------------------------------- */
305   NSBundle *bundle = [NSBundle mainBundle];
306   NSString *binDir = [bundle bundlePath], *resourceDir = [bundle resourcePath];
307   NSString *resourcePath, *resourcePaths;
308   NSRange range;
309   BOOL onWindows = NO; /* how do I determine this? */
310   NSString *pathSeparator = onWindows ? @";" : @":";
311   NSFileManager *fileManager = [NSFileManager defaultManager];
312   BOOL isDir;
313 /*NSLog (@"ns_init_paths: '%@'\n%@\n", [[NSBundle mainBundle] bundlePath], [[NSBundle mainBundle] resourcePath]); */
315   /* get bindir from base */
316   range = [resourceDir rangeOfString: @"Contents"];
317   if (range.location != NSNotFound)
318     {
319       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
320 #ifdef NS_IMPL_COCOA
321       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
322 #endif
323     }
325   /* the following based on Andrew Choi's init_mac_osx_environment () */
326   if (!getenv ("EMACSLOADPATH"))
327     {
328       NSArray *paths = [resourceDir stringsByAppendingPaths:
329                                   [NSArray arrayWithObjects:
330                                          @"site-lisp", @"lisp", @"leim", nil]];
331       NSEnumerator *pathEnum = [paths objectEnumerator];
332       resourcePaths = @"";
333       while (resourcePath = [pathEnum nextObject])
334         {
335           if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
336             if (isDir)
337               {
338                 if ([resourcePaths length] > 0)
339                   resourcePaths
340                     = [resourcePaths stringByAppendingString: pathSeparator];
341                 resourcePaths
342                   = [resourcePaths stringByAppendingString: resourcePath];
343               }
344         }
345       if ([resourcePaths length] > 0)
346         setenv ("EMACSLOADPATH", [resourcePaths UTF8String], 1);
347 /*NSLog (@"loadPath: '%@'\n", resourcePaths); */
348     }
350   if (!getenv ("EMACSPATH"))
351     {
352       NSArray *paths = [binDir stringsByAppendingPaths:
353                                   [NSArray arrayWithObjects: @"bin",
354                                                              @"lib-exec", nil]];
355       NSEnumerator *pathEnum = [paths objectEnumerator];
356       resourcePaths = @"";
357       while (resourcePath = [pathEnum nextObject])
358         {
359           if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
360             if (isDir)
361               {
362                 if ([resourcePaths length] > 0)
363                   resourcePaths
364                     = [resourcePaths stringByAppendingString: pathSeparator];
365                 resourcePaths
366                   = [resourcePaths stringByAppendingString: resourcePath];
367               }
368         }
369       if ([resourcePaths length] > 0)
370         setenv ("EMACSPATH", [resourcePaths UTF8String], 1);
371     }
373   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
374   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
375     {
376       if (isDir)
377         {
378           if (!getenv ("EMACSDATA"))
379             setenv ("EMACSDATA", [resourcePath UTF8String], 1);
380           if (!getenv ("EMACSDOC"))
381             setenv ("EMACSDOC", [resourcePath UTF8String], 1);
382         }
383     }
385   if (!getenv ("INFOPATH"))
386     {
387       resourcePath = [resourceDir stringByAppendingPathComponent: @"info"];
388       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
389         if (isDir)
390           setenv ("INFOPATH", [[resourcePath stringByAppendingString: @":"]
391                                              UTF8String], 1);
392       /* Note, extra colon needed to cause merge w/later user additions. */
393     }
397 static int
398 timeval_subtract (struct timeval *result, struct timeval x, struct timeval y)
399 /* --------------------------------------------------------------------------
400    Subtract the `struct timeval' values X and Y, storing the result in RESULT.
401    Return 1 if the difference is negative, otherwise 0.
402    -------------------------------------------------------------------------- */
404   /* Perform the carry for the later subtraction by updating y.
405      This is safer because on some systems
406      the tv_sec member is unsigned.  */
407   if (x.tv_usec < y.tv_usec)
408     {
409       int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
410       y.tv_usec -= 1000000 * nsec;
411       y.tv_sec += nsec;
412     }
413   if (x.tv_usec - y.tv_usec > 1000000)
414     {
415       int nsec = (y.tv_usec - x.tv_usec) / 1000000;
416       y.tv_usec += 1000000 * nsec;
417       y.tv_sec -= nsec;
418     }
420   /* Compute the time remaining to wait.  tv_usec is certainly positive.  */
421   result->tv_sec = x.tv_sec - y.tv_sec;
422   result->tv_usec = x.tv_usec - y.tv_usec;
424   /* Return indication of whether the result should be considered negative.  */
425   return x.tv_sec < y.tv_sec;
428 static void
429 ns_timeout (int usecs)
430 /* --------------------------------------------------------------------------
431      Blocking timer utility used by ns_ring_bell
432    -------------------------------------------------------------------------- */
434   struct timeval wakeup;
436   EMACS_GET_TIME (wakeup);
438   /* Compute time to wait until, propagating carry from usecs.  */
439   wakeup.tv_usec += usecs;
440   wakeup.tv_sec += (wakeup.tv_usec / 1000000);
441   wakeup.tv_usec %= 1000000;
443   /* Keep waiting until past the time wakeup.  */
444   while (1)
445     {
446       struct timeval timeout;
448       EMACS_GET_TIME (timeout);
450       /* In effect, timeout = wakeup - timeout.
451          Break if result would be negative.  */
452       if (timeval_subtract (&timeout, wakeup, timeout))
453         break;
455       /* Try to wait that long--but we might wake up sooner.  */
456       select (0, NULL, NULL, NULL, &timeout);
457     }
461 void
462 ns_release_object (void *obj)
463 /* --------------------------------------------------------------------------
464     Release an object (callable from C)
465    -------------------------------------------------------------------------- */
467     [(id)obj release];
471 void
472 ns_retain_object (void *obj)
473 /* --------------------------------------------------------------------------
474     Retain an object (callable from C)
475    -------------------------------------------------------------------------- */
477     [(id)obj retain];
481 void *
482 ns_alloc_autorelease_pool (void)
483 /* --------------------------------------------------------------------------
484      Allocate a pool for temporary objects (callable from C)
485    -------------------------------------------------------------------------- */
487   return [[NSAutoreleasePool alloc] init];
491 void
492 ns_release_autorelease_pool (void *pool)
493 /* --------------------------------------------------------------------------
494      Free a pool and temporary objects it refers to (callable from C)
495    -------------------------------------------------------------------------- */
497   ns_release_object (pool);
502 /* ==========================================================================
504     Focus (clipping) and screen update
506    ========================================================================== */
508 static NSRect
509 ns_resize_handle_rect (NSWindow *window)
511   NSRect r = [window frame];
512   r.origin.x = r.size.width - RESIZE_HANDLE_SIZE;
513   r.origin.y = 0;
514   r.size.width = r.size.height = RESIZE_HANDLE_SIZE;
515   return r;
519 static void
520 ns_update_begin (struct frame *f)
521 /* --------------------------------------------------------------------------
522    Prepare for a grouped sequence of drawing calls
523    external (RIF) call; whole frame, called before update_window_begin
524    -------------------------------------------------------------------------- */
526   NSView *view = FRAME_NS_VIEW (f);
527   NSTRACE (ns_update_begin);
529   ns_updating_frame = f;
530   [view lockFocus];
532 #ifdef NS_IMPL_GNUSTEP
533   uRect = NSMakeRect (0, 0, 0, 0);
534 #endif
538 static void
539 ns_update_window_begin (struct window *w)
540 /* --------------------------------------------------------------------------
541    Prepare for a grouped sequence of drawing calls
542    external (RIF) call; for one window, called after update_begin
543    -------------------------------------------------------------------------- */
545   struct frame *f = XFRAME (WINDOW_FRAME (w));
546   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
547   NSTRACE (ns_update_window_begin);
549   updated_window = w;
550   set_output_cursor (&w->cursor);
552   BLOCK_INPUT;
554   if (f == dpyinfo->mouse_face_mouse_frame)
555     {
556       /* Don't do highlighting for mouse motion during the update.  */
557       dpyinfo->mouse_face_defer = 1;
559         /* If the frame needs to be redrawn,
560            simply forget about any prior mouse highlighting.  */
561       if (FRAME_GARBAGED_P (f))
562         dpyinfo->mouse_face_window = Qnil;
564       /* (further code for mouse faces ifdef'd out in other terms elided) */
565     }
567   UNBLOCK_INPUT;
571 static void
572 ns_update_window_end (struct window *w, int cursor_on_p,
573                       int mouse_face_overwritten_p)
574 /* --------------------------------------------------------------------------
575    Finished a grouped sequence of drawing calls
576    external (RIF) call; for one window called before update_end
577    -------------------------------------------------------------------------- */
579   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (XFRAME (w->frame));
581   /* note: this fn is nearly identical in all terms */
582   if (!w->pseudo_window_p)
583     {
584       BLOCK_INPUT;
586       if (cursor_on_p)
587         display_and_set_cursor (w, 1,
588                                 output_cursor.hpos, output_cursor.vpos,
589                                 output_cursor.x, output_cursor.y);
591       if (draw_window_fringes (w, 1))
592         x_draw_vertical_border (w);
594       UNBLOCK_INPUT;
595     }
597   /* If a row with mouse-face was overwritten, arrange for
598      frame_up_to_date to redisplay the mouse highlight.  */
599   if (mouse_face_overwritten_p)
600     {
601       dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
602       dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
603       dpyinfo->mouse_face_window = Qnil;
604     }
606   updated_window = NULL;
607   NSTRACE (update_window_end);
611 static void
612 ns_update_end (struct frame *f)
613 /* --------------------------------------------------------------------------
614    Finished a grouped sequence of drawing calls
615    external (RIF) call; for whole frame, called after update_window_end
616    -------------------------------------------------------------------------- */
618   NSView *view = FRAME_NS_VIEW (f);
620 /*   if (f == FRAME_NS_DISPLAY_INFO (f)->mouse_face_mouse_frame) */
621     FRAME_NS_DISPLAY_INFO (f)->mouse_face_defer = 0;
623   BLOCK_INPUT;
625 #ifdef NS_IMPL_GNUSTEP
626   /* trigger flush only in the rectangle we tracked as being drawn */
627   [view unlockFocusNeedsFlush: NO];
628 /*fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", uRect.origin.x, uRect.origin.y, uRect.size.width, uRect.size.height); */
629   [view lockFocusInRect: uRect];
630 #endif
632   [view unlockFocus];
633   [[view window] flushWindow];
635   UNBLOCK_INPUT;
636   ns_updating_frame = NULL;
637   NSTRACE (ns_update_end);
641 static void
642 ns_flush (struct frame *f)
643 /* --------------------------------------------------------------------------
644    external (RIF) call
645    NS impl is no-op since currently we flush in ns_update_end and elsewhere
646    -------------------------------------------------------------------------- */
648     NSTRACE (ns_flush);
652 static void
653 ns_focus (struct frame *f, NSRect *r, int n)
654 /* --------------------------------------------------------------------------
655    Internal: Focus on given frame.  During small local updates this is used to
656      draw, however during large updates, ns_update_begin and ns_update_end are
657      called to wrap the whole thing, in which case these calls are stubbed out.
658      Except, on GNUstep, we accumulate the rectangle being drawn into, because
659      the back end won't do this automatically, and will just end up flushing
660      the entire window.
661    -------------------------------------------------------------------------- */
663 //  NSTRACE (ns_focus);
664 #ifdef NS_IMPL_GNUSTEP
665   NSRect u;
666     if (n == 2)
667       u = NSUnionRect (r[0], r[1]);
668     else if (r)
669       u = *r;
670 #endif
671 /* static int c =0;
672    fprintf (stderr, "focus: %d", c++);
673    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
674    fprintf (stderr, "\n"); */
676   if (f != ns_updating_frame)
677     {
678       NSView *view = FRAME_NS_VIEW (f);
679       if (view != focus_view)
680         {
681           if (focus_view != NULL)
682             {
683               [focus_view unlockFocus];
684               [[focus_view window] flushWindow];
685 /*debug_lock--; */
686             }
688           if (view)
689 #ifdef NS_IMPL_GNUSTEP
690             r ? [view lockFocusInRect: u] : [view lockFocus];
691 #else
692             [view lockFocus];
693 #endif
694           focus_view = view;
695 /*if (view) debug_lock++; */
696         }
697 #ifdef NS_IMPL_GNUSTEP
698       else
699         {
700           /* more than one rect being drawn into */
701           if (view && r)
702             {
703               [view unlockFocus]; /* add prev rect to redraw list */
704               [view lockFocusInRect: u]; /* focus for draw in new rect */
705             }
706         }
707 #endif
708     }
709 #ifdef NS_IMPL_GNUSTEP
710   else
711     {
712       /* in batch mode, but in GNUstep must still track rectangles explicitly */
713       uRect = (r ? NSUnionRect (uRect, u) : [FRAME_NS_VIEW (f) visibleRect]);
714     }
715 #endif
717   /* clipping */
718   if (r)
719     {
720       [[NSGraphicsContext currentContext] saveGraphicsState];
721       if (n == 2)
722         NSRectClipList (r, 2);
723       else
724         NSRectClip (*r);
725       gsaved = YES;
726     }
730 static void
731 ns_unfocus (struct frame *f)
732 /* --------------------------------------------------------------------------
733      Internal: Remove focus on given frame
734    -------------------------------------------------------------------------- */
736 //  NSTRACE (ns_unfocus);
738   if (gsaved)
739     {
740       [[NSGraphicsContext currentContext] restoreGraphicsState];
741       gsaved = NO;
742     }
744   if (f != ns_updating_frame)
745     {
746       if (focus_view != NULL)
747         {
748           [focus_view unlockFocus];
749           [[focus_view window] flushWindow];
750           focus_view = NULL;
751 /*debug_lock--; */
752         }
753     }
757 static void
758 ns_clip_to_row (struct window *w, struct glyph_row *row, int area, BOOL gc)
759 /* --------------------------------------------------------------------------
760      Internal (but parallels other terms): Focus drawing on given row
761    -------------------------------------------------------------------------- */
763   struct frame *f = XFRAME (WINDOW_FRAME (w));
764   NSRect clip_rect;
765   int window_x, window_y, window_width;
767   window_box (w, area, &window_x, &window_y, &window_width, 0);
769   clip_rect.origin.x = window_x - FRAME_INTERNAL_BORDER_WIDTH (f);
770   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
771   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
772   clip_rect.size.width = window_width + 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
773   clip_rect.size.height = row->visible_height;
775   /* allow a full-height row at the top when requested
776      (used to draw fringe all the way through internal border area) */
777   if (gc && clip_rect.origin.y < 5)
778     {
779       clip_rect.origin.y -= FRAME_INTERNAL_BORDER_WIDTH (f);
780       clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
781     }
783   /* likewise at bottom */
784   if (gc &&
785       FRAME_PIXEL_HEIGHT (f) - (clip_rect.origin.y + clip_rect.size.height) < 5)
786     clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
788   ns_focus (f, &clip_rect, 1);
792 static void
793 ns_ring_bell (struct frame *f)
794 /* --------------------------------------------------------------------------
795      "Beep" routine
796    -------------------------------------------------------------------------- */
798   NSTRACE (ns_ring_bell);
799   if (visible_bell)
800     {
801       NSAutoreleasePool *pool;
802       struct frame *frame = SELECTED_FRAME ();
803       NSView *view;
805       BLOCK_INPUT;
806       pool = [[NSAutoreleasePool alloc] init];
808       view = FRAME_NS_VIEW (frame);
809       if (view != nil)
810         {
811           NSRect r, surr;
812           NSPoint dim = NSMakePoint (128, 128);
814           r = [view bounds];
815           r.origin.x += (r.size.width - dim.x) / 2;
816           r.origin.y += (r.size.height - dim.y) / 2;
817           r.size.width = dim.x;
818           r.size.height = dim.y;
819           surr = NSInsetRect (r, -2, -2);
820           ns_focus (frame, &surr, 1);
821           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
822           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
823                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
824           NSRectFill (r);
825           [[view window] flushWindow];
826           ns_timeout (150000);
827           [[view window] restoreCachedImage];
828           [[view window] flushWindow];
829           ns_unfocus (frame);
830         }
831       [pool release];
832       UNBLOCK_INPUT;
833     }
834   else
835     {
836       NSBeep ();
837     }
841 static void
842 ns_reset_terminal_modes (struct terminal *terminal)
843 /*  Externally called as hook */
845   NSTRACE (ns_reset_terminal_modes);
849 static void
850 ns_set_terminal_modes (struct terminal *terminal)
851 /*  Externally called as hook */
853   NSTRACE (ns_set_terminal_modes);
858 /* ==========================================================================
860     Frame / window manager related functions
862    ========================================================================== */
865 static void
866 ns_raise_frame (struct frame *f)
867 /* --------------------------------------------------------------------------
868      Bring window to foreground and make it active
869    -------------------------------------------------------------------------- */
871   NSView *view = FRAME_NS_VIEW (f);
872   check_ns ();
873   BLOCK_INPUT;
874   FRAME_SAMPLE_VISIBILITY (f);
875   if (FRAME_VISIBLE_P (f))
876     {
877       [[view window] makeKeyAndOrderFront: NSApp];
878     }
879   UNBLOCK_INPUT;
883 static void
884 ns_lower_frame (struct frame *f)
885 /* --------------------------------------------------------------------------
886      Send window to back
887    -------------------------------------------------------------------------- */
889   NSView *view = FRAME_NS_VIEW (f);
890   check_ns ();
891   BLOCK_INPUT;
892   [[view window] orderBack: NSApp];
893   UNBLOCK_INPUT;
897 static void
898 ns_frame_raise_lower (struct frame *f, int raise)
899 /* --------------------------------------------------------------------------
900      External (hook)
901    -------------------------------------------------------------------------- */
903   NSTRACE (ns_frame_raise_lower);
905   if (raise)
906     ns_raise_frame (f);
907   else
908     ns_lower_frame (f);
912 static void
913 ns_frame_rehighlight (struct frame *frame)
914 /* --------------------------------------------------------------------------
915      External (hook): called on things like window switching within frame
916    -------------------------------------------------------------------------- */
918   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
919   struct frame *old_highlight = dpyinfo->x_highlight_frame;
921   NSTRACE (ns_frame_rehighlight);
922   if (dpyinfo->x_focus_frame)
923     {
924       dpyinfo->x_highlight_frame
925         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
926            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
927            : dpyinfo->x_focus_frame);
928       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
929         {
930           FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
931           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
932         }
933     }
934   else
935       dpyinfo->x_highlight_frame = 0;
937   if (dpyinfo->x_highlight_frame &&
938          dpyinfo->x_highlight_frame != old_highlight)
939     {
940       if (old_highlight)
941         {
942           x_update_cursor (old_highlight, 1);
943           x_set_frame_alpha (old_highlight);
944         }
945       if (dpyinfo->x_highlight_frame)
946         {
947           x_update_cursor (dpyinfo->x_highlight_frame, 1);
948           x_set_frame_alpha (dpyinfo->x_highlight_frame);
949         }
950     }
954 void
955 x_make_frame_visible (struct frame *f)
956 /* --------------------------------------------------------------------------
957      External: Show the window (X11 semantics)
958    -------------------------------------------------------------------------- */
960   NSTRACE (x_make_frame_visible);
961   /* XXX: at some points in past this was not needed, as the only place that
962      called this (frame.c:Fraise_frame ()) also called raise_lower;
963      if this ends up the case again, comment this out again. */
964   if (!FRAME_VISIBLE_P (f))
965     {
966       f->async_visible = 1;
967       ns_raise_frame (f);
968     }
972 void
973 x_make_frame_invisible (struct frame *f)
974 /* --------------------------------------------------------------------------
975      External: Hide the window (X11 semantics)
976    -------------------------------------------------------------------------- */
978   NSView * view = FRAME_NS_VIEW (f);
979   NSTRACE (x_make_frame_invisible);
980   check_ns ();
981   [[view window] orderOut: NSApp];
982   f->async_visible = 0;
983   f->async_iconified = 0;
987 void
988 x_iconify_frame (struct frame *f)
989 /* --------------------------------------------------------------------------
990      External: Iconify window
991    -------------------------------------------------------------------------- */
993   NSView * view = FRAME_NS_VIEW (f);
994   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
995   NSTRACE (x_iconify_frame);
996   check_ns ();
998   if (dpyinfo->x_highlight_frame == f)
999     dpyinfo->x_highlight_frame = 0;
1001   if ([[view window] windowNumber] <= 0)
1002     {
1003       /* the window is still deferred.  Make it very small, bring it
1004          on screen and order it out. */
1005       NSRect s = { { 100, 100}, {0, 0} };
1006       NSRect t;
1007       t = [[view window] frame];
1008       [[view window] setFrame: s display: NO];
1009       [[view window] orderBack: NSApp];
1010       [[view window] orderOut: NSApp];
1011       [[view window] setFrame: t display: NO];
1012     }
1013   [[view window] miniaturize: NSApp];
1017 void
1018 x_destroy_window (struct frame *f)
1019 /* --------------------------------------------------------------------------
1020      External: Delete the window
1021    -------------------------------------------------------------------------- */
1023   NSView *view = FRAME_NS_VIEW (f);
1024   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1025   NSTRACE (x_destroy_window);
1026   check_ns ();
1028   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1030   BLOCK_INPUT;
1032   free_frame_menubar (f);
1034   if (FRAME_FACE_CACHE (f))
1035     free_frame_faces (f);
1037   if (f == dpyinfo->x_focus_frame)
1038     dpyinfo->x_focus_frame = 0;
1039   if (f == dpyinfo->x_highlight_frame)
1040     dpyinfo->x_highlight_frame = 0;
1041   if (f == dpyinfo->mouse_face_mouse_frame)
1042     {
1043       dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
1044       dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
1045       dpyinfo->mouse_face_window = Qnil;
1046       dpyinfo->mouse_face_deferred_gc = 0;
1047       dpyinfo->mouse_face_mouse_frame = 0;
1048     }
1050   xfree (f->output_data.ns);
1052   [[view window] close];
1053   [view release];
1055   ns_window_num--;
1056   UNBLOCK_INPUT;
1060 void
1061 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1062 /* --------------------------------------------------------------------------
1063      External: Position the window
1064    -------------------------------------------------------------------------- */
1066   NSScreen *screen;
1067   NSView *view = FRAME_NS_VIEW (f);
1069   NSTRACE (x_set_offset);
1071   BLOCK_INPUT;
1073   f->left_pos = xoff;
1074   f->top_pos = yoff;
1075 #ifdef NS_IMPL_GNUSTEP
1076   if (xoff < 100)
1077     f->left_pos = 100;  /* don't overlap menu */
1078 #endif
1080   if (view != nil && (screen = [[view window] screen]))
1081     [[view window] setFrameTopLeftPoint:
1082         NSMakePoint (SCREENMAXBOUND (f->left_pos),
1083                      SCREENMAXBOUND ([screen frame].size.height
1084                                      - NS_TOP_POS (f)))];
1085   UNBLOCK_INPUT;
1089 void
1090 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1091 /* --------------------------------------------------------------------------
1092      Adjust window pixel size based on given character grid size
1093      Impl is a bit more complex than other terms, need to do some
1094      internal clipping and also pay attention to screen constraints.
1095    -------------------------------------------------------------------------- */
1097   EmacsView *view = FRAME_NS_VIEW (f);
1098   EmacsToolbar *toolbar = [view toolbar];
1099   NSWindow *window = [view window];
1100   NSScreen *screen = [window screen];
1101   NSRect wr = [window frame];
1102   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1103   int pixelwidth, pixelheight;
1104   static int oldRows, oldCols, oldFontWidth, oldFontHeight;
1105   static int oldTB;
1106   static struct frame *oldF;
1108   NSTRACE (x_set_window_size);
1110   if (view == nil ||
1111       (f == oldF
1112        && rows == oldRows && cols == oldCols
1113        && oldFontWidth == FRAME_COLUMN_WIDTH (f)
1114        && oldFontHeight == FRAME_LINE_HEIGHT (f)
1115        && oldTB == tb))
1116     return;
1118 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1120   BLOCK_INPUT;
1122   check_frame_size (f, &rows, &cols);
1123   oldF = f;
1124   oldRows = rows;
1125   oldCols = cols;
1126   oldFontWidth = FRAME_COLUMN_WIDTH (f);
1127   oldFontHeight = FRAME_LINE_HEIGHT (f);
1128   oldTB = tb;
1130   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1131   compute_fringe_widths (f, 0);
1133   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1134   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1136   /* If we have a toolbar, take its height into account. */
1137   if (tb)
1138     /* NOTE: previously this would generate wrong result if toolbar not
1139              yet displayed and fixing toolbar_height=32 helped, but
1140              now (200903) seems no longer needed */
1141     FRAME_TOOLBAR_HEIGHT (f) =
1142       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1143         - FRAME_NS_TITLEBAR_HEIGHT (f);
1144   else
1145     FRAME_TOOLBAR_HEIGHT (f) = 0;
1147   wr.size.width = pixelwidth + f->border_width;
1148   wr.size.height = pixelheight + FRAME_NS_TITLEBAR_HEIGHT (f) 
1149                   + FRAME_TOOLBAR_HEIGHT (f);
1151   /* constrain to screen if we can */
1152   if (screen)
1153     {
1154       NSSize sz = [screen visibleFrame].size;
1155       NSSize ez = { wr.size.width - sz.width, wr.size.height - sz.height };
1156       if (ez.width > 0)
1157         {
1158           int cr = ez.width / FRAME_COLUMN_WIDTH (f) + 1;
1159           cols -= cr;
1160           oldCols = cols;
1161           wr.size.width -= cr * FRAME_COLUMN_WIDTH (f);
1162           pixelwidth -= cr * FRAME_COLUMN_WIDTH (f);
1163         }
1164       if (ez.height > 0)
1165         {
1166           int rr = ez.height / FRAME_LINE_HEIGHT (f) + 1;
1167           rows -= rr;
1168           oldRows = rows;
1169           wr.size.height -= rr * FRAME_LINE_HEIGHT (f);
1170           pixelheight -= rr * FRAME_LINE_HEIGHT (f);
1171         }
1172       wr.origin.x = f->left_pos;
1173       wr.origin.y = [screen frame].size.height - NS_TOP_POS (f)
1174         - wr.size.height;
1175     }
1177   [view setRows: rows andColumns: cols];
1178   [window setFrame: wr display: YES];
1180 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1182   /* This is a trick to compensate for Emacs' managing the scrollbar area
1183      as a fixed number of standard character columns.  Instead of leaving
1184      blank space for the extra, we chopped it off above.  Now for
1185      left-hand scrollbars, we shift all rendering to the left by the
1186      difference between the real width and Emacs' imagined one.  For
1187      right-hand bars, don't worry about it since the extra is never used.
1188      (Obviously doesn't work for vertically split windows tho..) */
1189   {
1190     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1191       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1192                      - NS_SCROLL_BAR_WIDTH (f), 0)
1193       : NSMakePoint (0, 0);
1194     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1195     [view setBoundsOrigin: origin];
1196   }
1198   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1199   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1200   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1201 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1203   mark_window_cursors_off (XWINDOW (f->root_window));
1204   cancel_mouse_face (f);
1206   UNBLOCK_INPUT;
1211 /* ==========================================================================
1213     Color management
1215    ========================================================================== */
1218 NSColor *
1219 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1221   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1222   if (idx < 1 || idx >= color_table->avail)
1223     return nil;
1224   return color_table->colors[idx];
1228 unsigned long
1229 ns_index_color (NSColor *color, struct frame *f)
1231   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1232   int idx;
1233   NSNumber *index;
1235   if (!color_table->colors)
1236     {
1237       color_table->size = NS_COLOR_CAPACITY;
1238       color_table->avail = 1; /* skip idx=0 as marker */
1239       color_table->colors
1240         = (NSColor **)xmalloc (color_table->size * sizeof (NSColor *));
1241       color_table->colors[0] = nil;
1242       color_table->empty_indices = [[NSMutableSet alloc] init];
1243     }
1245   /* do we already have this color ? */
1246   {
1247     int i;
1248     for (i = 1; i < color_table->avail; i++)
1249       {
1250         if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1251           {
1252             [color_table->colors[i] retain];
1253             return i;
1254           }
1255       }
1256   }
1258   if ([color_table->empty_indices count] > 0)
1259     {
1260       index = [color_table->empty_indices anyObject];
1261       [color_table->empty_indices removeObject: index];
1262       idx = [index unsignedIntValue];
1263     }
1264   else
1265     {
1266       if (color_table->avail == color_table->size)
1267         {
1268           color_table->size += NS_COLOR_CAPACITY;
1269           color_table->colors
1270             = (NSColor **)xrealloc (color_table->colors,
1271                                     color_table->size * sizeof (NSColor *));
1272         }
1273       idx = color_table->avail++;
1274     }
1276   color_table->colors[idx] = color;
1277   [color retain];
1278 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1279   return idx;
1283 void
1284 ns_free_indexed_color (unsigned long idx, struct frame *f)
1286   struct ns_color_table *color_table;
1287   NSColor *color;
1288   NSNumber *index;
1290   if (!f)
1291     return;
1293   color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1295   if (idx <= 0 || idx >= color_table->size) {
1296     message1("ns_free_indexed_color: Color index out of range.\n");
1297     return;
1298   }
1300   index = [NSNumber numberWithUnsignedInt: idx];
1301   if ([color_table->empty_indices containsObject: index]) {
1302     message1("ns_free_indexed_color: attempt to free already freed color.\n");
1303     return;
1304   }
1306   color = color_table->colors[idx];
1307   [color release];
1308   color_table->colors[idx] = nil;
1309   [color_table->empty_indices addObject: [NSNumber numberWithUnsignedInt: idx]];
1310 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1314 static int
1315 ns_get_color (const char *name, NSColor **col)
1316 /* --------------------------------------------------------------------------
1317      Parse a color name
1318    -------------------------------------------------------------------------- */
1319 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1320    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1321    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1323   NSColor *new = nil;
1324   static char hex[20];
1325   int scaling;
1326   float r = -1.0, g, b;
1327   NSString *nsname = [NSString stringWithUTF8String: name];
1329 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1330   BLOCK_INPUT;
1332   if ([nsname isEqualToString: @"ns_selection_color"])
1333     {
1334       nsname = ns_selection_color;
1335       name = [ns_selection_color UTF8String];
1336     }
1338   /* First, check for some sort of numeric specification. */
1339   hex[0] = '\0';
1341   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1342     {
1343       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1344       [scanner scanFloat: &r];
1345       [scanner scanFloat: &g];
1346       [scanner scanFloat: &b];
1347     }
1348   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1349     {
1350       strncpy (hex, name + 4, 19);
1351       hex[19] = '\0';
1352       scaling = (strlen(hex) - 2) / 3;
1353     }
1354   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1355     {
1356       int len = (strlen(name) - 1);
1357       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1358       int i;
1359       scaling = strlen(name+start) / 3;
1360       for (i=0; i<3; i++) {
1361         strncpy(hex + i * (scaling + 1), name + start + i * scaling, scaling);
1362         hex[(i+1) * (scaling + 1) - 1] = '/';
1363       }
1364       hex[3 * (scaling + 1) - 1] = '\0';
1365     }
1367   if (hex[0])
1368     {
1369       int rr, gg, bb;
1370       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1371       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1372         {
1373           r = rr / fscale;
1374           g = gg / fscale;
1375           b = bb / fscale;
1376         }
1377     }
1379   if (r >= 0.0)
1380     {
1381       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1382       UNBLOCK_INPUT;
1383       return 0;
1384     }
1386   /* Otherwise, color is expected to be from a list */
1387   {
1388     NSEnumerator *lenum, *cenum;
1389     NSString *name;
1390     NSColorList *clist;
1392 #ifdef NS_IMPL_GNUSTEP
1393     /* XXX: who is wrong, the requestor or the implementation? */
1394     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1395         == NSOrderedSame)
1396       nsname = @"highlightColor";
1397 #endif
1399     lenum = [[NSColorList availableColorLists] objectEnumerator];
1400     while ( (clist = [lenum nextObject]) && new == nil)
1401       {
1402         cenum = [[clist allKeys] objectEnumerator];
1403         while ( (name = [cenum nextObject]) && new == nil )
1404           {
1405             if ([name compare: nsname
1406                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1407               new = [clist colorWithKey: name];
1408           }
1409       }
1410   }
1412   if (new)
1413     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1414   UNBLOCK_INPUT;
1415   return new ? 0 : 1;
1419 static NSColor *
1420 ns_get_color_default (const char *name, NSColor *dflt)
1421 /* --------------------------------------------------------------------------
1422      Parse a color or use a default value
1423    -------------------------------------------------------------------------- */
1425   NSColor * col;
1427   if (ns_get_color (name, &col))
1428     return dflt;
1429   else
1430     return col;
1435 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1436 /* --------------------------------------------------------------------------
1437      Convert a Lisp string object to a NS color
1438    -------------------------------------------------------------------------- */
1440   NSTRACE (ns_lisp_to_color);
1441   if (STRINGP (color))
1442     return ns_get_color (SDATA (color), col);
1443   else if (SYMBOLP (color))
1444     return ns_get_color (SDATA (SYMBOL_NAME (color)), col);
1445   return 1;
1449 Lisp_Object
1450 ns_color_to_lisp (NSColor *col)
1451 /* --------------------------------------------------------------------------
1452      Convert a color to a lisp string with the RGB equivalent
1453    -------------------------------------------------------------------------- */
1455   CGFloat red, green, blue, alpha, gray;
1456   char buf[1024];
1457   const char *str;
1458   NSTRACE (ns_color_to_lisp);
1460   BLOCK_INPUT;
1461   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1463       if ((str =[[col colorNameComponent] UTF8String]))
1464         {
1465           UNBLOCK_INPUT;
1466           return build_string ((char *)str);
1467         }
1469     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1470         getRed: &red green: &green blue: &blue alpha: &alpha];
1471   if (red ==green && red ==blue)
1472     {
1473       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1474             getWhite: &gray alpha: &alpha];
1475       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1476                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1477       UNBLOCK_INPUT;
1478       return build_string (buf);
1479     }
1481   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1482             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1484   UNBLOCK_INPUT;
1485   return build_string (buf);
1489 void
1490 ns_query_color(void *col, XColor *color_def, int setPixel)
1491 /* --------------------------------------------------------------------------
1492          Get ARGB values out of NSColor col and put them into color_def.
1493          If setPixel, set the pixel to a concatenated version.
1494          and set color_def pixel to the resulting index.
1495    -------------------------------------------------------------------------- */
1497   CGFloat r, g, b, a;
1499   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1500   color_def->red   = r * 65535;
1501   color_def->green = g * 65535;
1502   color_def->blue  = b * 65535;
1504   if (setPixel == YES)
1505     color_def->pixel
1506       = ARGB_TO_ULONG((int)(a*255),
1507                       (int)(r*255), (int)(g*255), (int)(b*255));
1512 ns_defined_color (struct frame *f,
1513                   const char *name,
1514                   XColor *color_def,
1515                   int alloc,
1516                   char makeIndex)
1517 /* --------------------------------------------------------------------------
1518          Return 1 if named color found, and set color_def rgb accordingly.
1519          If makeIndex and alloc are nonzero put the color in the color_table,
1520          and set color_def pixel to the resulting index.
1521          If makeIndex is zero, set color_def pixel to ARGB.
1522          Return 0 if not found
1523    -------------------------------------------------------------------------- */
1525   NSColor *col;
1526   NSTRACE (ns_defined_color);
1528   BLOCK_INPUT;
1529   if (ns_get_color (name, &col) != 0) /* Color not found  */
1530     {
1531       UNBLOCK_INPUT;
1532       return 0;
1533     }
1534   if (makeIndex && alloc)
1535     color_def->pixel = ns_index_color (col, f);
1536   ns_query_color (col, color_def, !makeIndex);
1537   UNBLOCK_INPUT;
1538   return 1;
1542 unsigned long
1543 ns_get_rgb_color (struct frame *f, float r, float g, float b, float a)
1544 /* --------------------------------------------------------------------------
1545     return an autoreleased RGB color
1546    -------------------------------------------------------------------------- */
1548 /*static int c = 1; fprintf (stderr, "color request %d\n", c++); */
1549   if (r < 0.0) r = 0.0;
1550   else if (r > 1.0) r = 1.0;
1551   if (g < 0.0) g = 0.0;
1552   else if (g > 1.0) g = 1.0;
1553   if (b < 0.0) b = 0.0;
1554   else if (b > 1.0) b = 1.0;
1555   if (a < 0.0) a = 0.0;
1556   else if (a > 1.0) a = 1.0;
1557   return (unsigned long) ns_index_color(
1558     [NSColor colorWithCalibratedRed: r green: g blue: b alpha: a], f);
1562 void
1563 x_set_frame_alpha (struct frame *f)
1564 /* --------------------------------------------------------------------------
1565      change the entire-frame transparency
1566    -------------------------------------------------------------------------- */
1568   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1569   EmacsView *view = FRAME_NS_VIEW (f);
1570   double alpha = 1.0;
1571   double alpha_min = 1.0;
1573   if (dpyinfo->x_highlight_frame == f)
1574     alpha = f->alpha[0];
1575   else
1576     alpha = f->alpha[1];
1578   if (FLOATP (Vframe_alpha_lower_limit))
1579     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1580   else if (INTEGERP (Vframe_alpha_lower_limit))
1581     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1583   if (alpha < 0.0)
1584     return;
1585   else if (1.0 < alpha)
1586     alpha = 1.0;
1587   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1588     alpha = alpha_min;
1590 #ifdef NS_IMPL_COCOA
1591   [[view window] setAlphaValue: alpha];
1592 #endif
1596 /* ==========================================================================
1598     Mouse handling
1600    ========================================================================== */
1603 void
1604 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1605 /* --------------------------------------------------------------------------
1606      Programmatically reposition mouse pointer in pixel coordinates
1607    -------------------------------------------------------------------------- */
1609   NSTRACE (x_set_mouse_pixel_position);
1610   ns_raise_frame (f);
1611 #if 0
1612   /* FIXME: this does not work, and what about GNUstep? */
1613 #ifdef NS_IMPL_COCOA
1614   [FRAME_NS_VIEW (f) lockFocus];
1615   PSsetmouse ((float)pix_x, (float)pix_y);
1616   [FRAME_NS_VIEW (f) unlockFocus];
1617 #endif
1618 #endif
1622 void
1623 x_set_mouse_position (struct frame *f, int h, int v)
1624 /* --------------------------------------------------------------------------
1625      Programmatically reposition mouse pointer in character coordinates
1626    -------------------------------------------------------------------------- */
1628   int pix_x, pix_y;
1630   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1631   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1633   if (pix_x < 0) pix_x = 0;
1634   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1636   if (pix_y < 0) pix_y = 0;
1637   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1639   x_set_mouse_pixel_position (f, pix_x, pix_y);
1643 static int
1644 note_mouse_movement (struct frame *frame, float x, float y)
1645 /*   ------------------------------------------------------------------------
1646      Called by EmacsView on mouseMovement events.  Passes on
1647      to emacs mainstream code if we moved off of a rect of interest
1648      known as last_mouse_glyph.
1649      ------------------------------------------------------------------------ */
1651 //  NSTRACE (note_mouse_movement);
1653   XSETFRAME (last_mouse_motion_frame, frame);
1655   /* Note, this doesn't get called for enter/leave, since we don't have a
1656      position.  Those are taken care of in the corresponding NSView methods. */
1658   /* has movement gone beyond last rect we were tracking? */
1659   if (x < last_mouse_glyph.origin.x ||
1660       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1661       y < last_mouse_glyph.origin.y ||
1662       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1663     {
1664       ns_update_begin(frame);
1665       frame->mouse_moved = 1;
1666       note_mouse_highlight (frame, x, y);
1667       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1668       ns_update_end(frame);
1669       return 1;
1670     }
1672   return 0;
1676 static void
1677 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1678                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1679                    unsigned long *time)
1680 /* --------------------------------------------------------------------------
1681     External (hook): inform emacs about mouse position and hit parts.
1682     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1683     x & y should be position in the scrollbar (the whole bar, not the handle)
1684     and length of scrollbar respectively
1685    -------------------------------------------------------------------------- */
1687   id view;
1688   NSPoint position;
1689   int xchar, ychar;
1690   Lisp_Object frame, tail;
1691   struct frame *f;
1692   struct ns_display_info *dpyinfo;
1694   NSTRACE (ns_mouse_position);
1696   if (*fp == NULL)
1697     {
1698       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1699       return;
1700     }
1702   dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1704   BLOCK_INPUT;
1706   if (last_mouse_scroll_bar != nil && insist == 0)
1707     {
1708       /* TODO: we do not use this path at the moment because drag events will
1709            go directly to the EmacsScroller.  Leaving code in for now. */
1710       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1711                                               x: x y: y];
1712       if (time) *time = last_mouse_movement_time;
1713       last_mouse_scroll_bar = nil;
1714     }
1715   else
1716     {
1717       /* Clear the mouse-moved flag for every frame on this display.  */
1718       FOR_EACH_FRAME (tail, frame)
1719         if (FRAME_NS_P (XFRAME (frame))
1720             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1721           XFRAME (frame)->mouse_moved = 0;
1723       last_mouse_scroll_bar = nil;
1724       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1725         f = last_mouse_frame;
1726       else
1727         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1728                                     : SELECTED_FRAME ();
1730       if (f && f->output_data.ns)  /* TODO: 2nd check no longer needed? */
1731         {
1732           view = FRAME_NS_VIEW (*fp);
1734           position = [[view window] mouseLocationOutsideOfEventStream];
1735           position = [view convertPoint: position fromView: nil];
1736           remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1737 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1739           if (bar_window) *bar_window = Qnil;
1740           if (part) *part = 0; /*scroll_bar_handle; */
1742           if (x) XSETINT (*x, lrint (position.x));
1743           if (y) XSETINT (*y, lrint (position.y));
1744           if (time) *time = last_mouse_movement_time;
1745           *fp = f;
1746         }
1747     }
1749   UNBLOCK_INPUT;
1753 static void
1754 ns_frame_up_to_date (struct frame *f)
1755 /* --------------------------------------------------------------------------
1756     External (hook): Fix up mouse highlighting right after a full update.
1757     Some highlighting was deferred if GC was happening during
1758     note_mouse_highlight (), while other highlighting was deferred for update.
1759    -------------------------------------------------------------------------- */
1761   NSTRACE (ns_frame_up_to_date);
1763   if (FRAME_NS_P (f))
1764     {
1765       struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1766       if ((dpyinfo->mouse_face_deferred_gc||f ==dpyinfo->mouse_face_mouse_frame)
1767       /*&& dpyinfo->mouse_face_mouse_frame*/)
1768         {
1769           BLOCK_INPUT;
1770          ns_update_begin(f);
1771           if (dpyinfo->mouse_face_mouse_frame)
1772             note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
1773                                   dpyinfo->mouse_face_mouse_x,
1774                                   dpyinfo->mouse_face_mouse_y);
1775           dpyinfo->mouse_face_deferred_gc = 0;
1776          ns_update_end(f);
1777           UNBLOCK_INPUT;
1778         }
1779     }
1783 void
1784 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1785 /* --------------------------------------------------------------------------
1786     External (RIF): set frame mouse pointer type.
1787    -------------------------------------------------------------------------- */
1789   NSTRACE (ns_define_frame_cursor);
1790   if (FRAME_POINTER_TYPE (f) != cursor)
1791     {
1792       EmacsView *view = FRAME_NS_VIEW (f);
1793       FRAME_POINTER_TYPE (f) = cursor;
1794       [[view window] invalidateCursorRectsForView: view];
1795       /* Redisplay assumes this function also draws the changed frame
1796          cursor, but this function doesn't, so do it explicitly.  */
1797       x_update_cursor (f, 1);
1798     }
1803 /* ==========================================================================
1805     Keyboard handling
1807    ========================================================================== */
1810 static unsigned
1811 ns_convert_key (unsigned code)
1812 /* --------------------------------------------------------------------------
1813     Internal call used by NSView-keyDown.
1814    -------------------------------------------------------------------------- */
1816   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1817                                 / sizeof (convert_ns_to_X_keysym[0]));
1818   unsigned keysym;
1819   /* An array would be faster, but less easy to read. */
1820   for (keysym = 0; keysym < last_keysym; keysym += 2)
1821     if (code == convert_ns_to_X_keysym[keysym])
1822       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1823   return 0;
1824 /* if decide to use keyCode and Carbon table, use this line:
1825      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1829 char *
1830 x_get_keysym_name (int keysym)
1831 /* --------------------------------------------------------------------------
1832     Called by keyboard.c.  Not sure if the return val is important, except
1833     that it be unique.
1834    -------------------------------------------------------------------------- */
1836   static char value[16];
1837   NSTRACE (x_get_keysym_name);
1838   sprintf (value, "%d", keysym);
1839   return value;
1844 /* ==========================================================================
1846     Block drawing operations
1848    ========================================================================== */
1851 static void
1852 ns_redraw_scroll_bars (struct frame *f)
1854   int i;
1855   id view;
1856   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1857   NSTRACE (ns_judge_scroll_bars);
1858   for (i =[subviews count]-1; i >= 0; i--)
1859     {
1860       view = [subviews objectAtIndex: i];
1861       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1862       [view display];
1863     }
1867 void
1868 ns_clear_frame (struct frame *f)
1869 /* --------------------------------------------------------------------------
1870       External (hook): Erase the entire frame
1871    -------------------------------------------------------------------------- */
1873   NSView *view = FRAME_NS_VIEW (f);
1874   NSRect r;
1876   NSTRACE (ns_clear_frame);
1877   if (ns_in_resize)
1878     return;
1880  /* comes on initial frame because we have
1881     after-make-frame-functions = select-frame */
1882  if (!FRAME_DEFAULT_FACE (f))
1883    return;
1885   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
1887   output_cursor.hpos = output_cursor.vpos = 0;
1888   output_cursor.x = -1;
1890   r = [view bounds];
1892   BLOCK_INPUT;
1893   ns_focus (f, &r, 1);
1894   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
1895   NSRectFill (r);
1896   ns_unfocus (f);
1898 #ifdef NS_IMPL_COCOA
1899   [[view window] display];  /* redraw resize handle */
1900 #endif
1902   /* as of 2006/11 or so this is now needed */
1903   ns_redraw_scroll_bars (f);
1904   UNBLOCK_INPUT;
1908 void
1909 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
1910 /* --------------------------------------------------------------------------
1911     External (RIF):  Clear section of frame
1912    -------------------------------------------------------------------------- */
1914   NSRect r = NSMakeRect (x, y, width, height);
1915   NSView *view = FRAME_NS_VIEW (f);
1916   struct face *face = FRAME_DEFAULT_FACE (f);
1918   if (!view || !face)
1919     return;
1921   NSTRACE (ns_clear_frame_area);
1923   r = NSIntersectionRect (r, [view frame]);
1924   ns_focus (f, &r, 1);
1925   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
1927 #ifdef NS_IMPL_COCOA
1928   {
1929     /* clip out the resize handle */
1930     NSWindow *window = [FRAME_NS_VIEW (f) window];
1931     NSRect ir
1932       = [view convertRect: ns_resize_handle_rect (window) fromView: nil];
1934     ir = NSIntersectionRect (r, ir);
1935     if (NSIsEmptyRect (ir))
1936       {
1937 #endif
1939   NSRectFill (r);
1941 #ifdef NS_IMPL_COCOA
1942       }
1943     else
1944       {
1945         NSRect r1 = r, r2 = r; /* upper and lower non-intersecting */
1946         r1.size.height -= ir.size.height;
1947         r2.origin.y += r1.size.height;
1948         r2.size.width -= ir.size.width;
1949         r2.size.height = ir.size.height;
1950         NSRectFill (r1);
1951         NSRectFill (r2);
1952       }
1953   }
1954 #endif
1956   ns_unfocus (f);
1957   return;
1961 static void
1962 ns_scroll_run (struct window *w, struct run *run)
1963 /* --------------------------------------------------------------------------
1964     External (RIF):  Insert or delete n lines at line vpos
1965    -------------------------------------------------------------------------- */
1967   struct frame *f = XFRAME (w->frame);
1968   int x, y, width, height, from_y, to_y, bottom_y;
1970   NSTRACE (ns_scroll_run);
1972   /* begin copy from other terms */
1973   /* Get frame-relative bounding box of the text display area of W,
1974      without mode lines.  Include in this box the left and right
1975      fringe of W.  */
1976   window_box (w, -1, &x, &y, &width, &height);
1978   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
1979   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
1980   bottom_y = y + height;
1982   if (to_y < from_y)
1983     {
1984       /* Scrolling up.  Make sure we don't copy part of the mode
1985          line at the bottom.  */
1986       if (from_y + run->height > bottom_y)
1987         height = bottom_y - from_y;
1988       else
1989         height = run->height;
1990     }
1991   else
1992     {
1993       /* Scolling down.  Make sure we don't copy over the mode line.
1994          at the bottom.  */
1995       if (to_y + run->height > bottom_y)
1996         height = bottom_y - to_y;
1997       else
1998         height = run->height;
1999     }
2000   /* end copy from other terms */
2002   if (height == 0)
2003       return;
2005   BLOCK_INPUT;
2007   updated_window = w;
2008   x_clear_cursor (w);
2010   {
2011     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2012     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2013     NSPoint dstOrigin = NSMakePoint (x, to_y);
2015     ns_focus (f, &dstRect, 1);
2016     NSCopyBits (0, srcRect , dstOrigin);
2017     ns_unfocus (f);
2018   }
2020   UNBLOCK_INPUT;
2024 static void
2025 ns_after_update_window_line (struct glyph_row *desired_row)
2026 /* --------------------------------------------------------------------------
2027     External (RIF): preparatory to fringe update after text was updated
2028    -------------------------------------------------------------------------- */
2030   struct window *w = updated_window;
2031   struct frame *f;
2032   int width, height;
2034   NSTRACE (ns_after_update_window_line);
2036   /* begin copy from other terms */
2037   xassert (w);
2039   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2040     desired_row->redraw_fringe_bitmaps_p = 1;
2042   /* When a window has disappeared, make sure that no rest of
2043      full-width rows stays visible in the internal border.
2044      Under NS this is drawn inside the fringes. */
2045   if (windows_or_buffers_changed
2046       && (f = XFRAME (w->frame),
2047           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2048           width != 0)
2049       && (height = desired_row->visible_height,
2050           height > 0))
2051     {
2052       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2054       /* Internal border is drawn below the tool bar.  */
2055       if (WINDOWP (f->tool_bar_window)
2056           && w == XWINDOW (f->tool_bar_window))
2057         y -= width;
2058       /* end copy from other terms */
2060       BLOCK_INPUT;
2061       if (!desired_row->full_width_p)
2062         {
2063           int x1 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2064             + WINDOW_LEFT_FRINGE_WIDTH (w);
2065           int x2 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2066             + FRAME_PIXEL_WIDTH (f) - NS_SCROLL_BAR_WIDTH (f)
2067             - WINDOW_RIGHT_FRINGE_WIDTH (w)
2068             - FRAME_INTERNAL_BORDER_WIDTH (f);
2069           ns_clear_frame_area (f, x1, y, width, height);
2070           ns_clear_frame_area (f, x2, y, width, height);
2071         }
2072       UNBLOCK_INPUT;
2073     }
2077 static void
2078 ns_shift_glyphs_for_insert (struct frame *f,
2079                            int x, int y, int width, int height,
2080                            int shift_by)
2081 /* --------------------------------------------------------------------------
2082     External (RIF): copy an area horizontally, don't worry about clearing src
2083    -------------------------------------------------------------------------- */
2085   NSRect srcRect = NSMakeRect (x, y, width, height);
2086   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2087   NSPoint dstOrigin = dstRect.origin;
2089   NSTRACE (ns_shift_glyphs_for_insert);
2091   ns_focus (f, &dstRect, 1);
2092   NSCopyBits (0, srcRect, dstOrigin);
2093   ns_unfocus (f);
2098 /* ==========================================================================
2100     Character encoding and metrics
2102    ========================================================================== */
2105 static inline void
2106 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2107 /* --------------------------------------------------------------------------
2108      External (RIF); compute left/right overhang of whole string and set in s
2109    -------------------------------------------------------------------------- */
2111   struct face *face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2112   struct font *font = s->font; /*face->font; */
2114   if (s->char2b)
2115     {
2116       struct font_metrics metrics;
2117       unsigned int codes[2];
2118       codes[0] = *(s->char2b);
2119       codes[1] = *(s->char2b + s->nchars - 1);
2121       font->driver->text_extents (font, codes, 2, &metrics);
2122       s->left_overhang = -metrics.lbearing;
2123       s->right_overhang
2124         = metrics.rbearing > metrics.width
2125         ? metrics.rbearing - metrics.width : 0;
2126     }
2127   else
2128     {
2129       s->left_overhang = 0;
2130       s->right_overhang = ((struct nsfont_info *)font)->ital ?
2131         FONT_HEIGHT (font) * 0.2 : 0;
2132     }
2137 /* ==========================================================================
2139     Fringe and cursor drawing
2141    ========================================================================== */
2144 extern int max_used_fringe_bitmap;
2145 static void
2146 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2147                       struct draw_fringe_bitmap_params *p)
2148 /* --------------------------------------------------------------------------
2149     External (RIF); fringe-related
2150    -------------------------------------------------------------------------- */
2152   struct frame *f = XFRAME (WINDOW_FRAME (w));
2153   struct face *face = p->face;
2154   int rowY;
2155   static EmacsImage **bimgs = NULL;
2156   static int nBimgs = 0;
2157   /* NS-specific: move internal border inside fringe */
2158   int x = p->bx < 0 ? p->x : p->bx;
2159   int wd = p->bx < 0 ? p->wd : p->nx;
2160   BOOL fringeOnVeryLeft
2161     = x - WINDOW_LEFT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w)
2162       - FRAME_INTERNAL_BORDER_WIDTH (f) < 10;
2163   BOOL fringeOnVeryRight
2164     = FRAME_PIXEL_WIDTH (f) - x - wd - FRAME_INTERNAL_BORDER_WIDTH (f)
2165       - WINDOW_RIGHT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w) < 10;
2166   int xAdjust = FRAME_INTERNAL_BORDER_WIDTH (f) *
2167     (fringeOnVeryLeft ? -1 : (fringeOnVeryRight ? 1 : 0));
2169   /* grow bimgs if needed */
2170   if (nBimgs < max_used_fringe_bitmap)
2171     {
2172       EmacsImage **newBimgs
2173         = xmalloc (max_used_fringe_bitmap * sizeof (EmacsImage *));
2174       memset (newBimgs, 0, max_used_fringe_bitmap * sizeof (EmacsImage *));
2176       if (nBimgs)
2177         {
2178           memcpy (newBimgs, bimgs, nBimgs * sizeof (EmacsImage *));
2179           xfree (bimgs);
2180         }
2182       bimgs = newBimgs;
2183       nBimgs = max_used_fringe_bitmap;
2184     }
2186   /* Must clip because of partially visible lines.  */
2187   rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2188   ns_clip_to_row (w, row, -1, YES);
2190   if (p->bx >= 0 && !p->overlay_p)
2191     {
2192       int yAdjust = rowY - FRAME_INTERNAL_BORDER_WIDTH (f) < 5 ?
2193         -FRAME_INTERNAL_BORDER_WIDTH (f) : 0;
2194       int yIncr = FRAME_PIXEL_HEIGHT (f) - (p->by+yAdjust + p->ny) < 5 ?
2195         FRAME_INTERNAL_BORDER_WIDTH (f) : 0
2196         + (yAdjust ? FRAME_INTERNAL_BORDER_WIDTH (f) : 0);
2197       NSRect r = NSMakeRect (p->bx+xAdjust, p->by+yAdjust, p->nx, p->ny+yIncr);
2198       NSRectClip (r);
2199       [ns_lookup_indexed_color(face->background, f) set];
2200       NSRectFill (r);
2201     }
2203   if (p->which)
2204     {
2205       NSRect r = NSMakeRect (p->x+xAdjust, p->y, p->wd, p->h);
2206       NSPoint pt = r.origin;
2207       EmacsImage *img = bimgs[p->which - 1];
2209       if (!img)
2210         {
2211           unsigned short *bits = p->bits + p->dh;
2212           int len = 8 * p->h/8;
2213           int i;
2214           unsigned char *cbits = xmalloc (len);
2216           for (i =0; i<len; i++)
2217             cbits[i] = ~(bits[i] & 0xff);
2218           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2219                                            flip: NO];
2220           bimgs[p->which - 1] = img;
2221           xfree (cbits);
2222         }
2224       NSRectClip (r);
2225       /* Since we composite the bitmap instead of just blitting it, we need
2226          to erase the whole background. */
2227       [ns_lookup_indexed_color(face->background, f) set];
2228       NSRectFill (r);
2229       pt.y += p->h;
2230       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2231       [img compositeToPoint: pt operation: NSCompositeSourceOver];
2232     }
2233   ns_unfocus (f);
2237 void
2238 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2239                        int x, int y, int cursor_type, int cursor_width,
2240                        int on_p, int active_p)
2241 /* --------------------------------------------------------------------------
2242      External call (RIF): draw cursor
2243      (modeled after x_draw_window_cursor
2244      FIXME: cursor_width is effectively bogus -- it sometimes gets set
2245      in xdisp.c set_frame_cursor_types, sometimes left uninitialized;
2246      DON'T USE IT (no other terms do)
2247    -------------------------------------------------------------------------- */
2249   NSRect r, s;
2250   int fx, fy, h;
2251   struct frame *f = WINDOW_XFRAME (w);
2252   struct glyph *phys_cursor_glyph;
2253   int overspill;
2255   NSTRACE (dumpcursor);
2256 //fprintf(stderr, "drawcursor (%d,%d) activep = %d\tonp = %d\tc_type = %d\twidth = %d\n",x,y, active_p,on_p,cursor_type,cursor_width);
2258   if (!on_p)
2259         return;
2261   w->phys_cursor_type = cursor_type;
2262   w->phys_cursor_on_p = on_p;
2264   if (cursor_type == NO_CURSOR)
2265     {
2266       w->phys_cursor_width = 0;
2267       return;
2268     }
2270   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2271     {
2272       if (glyph_row->exact_window_width_line_p
2273           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2274         {
2275           glyph_row->cursor_in_fringe_p = 1;
2276           draw_fringe_bitmap (w, glyph_row, 0);
2277         }
2278       return;
2279     }
2281   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2283   r.origin.x = fx, r.origin.y = fy;
2284   r.size.height = h;
2285   r.size.width = w->phys_cursor_width;
2287   /* FIXME: if we overwrite the internal border area, it does not get erased;
2288      fix by truncating cursor, but better would be to erase properly */
2289   overspill = r.origin.x + r.size.width -
2290     WINDOW_TEXT_TO_FRAME_PIXEL_X (w, WINDOW_BOX_RIGHT_EDGE_X (w) 
2291       - WINDOW_TOTAL_FRINGE_WIDTH (w) - FRAME_INTERNAL_BORDER_WIDTH (f));
2292   if (overspill > 0)
2293     r.size.width -= overspill;
2295   /* TODO: only needed in rare cases with last-resort font in HELLO..
2296      should we do this more efficiently? */
2297   ns_clip_to_row (w, glyph_row, -1, NO); /* do ns_focus(f, &r, 1); if remove */
2298   [FRAME_CURSOR_COLOR (f) set];
2300 #ifdef NS_IMPL_COCOA
2301   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2302            atomic.  Cleaner ways of doing this should be investigated.
2303            One way would be to set a global variable DRAWING_CURSOR
2304            when making the call to draw_phys..(), don't focus in that
2305            case, then move the ns_unfocus() here after that call. */
2306   NSDisableScreenUpdates ();
2307 #endif
2309   switch (cursor_type)
2310     {
2311     case NO_CURSOR:
2312       break;
2313     case FILLED_BOX_CURSOR:
2314       NSRectFill (r);
2315       break;
2316     case HOLLOW_BOX_CURSOR:
2317       NSRectFill (r);
2318       [FRAME_BACKGROUND_COLOR (f) set];
2319       NSRectFill (NSInsetRect (r, 1, 1));
2320       [FRAME_CURSOR_COLOR (f) set];
2321       break;
2322     case HBAR_CURSOR:
2323       s = r;
2324       s.origin.y += lrint (0.75 * s.size.height);
2325       s.size.height = lrint (s.size.height * 0.25);
2326       NSRectFill (s);
2327       break;
2328     case BAR_CURSOR:
2329       s = r;
2330       s.size.width = min (cursor_width, 2); //FIXME(see above)
2331       NSRectFill (s);
2332       break;
2333     }
2334   ns_unfocus (f);
2336   /* draw the character under the cursor */
2337   if (cursor_type != NO_CURSOR)
2338     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2340 #ifdef NS_IMPL_COCOA
2341   NSEnableScreenUpdates ();
2342 #endif
2347 static void
2348 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2349 /* --------------------------------------------------------------------------
2350      External (RIF): Draw a vertical line.
2351    -------------------------------------------------------------------------- */
2353   struct frame *f = XFRAME (WINDOW_FRAME (w));
2354   struct face *face;
2355   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2357   NSTRACE (ns_draw_vertical_window_border);
2359   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2360   if (face)
2361       [ns_lookup_indexed_color(face->foreground, f) set];
2363   ns_focus (f, &r, 1);
2364   NSRectFill(r);
2365   ns_unfocus (f);
2369 void
2370 show_hourglass (struct atimer *timer)
2372   if (hourglass_shown_p)
2373     return;
2375   BLOCK_INPUT;
2377   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2379   hourglass_shown_p = 1;
2380   UNBLOCK_INPUT;
2384 void
2385 hide_hourglass (void)
2387   if (!hourglass_shown_p)
2388     return;
2390   BLOCK_INPUT;
2392   /* TODO: remove NSProgressIndicator from all frames */
2394   hourglass_shown_p = 0;
2395   UNBLOCK_INPUT;
2400 /* ==========================================================================
2402     Glyph drawing operations
2404    ========================================================================== */
2407 static inline NSRect
2408 ns_fix_rect_ibw (NSRect r, int fibw, int frame_pixel_width)
2409 /* --------------------------------------------------------------------------
2410     Under NS we draw internal borders inside fringes, and want full-width
2411     rendering to go all the way to edge.  This function makes that correction.
2412    -------------------------------------------------------------------------- */
2414   if (r.origin.y <= fibw+1)
2415     {
2416       r.size.height += r.origin.y;
2417       r.origin.y = 0;
2418     }
2419   if (r.origin.x <= fibw+1)
2420     {
2421       r.size.width += r.origin.x;
2422       r.origin.x = 0;
2423     }
2424   if (frame_pixel_width - (r.origin.x+r.size.width) <= fibw+1)
2425     r.size.width += fibw;
2427   return r;
2431 static int
2432 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2433 /* --------------------------------------------------------------------------
2434     Wrapper utility to account for internal border width on full-width lines,
2435     and allow top full-width rows to hit the frame top.  nr should be pointer
2436     to two successive NSRects.  Number of rects actually used is returned.
2437    -------------------------------------------------------------------------- */
2439   int n = get_glyph_string_clip_rects (s, nr, 2);
2440   if (s->row->full_width_p)
2441     {
2442       *nr = ns_fix_rect_ibw (*nr, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2443                             FRAME_PIXEL_WIDTH (s->f));
2444       if (n == 2)
2445         *nr = ns_fix_rect_ibw (*(nr+1), FRAME_INTERNAL_BORDER_WIDTH (s->f),
2446                               FRAME_PIXEL_WIDTH (s->f));
2447     }
2448   return n;
2452 static void
2453 ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char right_p)
2454 /* --------------------------------------------------------------------------
2455     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2456     Note we can't just use an NSDrawRect command, because of the possibility
2457     of some sides not being drawn, and because the rect will be filled.
2458    -------------------------------------------------------------------------- */
2460   NSRect s = r;
2461   [col set];
2463   /* top, bottom */
2464   s.size.height = thickness;
2465   NSRectFill (s);
2466   s.origin.y += r.size.height - thickness;
2467   NSRectFill (s);
2469   s.size.height = r.size.height;
2470   s.origin.y = r.origin.y;
2472   /* left, right (optional) */
2473   s.size.width = thickness;
2474   if (left_p)
2475     NSRectFill (s);
2476   if (right_p)
2477     {
2478       s.origin.x += r.size.width - thickness;
2479       NSRectFill (s);
2480     }
2484 static void
2485 ns_draw_relief (NSRect r, int thickness, char raised_p,
2486                char top_p, char bottom_p, char left_p, char right_p,
2487                struct glyph_string *s)
2488 /* --------------------------------------------------------------------------
2489     Draw a relief rect inside r, optionally leaving some sides open.
2490     Note we can't just use an NSDrawBezel command, because of the possibility
2491     of some sides not being drawn, and because the rect will be filled.
2492    -------------------------------------------------------------------------- */
2494   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2495   NSColor *newBaseCol = nil;
2496   NSRect sr = r;
2498   NSTRACE (ns_draw_relief);
2500   /* set up colors */
2502   if (s->face->use_box_color_for_shadows_p)
2503     {
2504       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2505     }
2506 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2507            && s->img->pixmap
2508            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2509        {
2510          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2511        } */
2512   else
2513     {
2514       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2515     }
2517   if (newBaseCol == nil)
2518     newBaseCol = [NSColor grayColor];
2520   if (newBaseCol != baseCol)  /* TODO: better check */
2521     {
2522       [baseCol release];
2523       baseCol = [newBaseCol retain];
2524       [lightCol release];
2525       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2526       [darkCol release];
2527       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2528     }
2530   [(raised_p ? lightCol : darkCol) set];
2532   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2534   /* top */
2535   sr.size.height = thickness;
2536   if (top_p) NSRectFill (sr);
2538   /* left */
2539   sr.size.height = r.size.height;
2540   sr.size.width = thickness;
2541   if (left_p) NSRectFill (sr);
2543   [(raised_p ? darkCol : lightCol) set];
2545   /* bottom */
2546   sr.size.width = r.size.width;
2547   sr.size.height = thickness;
2548   sr.origin.y += r.size.height - thickness;
2549   if (bottom_p) NSRectFill (sr);
2551   /* right */
2552   sr.size.height = r.size.height;
2553   sr.origin.y = r.origin.y;
2554   sr.size.width = thickness;
2555   sr.origin.x += r.size.width - thickness;
2556   if (right_p) NSRectFill (sr);
2560 static void
2561 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2562 /* --------------------------------------------------------------------------
2563       Function modeled after x_draw_glyph_string_box ().
2564       Sets up parameters for drawing.
2565    -------------------------------------------------------------------------- */
2567   int right_x, last_x;
2568   char left_p, right_p;
2569   struct glyph *last_glyph;
2570   NSRect r;
2571   int thickness;
2572   struct face *face;
2574   if (s->hl == DRAW_MOUSE_FACE)
2575     {
2576       face = FACE_FROM_ID
2577         (s->f, FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
2578       if (!face)
2579         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2580     }
2581   else
2582     face = s->face;
2584   thickness = face->box_line_width;
2586   NSTRACE (ns_dumpglyphs_box_or_relief);
2588   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2589             ? WINDOW_RIGHT_EDGE_X (s->w)
2590             : window_box_right (s->w, s->area));
2591   last_glyph = (s->cmp || s->img
2592                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2594   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2595               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2597   left_p = (s->first_glyph->left_box_line_p
2598             || (s->hl == DRAW_MOUSE_FACE
2599                 && (s->prev == NULL || s->prev->hl != s->hl)));
2600   right_p = (last_glyph->right_box_line_p
2601              || (s->hl == DRAW_MOUSE_FACE
2602                  && (s->next == NULL || s->next->hl != s->hl)));
2604   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2606   /* expand full-width row over internal borders */
2607   if (s->row->full_width_p)
2608     r = ns_fix_rect_ibw (r, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2609                         FRAME_PIXEL_WIDTH (s->f));
2611   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2612   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2613     {
2614       ns_draw_box (r, abs (thickness),
2615                    ns_lookup_indexed_color (face->box_color, s->f),
2616                   left_p, right_p);
2617     }
2618   else
2619     {
2620       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2621                      1, 1, left_p, right_p, s);
2622     }
2626 static void
2627 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2628 /* --------------------------------------------------------------------------
2629       Modeled after x_draw_glyph_string_background, which draws BG in
2630       certain cases.  Others are left to the text rendering routine.
2631    -------------------------------------------------------------------------- */
2633   NSTRACE (ns_maybe_dumpglyphs_background);
2635   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2636     {
2637       int box_line_width = max (s->face->box_line_width, 0);
2638       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2639           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2640         {
2641           struct face *face;
2642           if (s->hl == DRAW_MOUSE_FACE)
2643             {
2644               face = FACE_FROM_ID
2645                 (s->f, FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
2646               if (!face)
2647                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2648             }
2649           else
2650             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2651           if (!face->stipple)
2652             [(NS_FACE_BACKGROUND (face) != 0
2653               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2654               : FRAME_BACKGROUND_COLOR (s->f)) set];
2655           else
2656             {
2657               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2658               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2659             }
2661           if (s->hl != DRAW_CURSOR)
2662             {
2663               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2664                                     s->background_width,
2665                                     s->height-2*box_line_width);
2667               /* expand full-width row over internal borders */
2668               if (s->row->full_width_p)
2669                 {
2670                   int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2671                   if (r.origin.y <= fibw+1 + box_line_width)
2672                     {
2673                       r.size.height += r.origin.y;
2674                       r.origin.y = 0;
2675                     }
2676                   if (r.origin.x <= fibw+1)
2677                     {
2678                       r.size.width += 2*r.origin.x;
2679                       r.origin.x = 0;
2680                     }
2681                   if (FRAME_PIXEL_WIDTH (s->f) - (r.origin.x + r.size.width)
2682                       <= fibw+1)
2683                     r.size.width += fibw;
2684                 }
2686               NSRectFill (r);
2687             }
2689           s->background_filled_p = 1;
2690         }
2691     }
2695 static void
2696 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2697 /* --------------------------------------------------------------------------
2698       Renders an image and associated borders.
2699    -------------------------------------------------------------------------- */
2701   EmacsImage *img = s->img->pixmap;
2702   int box_line_vwidth = max (s->face->box_line_width, 0);
2703   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2704   int bg_x, bg_y, bg_height;
2705   int th;
2706   char raised_p;
2707   NSRect br;
2708   struct face *face;
2710   NSTRACE (ns_dumpglyphs_image);
2712   if (s->face->box != FACE_NO_BOX
2713       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2714     x += abs (s->face->box_line_width);
2716   bg_x = x;
2717   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2718   bg_height = s->height;
2719   /* other terms have this, but was causing problems w/tabbar mode */
2720   /* - 2 * box_line_vwidth; */
2722   if (s->slice.x == 0) x += s->img->hmargin;
2723   if (s->slice.y == 0) y += s->img->vmargin;
2725   /* Draw BG: if we need larger area than image itself cleared, do that,
2726      otherwise, since we composite the image under NS (instead of mucking
2727      with its background color), we must clear just the image area. */
2728   if (s->hl == DRAW_MOUSE_FACE)
2729     {
2730       face = FACE_FROM_ID
2731        (s->f, FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
2732       if (!face)
2733        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2734     }
2735   else
2736     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2738   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2740   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2741       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2742     {
2743       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
2744       s->background_filled_p = 1;
2745     }
2746   else
2747     {
2748       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
2749     }
2751   /* expand full-width row over internal borders */
2752   if (s->row->full_width_p)
2753     {
2754       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2755       if (br.origin.y <= fibw+1 + box_line_vwidth)
2756         {
2757           br.size.height += br.origin.y;
2758           br.origin.y = 0;
2759         }
2760       if (br.origin.x <= fibw+1 + box_line_vwidth)
2761         {
2762           br.size.width += br.origin.x;
2763           br.origin.x = 0;
2764         }
2765       if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) <= fibw+1)
2766         br.size.width += fibw;
2767     }
2769   NSRectFill (br);
2771   /* Draw the image.. do we need to draw placeholder if img ==nil? */
2772   if (img != nil)
2773     [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
2774                 operation: NSCompositeSourceOver];
2776   /* Draw relief, if requested */
2777   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
2778     {
2779       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
2780         {
2781           th = tool_bar_button_relief >= 0 ?
2782             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
2783           raised_p = (s->hl == DRAW_IMAGE_RAISED);
2784         }
2785       else
2786         {
2787           th = abs (s->img->relief);
2788           raised_p = (s->img->relief > 0);
2789         }
2791       r.origin.x = x - th;
2792       r.origin.y = y - th;
2793       r.size.width = s->slice.width + 2*th-1;
2794       r.size.height = s->slice.height + 2*th-1;
2795       ns_draw_relief (r, th, raised_p,
2796                       s->slice.y == 0,
2797                       s->slice.y + s->slice.height == s->img->height,
2798                       s->slice.x == 0,
2799                       s->slice.x + s->slice.width == s->img->width, s);
2800     }
2804 static void
2805 ns_dumpglyphs_stretch (struct glyph_string *s)
2807   NSRect r[2];
2808   int n, i;
2809   struct face *face;
2811   if (!s->background_filled_p)
2812     {
2813       n = ns_get_glyph_string_clip_rect (s, r);
2814       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
2816       for (i=0; i<n; i++)
2817         {
2818           if (!s->row->full_width_p)
2819             {
2820               /* truncate to avoid overwriting fringe and/or scrollbar */
2821               int overrun = max (0, (s->x + s->background_width)
2822                                   - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
2823                                     - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
2824               r[i].size.width -= overrun;
2826               /* XXX: Try to work between problem where a stretch glyph on
2827                  a partially-visible bottom row will clear part of the
2828                  modeline, and another where list-buffers headers and similar
2829                  rows erroneously have visible_height set to 0.  Not sure
2830                  where this is coming from as other terms seem not to show. */
2831               r[i].size.height = min (s->height, s->row->visible_height);
2832             }
2834           /* expand full-width rows over internal borders */
2835           else
2836             {
2837               r[i] = ns_fix_rect_ibw (r[i], FRAME_INTERNAL_BORDER_WIDTH (s->f),
2838                                       FRAME_PIXEL_WIDTH (s->f));
2839             }
2841           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
2842              overwriting cursor (usually when cursor on a tab) */
2843           if (s->hl == DRAW_CURSOR)
2844             {
2845               r[i].origin.x += s->width;
2846               r[i].size.width -= s->width;
2847             }
2848         }
2850       ns_focus (s->f, r, n);
2852       if (s->hl == DRAW_MOUSE_FACE)
2853        {
2854          face = FACE_FROM_ID
2855            (s->f, FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
2856          if (!face)
2857            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2858        }
2859       else
2860        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2862       [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2864       NSRectFill (r[0]);
2865       NSRectFill (r[1]);
2866       ns_unfocus (s->f);
2867       s->background_filled_p = 1;
2868     }
2872 static void
2873 ns_draw_glyph_string (struct glyph_string *s)
2874 /* --------------------------------------------------------------------------
2875       External (RIF): Main draw-text call.
2876    -------------------------------------------------------------------------- */
2878   /* TODO (optimize): focus for box and contents draw */
2879   NSRect r[2];
2880   int n;
2881   char box_drawn_p = 0;
2883   NSTRACE (ns_draw_glyph_string);
2885   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
2886     {
2887       int width;
2888       struct glyph_string *next;
2890       for (width = 0, next = s->next;
2891            next && width < s->right_overhang;
2892            width += next->width, next = next->next)
2893         if (next->first_glyph->type != IMAGE_GLYPH)
2894           {
2895             if (next->first_glyph->type != STRETCH_GLYPH)
2896               {
2897                 n = ns_get_glyph_string_clip_rect (s->next, r);
2898                 ns_focus (s->f, r, n);
2899                 ns_maybe_dumpglyphs_background (s->next, 1);
2900                 ns_unfocus (s->f);
2901               }
2902             else
2903               {
2904                 ns_dumpglyphs_stretch (s->next);
2905               }
2906             next->num_clips = 0;
2907           }
2908     }
2910   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
2911         && (s->first_glyph->type == CHAR_GLYPH
2912             || s->first_glyph->type == COMPOSITE_GLYPH))
2913     {
2914       n = ns_get_glyph_string_clip_rect (s, r);
2915       ns_focus (s->f, r, n);
2916       ns_maybe_dumpglyphs_background (s, 1);
2917       ns_dumpglyphs_box_or_relief (s);
2918       ns_unfocus (s->f);
2919       box_drawn_p = 1;
2920     }
2922   switch (s->first_glyph->type)
2923     {
2925     case IMAGE_GLYPH:
2926       n = ns_get_glyph_string_clip_rect (s, r);
2927       ns_focus (s->f, r, n);
2928       ns_dumpglyphs_image (s, r[0]);
2929       ns_unfocus (s->f);
2930       break;
2932     case STRETCH_GLYPH:
2933       ns_dumpglyphs_stretch (s);
2934       break;
2936     case CHAR_GLYPH:
2937     case COMPOSITE_GLYPH:
2938       n = ns_get_glyph_string_clip_rect (s, r);
2939       ns_focus (s->f, r, n);
2941       if (s->for_overlaps || (s->cmp_from > 0
2942                               && ! s->first_glyph->u.cmp.automatic))
2943         s->background_filled_p = 1;
2944       else
2945         ns_maybe_dumpglyphs_background
2946           (s, s->first_glyph->type == COMPOSITE_GLYPH);
2948       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
2949                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
2950                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
2951                       NS_DUMPGLYPH_NORMAL));
2952       ns_tmp_font = (struct nsfont_info *)s->face->font;
2953       if (ns_tmp_font == NULL)
2954           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
2956       ns_tmp_font->font.driver->draw
2957         (s, 0, s->nchars, s->x, s->y,
2958          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
2959          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
2961       ns_unfocus (s->f);
2962       break;
2964     default:
2965       abort ();
2966     }
2968   /* Draw box if not done already. */
2969   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
2970     {
2971       n = ns_get_glyph_string_clip_rect (s, r);
2972       ns_focus (s->f, r, n);
2973       ns_dumpglyphs_box_or_relief (s);
2974       ns_unfocus (s->f);
2975     }
2977   s->num_clips = 0;
2982 /* ==========================================================================
2984     Event loop
2986    ========================================================================== */
2989 static void
2990 ns_send_appdefined (int value)
2991 /* --------------------------------------------------------------------------
2992     Internal: post an appdefined event which EmacsApp-sendEvent will
2993               recognize and take as a command to halt the event loop.
2994    -------------------------------------------------------------------------- */
2996   /*NSTRACE (ns_send_appdefined); */
2998   /* Only post this event if we haven't already posted one.  This will end
2999        the [NXApp run] main loop after having processed all events queued at
3000        this moment.  */
3001   if (send_appdefined)
3002     {
3003       NSEvent *nxev;
3005       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3006       send_appdefined = NO;
3008       /* Don't need wakeup timer any more */
3009       if (timed_entry)
3010         {
3011           [timed_entry invalidate];
3012           [timed_entry release];
3013           timed_entry = nil;
3014         }
3016       /* Ditto for file descriptor poller */
3017       if (fd_entry)
3018         {
3019           [fd_entry invalidate];
3020           [fd_entry release];
3021           fd_entry = nil;
3022         }
3024       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3025                                 location: NSMakePoint (0, 0)
3026                            modifierFlags: 0
3027                                timestamp: 0
3028                             windowNumber: [[NSApp mainWindow] windowNumber]
3029                                  context: [NSApp context]
3030                                  subtype: 0
3031                                    data1: value
3032                                    data2: 0];
3034       /* Post an application defined event on the event queue.  When this is
3035          received the [NXApp run] will return, thus having processed all
3036          events which are currently queued.  */
3037       [NSApp postEvent: nxev atStart: NO];
3038     }
3042 static int
3043 ns_read_socket (struct terminal *terminal, int expected,
3044                 struct input_event *hold_quit)
3045 /* --------------------------------------------------------------------------
3046      External (hook): Post an event to ourself and keep reading events until
3047      we read it back again.  In effect process all events which were waiting.
3048      From 21+ we have to manage the event buffer ourselves.
3049    -------------------------------------------------------------------------- */
3051   struct input_event ev;
3052   int nevents;
3054 /* NSTRACE (ns_read_socket); */
3056   if (interrupt_input_blocked)
3057     {
3058       interrupt_input_pending = 1;
3059 #ifdef SYNC_INPUT
3060       pending_signals = 1;
3061 #endif
3062       return -1;
3063     }
3065   interrupt_input_pending = 0;
3066 #ifdef SYNC_INPUT
3067   pending_signals = pending_atimers;
3068 #endif
3070   BLOCK_INPUT;
3071   n_emacs_events_pending = 0;
3072   EVENT_INIT (ev);
3073   emacs_event = &ev;
3074   q_event_ptr = hold_quit;
3076   /* we manage autorelease pools by allocate/reallocate each time around
3077      the loop; strict nesting is occasionally violated but seems not to
3078      matter.. earlier methods using full nesting caused major memory leaks */
3079   [outerpool release];
3080   outerpool = [[NSAutoreleasePool alloc] init];
3082   /* If have pending open-file requests, attend to the next one of those. */
3083   if (ns_pending_files && [ns_pending_files count] != 0
3084       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3085     {
3086       [ns_pending_files removeObjectAtIndex: 0];
3087     }
3088   /* Deal with pending service requests. */
3089   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3090     && [(EmacsApp *)
3091          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3092                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3093     {
3094       [ns_pending_service_names removeObjectAtIndex: 0];
3095       [ns_pending_service_args removeObjectAtIndex: 0];
3096     }
3097   else
3098     {
3099       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3100          to ourself, otherwise [NXApp run] will never exit.  */
3101       send_appdefined = YES;
3103       /* If called via ns_select, this is called once with expected=1,
3104          because we expect either the timeout or file descriptor activity.
3105          In this case the first event through will either be real input or
3106          one of these.  read_avail_input() then calls once more with expected=0
3107          and in that case we need to return quickly if there is nothing.
3108          If we're being called outside of that, it's also OK to return quickly
3109          after one iteration through the event loop, since other terms do
3110          this and emacs expects it. */
3111       if (!(inNsSelect && expected))
3112         {
3113           /* Post an application defined event on the event queue.  When this is
3114              received the [NXApp run] will return, thus having processed all
3115              events which are currently queued, if any.  */
3116           ns_send_appdefined (-1);
3117         }
3119       [NSApp run];
3120     }
3122   nevents = n_emacs_events_pending;
3123   n_emacs_events_pending = 0;
3124   emacs_event = q_event_ptr = NULL;
3125   UNBLOCK_INPUT;
3127   return nevents;
3132 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3133            fd_set *exceptfds, struct timeval *timeout)
3134 /* --------------------------------------------------------------------------
3135      Replacement for select, checking for events
3136    -------------------------------------------------------------------------- */
3138   int result;
3139   double time;
3140   NSEvent *ev;
3141 /*  NSTRACE (ns_select); */
3143   if (NSApp == nil || inNsSelect == 1 /* || ([NSApp isActive] == NO &&
3144                       [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil
3145  inMode:NSDefaultRunLoopMode dequeue:NO] == nil) */)
3146     return select (nfds, readfds, writefds, exceptfds, timeout);
3148   /* Save file descriptor set, which gets overwritten in calls to select ()
3149      Note, this is called from process.c, and only readfds is ever set */
3150   if (readfds)
3151     {
3152       memcpy (&select_readfds, readfds, sizeof (fd_set));
3153       select_nfds = nfds;
3154     }
3155   else
3156     select_nfds = 0;
3158     /* Try an initial select for pending data on input files */
3159   select_timeout.tv_sec = select_timeout.tv_usec = 0;
3160   result = select (nfds, readfds, writefds, exceptfds, &select_timeout);
3161   if (result)
3162     return result;
3164   /* if (!timeout || timed_entry || fd_entry)
3165        fprintf (stderr, "assertion failed: timeout null or timed_entry/fd_entry non-null in ns_select\n"); */
3167     /* set a timeout and run the main AppKit event loop while continuing
3168        to monitor the files */
3169   time = ((double) timeout->tv_sec) + ((double) timeout->tv_usec)/1000000.0;
3170   timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3171                                            target: NSApp
3172                                          selector: @selector (timeout_handler:)
3173                                          userInfo: 0
3174                                           repeats: YES] /* for safe removal */
3175                                                          retain];
3177   /* set a periodic task to try the select () again */
3178   fd_entry = [[NSTimer scheduledTimerWithTimeInterval: 0.1
3179                                                target: NSApp
3180                                              selector: @selector (fd_handler:)
3181                                              userInfo: 0
3182                                               repeats: YES]
3183                retain];
3185   /* Let Application dispatch events until it receives an event of the type
3186      NX_APPDEFINED, which should only be sent by timeout_handler.
3187      We tell read_avail_input() that input is "expected" because we do expect
3188      either the timeout or fd handler to fire, and if they don't, the original
3189      call from process.c that got us here expects us to wait until some input
3190      comes. */
3191   inNsSelect = 1;
3192   gobble_input (1);
3193   ev = last_appdefined_event;
3194   inNsSelect = 0;
3196   if (ev)
3197     {
3198       int t;
3199       if ([ev type] != NSApplicationDefined)
3200         abort ();
3202       t = [ev data1];
3203       last_appdefined_event = 0;
3205       if (t == -2)
3206         {
3207           /* The NX_APPDEFINED event we received was a timeout. */
3208           return 0;
3209         }
3210       else if (t == -1)
3211         {
3212           /* The NX_APPDEFINED event we received was the result of
3213              at least one real input event arriving.  */
3214           errno = EINTR;
3215           return -1;
3216         }
3217       else
3218         {
3219           /* Received back from select () in fd_handler; copy the results */
3220           if (readfds)
3221             memcpy (readfds, &select_readfds, sizeof (fd_set));
3222           return t;
3223         }
3224     }
3225   /* never reached, shut compiler up */
3226   return 0;
3231 /* ==========================================================================
3233     Scrollbar handling
3235    ========================================================================== */
3238 static void
3239 ns_set_vertical_scroll_bar (struct window *window,
3240                            int portion, int whole, int position)
3241 /* --------------------------------------------------------------------------
3242       External (hook): Update or add scrollbar
3243    -------------------------------------------------------------------------- */
3245   Lisp_Object win;
3246   NSRect r, v;
3247   struct frame *f = XFRAME (WINDOW_FRAME (window));
3248   EmacsView *view = FRAME_NS_VIEW (f);
3249   int window_y, window_height;
3250   BOOL barOnVeryLeft, barOnVeryRight;
3251   int top, left, height, width, sb_width, sb_left;
3252   EmacsScroller *bar;
3253 static int count = 0;
3255   /* optimization; display engine sends WAY too many of these.. */
3256   if (!NILP (window->vertical_scroll_bar))
3257     {
3258       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3259       if ([bar checkSamePosition: position portion: portion whole: whole])
3260         {
3261           if (view->scrollbarsNeedingUpdate == 0)
3262             {
3263               if (!windows_or_buffers_changed)
3264                   return;
3265             }
3266           else
3267             view->scrollbarsNeedingUpdate--;
3268         }
3269     }
3271   NSTRACE (ns_set_vertical_scroll_bar);
3273   /* Get dimensions.  */
3274   window_box (window, -1, 0, &window_y, 0, &window_height);
3275   top = window_y;
3276   height = window_height;
3277   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3278   left = WINDOW_SCROLL_BAR_AREA_X (window);
3280   if (top < 5) /* top scrollbar adjustment */
3281     {
3282       top -= FRAME_INTERNAL_BORDER_WIDTH (f);
3283       height += FRAME_INTERNAL_BORDER_WIDTH (f);
3284     }
3286   /* allow for displaying a skinnier scrollbar than char area allotted */
3287   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3288     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3290   barOnVeryLeft = left < 5;
3291   barOnVeryRight = FRAME_PIXEL_WIDTH (f) - left - width < 5;
3292   sb_left = left + FRAME_INTERNAL_BORDER_WIDTH (f)
3293       * (barOnVeryLeft ? -1 : (barOnVeryRight ? 1 : 0));
3295   r = NSMakeRect (sb_left, top, sb_width, height);
3296   /* the parent view is flipped, so we need to flip y value */
3297   v = [view frame];
3298   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3300   XSETWINDOW (win, window);
3301   BLOCK_INPUT;
3303   /* we want at least 5 lines to display a scrollbar */
3304   if (WINDOW_TOTAL_LINES (window) < 5)
3305     {
3306       if (!NILP (window->vertical_scroll_bar))
3307         {
3308           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3309           [bar removeFromSuperview];
3310           window->vertical_scroll_bar = Qnil;
3311         }
3312       ns_clear_frame_area (f, sb_left, top, width, height);
3313       UNBLOCK_INPUT;
3314       return;
3315     }
3317   if (NILP (window->vertical_scroll_bar))
3318     {
3319       ns_clear_frame_area (f, sb_left, top, width, height);
3320       bar = [[EmacsScroller alloc] initFrame: r window: win];
3321       window->vertical_scroll_bar = make_save_value (bar, 0);
3322     }
3323   else
3324     {
3325       NSRect oldRect;
3326       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3327       oldRect = [bar frame];
3328       r.size.width = oldRect.size.width;
3329       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3330         {
3331           if (oldRect.origin.x != r.origin.x)
3332               ns_clear_frame_area (f, sb_left, top, width, height);
3333           [bar setFrame: r];
3334         }
3335     }
3337   [bar setPosition: position portion: portion whole: whole];
3338   UNBLOCK_INPUT;
3342 static void
3343 ns_condemn_scroll_bars (struct frame *f)
3344 /* --------------------------------------------------------------------------
3345      External (hook): arrange for all frame's scrollbars to be removed
3346      at next call to judge_scroll_bars, except for those redeemed.
3347    -------------------------------------------------------------------------- */
3349   int i;
3350   id view;
3351   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3353   NSTRACE (ns_condemn_scroll_bars);
3355   for (i =[subviews count]-1; i >= 0; i--)
3356     {
3357       view = [subviews objectAtIndex: i];
3358       if ([view isKindOfClass: [EmacsScroller class]])
3359         [view condemn];
3360     }
3364 static void
3365 ns_redeem_scroll_bar (struct window *window)
3366 /* --------------------------------------------------------------------------
3367      External (hook): arrange to spare this window's scrollbar
3368      at next call to judge_scroll_bars.
3369    -------------------------------------------------------------------------- */
3371   id bar;
3372   NSTRACE (ns_redeem_scroll_bar);
3373   if (!NILP (window->vertical_scroll_bar))
3374     {
3375       bar =XNS_SCROLL_BAR (window->vertical_scroll_bar);
3376       [bar reprieve];
3377     }
3381 static void
3382 ns_judge_scroll_bars (struct frame *f)
3383 /* --------------------------------------------------------------------------
3384      External (hook): destroy all scrollbars on frame that weren't
3385      redeemed after call to condemn_scroll_bars.
3386    -------------------------------------------------------------------------- */
3388   int i;
3389   id view;
3390   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3391   NSTRACE (ns_judge_scroll_bars);
3392   for (i =[subviews count]-1; i >= 0; i--)
3393     {
3394       view = [subviews objectAtIndex: i];
3395       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3396       [view judge];
3397     }
3401 void
3402 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
3404   /* XXX irrelevant under NS */
3409 /* ==========================================================================
3411     Initialization
3413    ========================================================================== */
3416 x_display_pixel_height (struct ns_display_info *dpyinfo)
3418   NSScreen *screen = [NSScreen mainScreen];
3419   return [screen frame].size.height;
3423 x_display_pixel_width (struct ns_display_info *dpyinfo)
3425   NSScreen *screen = [NSScreen mainScreen];
3426   return [screen frame].size.width;
3430 static Lisp_Object ns_string_to_lispmod (const char *s)
3431 /* --------------------------------------------------------------------------
3432      Convert modifier name to lisp symbol
3433    -------------------------------------------------------------------------- */
3435   if (!strncmp (SDATA (SYMBOL_NAME (Qmeta)), s, 10))
3436     return Qmeta;
3437   else if (!strncmp (SDATA (SYMBOL_NAME (Qsuper)), s, 10))
3438     return Qsuper;
3439   else if (!strncmp (SDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3440     return Qcontrol;
3441   else if (!strncmp (SDATA (SYMBOL_NAME (Qalt)), s, 10))
3442     return Qalt;
3443   else if (!strncmp (SDATA (SYMBOL_NAME (Qhyper)), s, 10))
3444     return Qhyper;
3445   else if (!strncmp (SDATA (SYMBOL_NAME (Qnone)), s, 10))
3446     return Qnone;
3447   else
3448     return Qnil;
3452 static Lisp_Object ns_mod_to_lisp (int m)
3453 /* --------------------------------------------------------------------------
3454      Convert modifier code (see lisp.h) to lisp symbol
3455    -------------------------------------------------------------------------- */
3457   if (m == CHAR_META)
3458     return Qmeta;
3459   else if (m == CHAR_SUPER)
3460     return Qsuper;
3461   else if (m == CHAR_CTL)
3462     return Qcontrol;
3463   else if (m == CHAR_ALT)
3464     return Qalt;
3465   else if (m == CHAR_HYPER)
3466     return Qhyper;
3467   else /* if (m == 0) */
3468     return Qnone;
3472 static void
3473 ns_default (const char *parameter, Lisp_Object *result,
3474            Lisp_Object yesval, Lisp_Object noval,
3475            BOOL is_float, BOOL is_modstring)
3476 /* --------------------------------------------------------------------------
3477       Check a parameter value in user's preferences
3478    -------------------------------------------------------------------------- */
3480   const char *value;
3482   if ( (value =[[[NSUserDefaults standardUserDefaults]
3483                    stringForKey: [NSString stringWithUTF8String: parameter]]
3484                 UTF8String]) )
3485     {
3486       double f;
3487       char *pos;
3488       if (strcasecmp (value, "YES") == 0)
3489         *result = yesval;
3490       else if (strcasecmp (value, "NO") == 0)
3491         *result = noval;
3492       else if (is_float && (f = strtod (value, &pos), pos != value))
3493         *result = make_float (f);
3494       else if (is_modstring && value)
3495         *result = ns_string_to_lispmod (value);
3496       else fprintf (stderr,
3497                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3498     }
3502 void
3503 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3504 /* --------------------------------------------------------------------------
3505       Initialize global info and storage for display.
3506    -------------------------------------------------------------------------- */
3508     NSScreen *screen = [NSScreen mainScreen];
3509     NSWindowDepth depth = [screen depth];
3511     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3512     dpyinfo->resy = 72.27;
3513     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3514                                                   NSColorSpaceFromDepth (depth)]
3515                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3516                                                  NSColorSpaceFromDepth (depth)];
3517     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3518     dpyinfo->image_cache = make_image_cache ();
3519     dpyinfo->color_table
3520       = (struct ns_color_table *)xmalloc (sizeof (struct ns_color_table));
3521     dpyinfo->color_table->colors = NULL;
3522     dpyinfo->root_window = 42; /* a placeholder.. */
3524     dpyinfo->mouse_face_mouse_frame = NULL;
3525     dpyinfo->mouse_face_deferred_gc = 0;
3526     dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
3527     dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
3528     dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
3529     dpyinfo->mouse_face_window = dpyinfo->mouse_face_overlay = Qnil;
3530     dpyinfo->mouse_face_hidden = 0;
3532     dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
3533     dpyinfo->mouse_face_defer = 0;
3535     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3537     dpyinfo->n_fonts = 0;
3538     dpyinfo->smallest_font_height = 1;
3539     dpyinfo->smallest_char_width = 1;
3543 /* This and next define (many of the) public functions in this file. */
3544 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3545          with using despite presence in the "system dependent" redisplay
3546          interface.  In addition, many of the ns_ methods have code that is
3547          shared with all terms, indicating need for further refactoring. */
3548 extern frame_parm_handler ns_frame_parm_handlers[];
3549 static struct redisplay_interface ns_redisplay_interface =
3551   ns_frame_parm_handlers,
3552   x_produce_glyphs,
3553   x_write_glyphs,
3554   x_insert_glyphs,
3555   x_clear_end_of_line,
3556   ns_scroll_run,
3557   ns_after_update_window_line,
3558   ns_update_window_begin,
3559   ns_update_window_end,
3560   x_cursor_to,
3561   ns_flush,
3562   0, /* flush_display_optional */
3563   x_clear_window_mouse_face,
3564   x_get_glyph_overhangs,
3565   x_fix_overlapping_area,
3566   ns_draw_fringe_bitmap,
3567   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3568   0, /* destroy_fringe_bitmap */
3569   ns_compute_glyph_string_overhangs,
3570   ns_draw_glyph_string, /* interface to nsfont.m */
3571   ns_define_frame_cursor,
3572   ns_clear_frame_area,
3573   ns_draw_window_cursor,
3574   ns_draw_vertical_window_border,
3575   ns_shift_glyphs_for_insert
3579 static void
3580 ns_delete_display (struct ns_display_info *dpyinfo)
3582   /* TODO... */
3586 /* This function is called when the last frame on a display is deleted. */
3587 static void
3588 ns_delete_terminal (struct terminal *terminal)
3590   struct ns_display_info *dpyinfo = terminal->display_info.ns;
3591   int i;
3593   /* Protect against recursive calls.  delete_frame in
3594      delete_terminal calls us back when it deletes our last frame.  */
3595   if (!terminal->name)
3596     return;
3598   BLOCK_INPUT;
3600   x_destroy_all_bitmaps (dpyinfo);
3601   ns_delete_display (dpyinfo);
3602   UNBLOCK_INPUT;
3606 static struct terminal *
3607 ns_create_terminal (struct ns_display_info *dpyinfo)
3608 /* --------------------------------------------------------------------------
3609       Set up use of NS before we make the first connection.
3610    -------------------------------------------------------------------------- */
3612   struct terminal *terminal;
3614   NSTRACE (ns_create_terminal);
3616   terminal = create_terminal ();
3618   terminal->type = output_ns;
3619   terminal->display_info.ns = dpyinfo;
3620   dpyinfo->terminal = terminal;
3622   terminal->rif = &ns_redisplay_interface;
3624   terminal->clear_frame_hook = ns_clear_frame;
3625   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
3626   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
3627   terminal->ring_bell_hook = ns_ring_bell;
3628   terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
3629   terminal->set_terminal_modes_hook = ns_set_terminal_modes;
3630   terminal->update_begin_hook = ns_update_begin;
3631   terminal->update_end_hook = ns_update_end;
3632   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
3633   terminal->read_socket_hook = ns_read_socket;
3634   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
3635   terminal->mouse_position_hook = ns_mouse_position;
3636   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
3637   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
3639   terminal->fullscreen_hook = 0; /* see XTfullscreen_hook */
3641   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
3642   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
3643   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
3644   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
3646   terminal->delete_frame_hook = x_destroy_window;
3647   terminal->delete_terminal_hook = ns_delete_terminal;
3649   terminal->scroll_region_ok = 1;
3650   terminal->char_ins_del_ok = 1;
3651   terminal->line_ins_del_ok = 1;
3652   terminal->fast_clear_end_of_line = 1;
3653   terminal->memory_below_frame = 0;
3655   return terminal;
3659 struct ns_display_info *
3660 ns_term_init (Lisp_Object display_name)
3661 /* --------------------------------------------------------------------------
3662      Start the Application and get things rolling.
3663    -------------------------------------------------------------------------- */
3665   struct terminal *terminal;
3666   struct ns_display_info *dpyinfo;
3667   static int ns_initialized = 0;
3668   Lisp_Object tmp;
3670   NSTRACE (ns_term_init);
3672   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
3673   /*GSDebugAllocationActive (YES); */
3674   BLOCK_INPUT;
3675   handling_signal = 0;
3677   if (!ns_initialized)
3678     {
3679       baud_rate = 38400;
3680       Fset_input_interrupt_mode (Qnil);
3681       ns_initialized = 1;
3682     }
3684   ns_pending_files = [[NSMutableArray alloc] init];
3685   ns_pending_service_names = [[NSMutableArray alloc] init];
3686   ns_pending_service_args = [[NSMutableArray alloc] init];
3688   /* Start app and create the main menu, window, view.
3689      Needs to be here because ns_initialize_display_info () uses AppKit classes.
3690      The view will then ask the NSApp to stop and return to Emacs. */
3691   [EmacsApp sharedApplication];
3692   if (NSApp == nil)
3693     return NULL;
3694   [NSApp setDelegate: NSApp];
3696   /* debugging: log all notifications */
3697   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
3698                                          selector: @selector (logNotification:)
3699                                              name: nil object: nil]; */
3701   dpyinfo = (struct ns_display_info *)xmalloc (sizeof (struct ns_display_info));
3702   memset (dpyinfo, 0, sizeof (struct ns_display_info));
3704   ns_initialize_display_info (dpyinfo);
3705   terminal = ns_create_terminal (dpyinfo);
3707   terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
3708   init_kboard (terminal->kboard);
3709   terminal->kboard->Vwindow_system = Qns;
3710   terminal->kboard->next_kboard = all_kboards;
3711   all_kboards = terminal->kboard;
3712   /* Don't let the initial kboard remain current longer than necessary.
3713      That would cause problems if a file loaded on startup tries to
3714      prompt in the mini-buffer.  */
3715   if (current_kboard == initial_kboard)
3716     current_kboard = terminal->kboard;
3717   terminal->kboard->reference_count++;
3719   dpyinfo->next = x_display_list;
3720   x_display_list = dpyinfo;
3722   /* Put it on ns_display_name_list */
3723   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
3724                                 ns_display_name_list);
3725   dpyinfo->name_list_element = XCAR (ns_display_name_list);
3727   /* Set the name of the terminal. */
3728   terminal->name = (char *) xmalloc (SBYTES (display_name) + 1);
3729   strncpy (terminal->name, SDATA (display_name), SBYTES (display_name));
3730   terminal->name[SBYTES (display_name)] = 0;
3732   UNBLOCK_INPUT; 
3734   if (!inhibit_x_resources)
3735     {
3736       ns_default ("GSFontAntiAlias", &ns_antialias_text,
3737                  Qt, Qnil, NO, NO);
3738       tmp = Qnil;
3739       /* this is a standard variable */
3740       ns_default ("AppleAntiAliasingThreshold", &tmp,
3741                  make_float (10.0), make_float (6.0), YES, NO);
3742       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
3743     }
3745   ns_selection_color = [[NSUserDefaults standardUserDefaults]
3746                          stringForKey: @"AppleHighlightColor"];
3747   if (ns_selection_color == nil)
3748     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
3749   
3750   {
3751     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
3753     if ( cl == nil )
3754       {
3755         Lisp_Object color_file, color_map, color;
3756         int r,g,b;
3757         unsigned long c;
3758         char *name;
3760         color_file = Fexpand_file_name (build_string ("rgb.txt"),
3761                          Fsymbol_value (intern ("data-directory")));
3762         if (NILP (Ffile_readable_p (color_file)))
3763           fatal ("Could not find %s.\n", SDATA (color_file));
3765         color_map = Fx_load_color_file (color_file);
3766         if (NILP (color_map))
3767           fatal ("Could not read %s.\n", SDATA (color_file));
3769         cl = [[NSColorList alloc] initWithName: @"Emacs"];
3770         for ( ; CONSP (color_map); color_map = XCDR (color_map))
3771           {
3772             color = XCAR (color_map);
3773             name = SDATA (XCAR (color));
3774             c = XINT (XCDR (color));
3775             [cl setColor:
3776                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
3777                                             green: GREEN_FROM_ULONG (c) / 255.0
3778                                              blue: BLUE_FROM_ULONG (c) / 255.0
3779                                             alpha: 1.0]
3780                   forKey: [NSString stringWithUTF8String: name]];
3781           }
3782         [cl writeToFile: nil];
3783       }
3784   }
3786   {
3787     char c[128];
3788 #ifdef NS_IMPL_GNUSTEP
3789     strncpy (c, gnustep_base_version, sizeof (c));
3790 #else
3791     /*PSnextrelease (128, c); */
3792     snprintf (c, sizeof (c), "%g", NSAppKitVersionNumber);
3793 #endif
3794     Vwindow_system_version = build_string (c);
3795   }
3797   delete_keyboard_wait_descriptor (0);
3799   ns_app_name = [[NSProcessInfo processInfo] processName];
3801 /* Set up OS X app menu */
3802 #ifdef NS_IMPL_COCOA
3803   {
3804     NSMenu *appMenu;
3805     NSMenuItem *item;
3806     /* set up the application menu */
3807     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
3808     [svcsMenu setAutoenablesItems: NO];
3809     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
3810     [appMenu setAutoenablesItems: NO];
3811     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
3812     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
3814     [appMenu insertItemWithTitle: @"About Emacs"
3815                           action: @selector (orderFrontStandardAboutPanel:)
3816                    keyEquivalent: @""
3817                          atIndex: 0];
3818     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
3819     [appMenu insertItemWithTitle: @"Preferences..."
3820                           action: @selector (showPreferencesWindow:)
3821                    keyEquivalent: @","
3822                          atIndex: 2];
3823     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
3824     item = [appMenu insertItemWithTitle: @"Services"
3825                                  action: @selector (menuDown:)
3826                           keyEquivalent: @""
3827                                 atIndex: 4];
3828     [appMenu setSubmenu: svcsMenu forItem: item];
3829     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
3830     [appMenu insertItemWithTitle: @"Hide Emacs"
3831                           action: @selector (hide:)
3832                    keyEquivalent: @"h"
3833                          atIndex: 6];
3834     item =  [appMenu insertItemWithTitle: @"Hide Others"
3835                           action: @selector (hideOtherApplications:)
3836                    keyEquivalent: @"h"
3837                          atIndex: 7];
3838     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
3839     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
3840     [appMenu insertItemWithTitle: @"Quit Emacs"
3841                           action: @selector (terminate:)
3842                    keyEquivalent: @"q"
3843                          atIndex: 9];
3845     item = [mainMenu insertItemWithTitle: ns_app_name                       
3846                                   action: @selector (menuDown:)
3847                            keyEquivalent: @""
3848                                  atIndex: 0];
3849     [mainMenu setSubmenu: appMenu forItem: item];
3850     [dockMenu insertItemWithTitle: @"New Frame"
3851                            action: @selector (newFrame:)
3852                     keyEquivalent: @""
3853                           atIndex: 0];
3855     [NSApp setMainMenu: mainMenu];
3856     [NSApp setAppleMenu: appMenu];
3857     [NSApp setServicesMenu: svcsMenu];
3858     /* Needed at least on Cocoa, to get dock menu to show windows */
3859     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
3860   }
3861 #endif /* MAC OS X menu setup */
3863   [NSApp run];
3865   return dpyinfo;
3869 extern Lisp_Object Vauto_save_list_file_name;
3870 void
3871 ns_term_shutdown (int sig)
3873   /* code not reached in emacs.c after this is called by shut_down_emacs: */
3874   if (STRINGP (Vauto_save_list_file_name))
3875     unlink (SDATA (Vauto_save_list_file_name));
3877   if (sig == 0 || sig == SIGTERM)
3878     {
3879       [NSApp terminate: NSApp];
3880     }
3881   else // force a stack trace to happen
3882     {
3883       abort();
3884     }
3888 /* ==========================================================================
3890     EmacsApp implementation
3892    ========================================================================== */
3895 @implementation EmacsApp
3897 - (void)logNotification: (NSNotification *)notification
3899   const char *name = [[notification name] UTF8String];
3900   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
3901       && !strstr (name, "WindowNumber"))
3902     NSLog (@"notification: '%@'", [notification name]);
3906 - (void)sendEvent: (NSEvent *)theEvent
3907 /* --------------------------------------------------------------------------
3908      Called when NSApp is running for each event received.  Used to stop
3909      the loop when we choose, since there's no way to just run one iteration.
3910    -------------------------------------------------------------------------- */
3912   int type = [theEvent type];
3913   NSWindow *window = [theEvent window];
3914 /*  NSTRACE (sendEvent); */
3915 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
3917   if (type == NSCursorUpdate && window == nil)
3918     {
3919       fprintf (stderr, "Dropping external cursor update event.\n");
3920       return;
3921     }
3923 #ifdef NS_IMPL_COCOA
3924   /* pass mouse down in resize handle and subsequent drags directly to
3925      EmacsWindow so we can generate continuous redisplays */
3926   if (ns_in_resize)
3927     {
3928       if (type == NSLeftMouseDragged)
3929         {
3930           [window mouseDragged: theEvent];
3931           return;
3932         }
3933       else if (type == NSLeftMouseUp)
3934         {
3935           [window mouseUp: theEvent];
3936           return;
3937         }
3938     }
3939   else if (type == NSLeftMouseDown)
3940     {
3941       NSRect r = ns_resize_handle_rect (window);
3942       if (NSPointInRect ([theEvent locationInWindow], r))
3943         {
3944           ns_in_resize = YES;
3945           [window mouseDown: theEvent];
3946           return;
3947         }
3948     }
3949 #endif
3951   if (type == NSApplicationDefined)
3952     {
3953       /* Events posted by ns_send_appdefined interrupt the run loop here.
3954          But, if a modal window is up, an appdefined can still come through,
3955          (e.g., from a makeKeyWindow event) but stopping self also stops the
3956          modal loop. Just defer it until later. */
3957       if ([NSApp modalWindow] == nil)
3958         {
3959           last_appdefined_event = theEvent;
3960           [self stop: self];
3961         }
3962       else
3963         {
3964           send_appdefined = YES;
3965         }
3966     }
3968   [super sendEvent: theEvent];
3972 - (void)showPreferencesWindow: (id)sender
3974   struct frame *emacsframe = SELECTED_FRAME ();
3975   NSEvent *theEvent = [NSApp currentEvent];
3977   if (!emacs_event)
3978     return;
3979   emacs_event->kind = NS_NONKEY_EVENT;
3980   emacs_event->code = KEY_NS_SHOW_PREFS;
3981   emacs_event->modifiers = 0;
3982   EV_TRAILER (theEvent);
3986 - (void)newFrame: (id)sender
3988   struct frame *emacsframe = SELECTED_FRAME ();
3989   NSEvent *theEvent = [NSApp currentEvent];
3991   if (!emacs_event)
3992     return;
3993   emacs_event->kind = NS_NONKEY_EVENT;
3994   emacs_event->code = KEY_NS_NEW_FRAME;
3995   emacs_event->modifiers = 0;
3996   EV_TRAILER (theEvent);
4000 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4001 - (BOOL) openFile: (NSString *)fileName
4003   struct frame *emacsframe = SELECTED_FRAME ();
4004   NSEvent *theEvent = [NSApp currentEvent];
4006   if (!emacs_event)
4007     return NO;
4009   emacs_event->kind = NS_NONKEY_EVENT;
4010   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4011   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4012   ns_input_line = Qnil; /* can be start or cons start,end */
4013   emacs_event->modifiers =0;
4014   EV_TRAILER (theEvent);
4016   return YES;
4020 /* **************************************************************************
4022       EmacsApp delegate implementation
4024    ************************************************************************** */
4026 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4027 /* --------------------------------------------------------------------------
4028      When application is loaded, terminate event loop in ns_term_init
4029    -------------------------------------------------------------------------- */
4031   NSTRACE (applicationDidFinishLaunching);
4032   [NSApp setServicesProvider: NSApp];
4033   ns_send_appdefined (-2);
4037 /* Termination sequences:
4038     C-x C-c:
4039     Cmd-Q:
4040     MenuBar | File | Exit:
4041     Select Quit from App menubar:
4042         -terminate
4043         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4044         ns_term_shutdown()
4046     Select Quit from Dock menu:
4047     Logout attempt:
4048         -appShouldTerminate
4049           Cancel -> Nothing else
4050           Accept ->
4051           
4052           -terminate
4053           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4054           ns_term_shutdown()
4058 - (void) terminate: (id)sender
4060   struct frame *emacsframe = SELECTED_FRAME ();
4061   
4062   if (!emacs_event)
4063     return;
4064   
4065   emacs_event->kind = NS_NONKEY_EVENT;
4066   emacs_event->code = KEY_NS_POWER_OFF;
4067   emacs_event->arg = Qt; /* mark as non-key event */
4068   EV_TRAILER ((id)nil);
4072 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4074   int ret;
4076   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4077     return NSTerminateNow;
4079     ret = NSRunAlertPanel(ns_app_name,
4080                           [NSString stringWithUTF8String:"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?"],
4081                           @"Save Buffers and Exit", @"Cancel", nil);
4083     if (ret == NSAlertDefaultReturn)
4084         return NSTerminateNow;
4085     else if (ret == NSAlertAlternateReturn)
4086         return NSTerminateCancel;
4087     return NSTerminateNow;  /* just in case */
4091 /*   Notification from the Workspace to open a file */
4092 - (BOOL)application: sender openFile: (NSString *)file
4094   [ns_pending_files addObject: file];
4095   return YES;
4099 /*   Open a file as a temporary file */
4100 - (BOOL)application: sender openTempFile: (NSString *)file
4102   [ns_pending_files addObject: file];
4103   return YES;
4107 /*   Notification from the Workspace to open a file noninteractively (?) */
4108 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4110   [ns_pending_files addObject: file];
4111   return YES;
4115 /*   Notification from the Workspace to open multiple files */
4116 - (void)application: sender openFiles: (NSArray *)fileList
4118   NSEnumerator *files = [fileList objectEnumerator];
4119   NSString *file;
4120   while ((file = [files nextObject]) != nil)
4121     [ns_pending_files addObject: file];
4123   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4128 /* Handle dock menu requests.  */
4129 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4131   return dockMenu;
4135 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4136 - (void)applicationWillBecomeActive: (NSNotification *)notification
4138   //ns_app_active=YES;
4140 - (void)applicationDidBecomeActive: (NSNotification *)notification
4142   //ns_app_active=YES;
4144 - (void)applicationDidResignActive: (NSNotification *)notification
4146   //ns_app_active=NO;
4147   ns_send_appdefined (-1);
4152 /* ==========================================================================
4154     EmacsApp aux handlers for managing event loop
4156    ========================================================================== */
4159 - (void)timeout_handler: (NSTimer *)timedEntry
4160 /* --------------------------------------------------------------------------
4161      The timeout specified to ns_select has passed.
4162    -------------------------------------------------------------------------- */
4164   /*NSTRACE (timeout_handler); */
4165   ns_send_appdefined (-2);
4168 - (void)fd_handler: (NSTimer *) fdEntry
4169 /* --------------------------------------------------------------------------
4170      Check data waiting on file descriptors and terminate if so
4171    -------------------------------------------------------------------------- */
4173   int result;
4174   /* NSTRACE (fd_handler); */
4176   if (select_nfds == 0)
4177     return;
4179   memcpy (&t_readfds, &select_readfds, sizeof (fd_set));
4181   select_timeout.tv_sec = select_timeout.tv_usec = 0;
4182   result = select (select_nfds, &t_readfds, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
4183                   &select_timeout);
4184   if (result)
4185     {
4186       memcpy (&select_readfds, &t_readfds, sizeof (fd_set));
4187       ns_send_appdefined (result);
4188     }
4193 /* ==========================================================================
4195     Service provision
4197    ========================================================================== */
4199 /* called from system: queue for next pass through event loop */
4200 - (void)requestService: (NSPasteboard *)pboard
4201               userData: (NSString *)userData
4202                  error: (NSString **)error
4204   [ns_pending_service_names addObject: userData];
4205   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4206       SDATA (ns_string_from_pasteboard (pboard))]];
4210 /* called from ns_read_socket to clear queue */
4211 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4213   struct frame *emacsframe = SELECTED_FRAME ();
4214   NSEvent *theEvent = [NSApp currentEvent];
4216   if (!emacs_event)
4217     return NO;
4219   emacs_event->kind = NS_NONKEY_EVENT;
4220   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4221   ns_input_spi_name = build_string ([name UTF8String]);
4222   ns_input_spi_arg = build_string ([arg UTF8String]);
4223   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4224   EV_TRAILER (theEvent);
4226   return YES;
4230 @end  /* EmacsApp */
4234 /* ==========================================================================
4236     EmacsView implementation
4238    ========================================================================== */
4241 @implementation EmacsView
4243 /* needed to inform when window closed from LISP */
4244 - (void) setWindowClosing: (BOOL)closing
4246   windowClosing = closing;
4250 - (void)dealloc
4252   NSTRACE (EmacsView_dealloc);
4253   [toolbar release];
4254   [super dealloc];
4258 /* called on font panel selection */
4259 - (void)changeFont: (id)sender
4261   NSEvent *e =[[self window] currentEvent];
4262   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4263   id newFont;
4264   float size;
4266   NSTRACE (changeFont);
4267   if (!emacs_event)
4268     return;
4270   if (newFont = [sender convertFont:
4271                            ((struct nsfont_info *)face->font)->nsfont])
4272     {
4273       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4275       emacs_event->kind = NS_NONKEY_EVENT;
4276       emacs_event->modifiers = 0;
4277       emacs_event->code = KEY_NS_CHANGE_FONT;
4279       size = [newFont pointSize];
4280       ns_input_fontsize = make_number (lrint (size));
4281       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4282       EV_TRAILER (e);
4283     }
4287 - (BOOL)acceptsFirstResponder
4289   NSTRACE (acceptsFirstResponder);
4290   return YES;
4294 - (void)resetCursorRects
4296   NSRect visible = [self visibleRect];
4297   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4298   NSTRACE (resetCursorRects);
4300   if (currentCursor == nil)
4301     currentCursor = [NSCursor arrowCursor];
4303   if (!NSIsEmptyRect (visible))
4304     [self addCursorRect: visible cursor: currentCursor];
4305   [currentCursor setOnMouseEntered: YES];
4310 /*****************************************************************************/
4311 /* Keyboard handling. */
4312 #define NS_KEYLOG 0
4314 - (void)keyDown: (NSEvent *)theEvent
4316   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
4317   int code;
4318   unsigned fnKeysym = 0;
4319   int flags;
4320   static NSMutableArray *nsEvArray;
4321   static BOOL firstTime = YES;
4323   NSTRACE (keyDown);
4325   /* Rhapsody and OS X give up and down events for the arrow keys */
4326   if (ns_fake_keydown == YES)
4327     ns_fake_keydown = NO;
4328   else if ([theEvent type] != NSKeyDown)
4329     return;
4331   if (!emacs_event)
4332     return;
4334  if (![[self window] isKeyWindow]
4335      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4336      /* we must avoid an infinite loop here. */
4337      && (EmacsView *)[[theEvent window] delegate] != self)
4338    {
4339      /* XXX: There is an occasional condition in which, when Emacs display
4340          updates a different frame from the current one, and temporarily
4341          selects it, then processes some interrupt-driven input
4342          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4343          for some reason that window has its first responder set to the NSView
4344          most recently updated (I guess), which is not the correct one. */
4345      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4346      return;
4347    }
4349   if (nsEvArray == nil)
4350     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4352   [NSCursor setHiddenUntilMouseMoves: YES];
4354   if (dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4355     {
4356       clear_mouse_face (dpyinfo);
4357       dpyinfo->mouse_face_hidden = 1;
4358     }
4360   if (!processingCompose)
4361     {
4362       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4363         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4364       /* (Carbon way: [theEvent keyCode]) */
4366       /* is it a "function key"? */
4367       fnKeysym = ns_convert_key (code);
4368       if (fnKeysym)
4369         {
4370           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4371              because Emacs treats Delete and KP-Delete same (in simple.el). */
4372           if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4373             code = 0xFF08; /* backspace */
4374           else
4375             code = fnKeysym;
4376         }
4378       /* are there modifiers? */
4379       emacs_event->modifiers = 0;
4380       flags = [theEvent modifierFlags];
4382       if (flags & NSHelpKeyMask)
4383           emacs_event->modifiers |= hyper_modifier;
4385       if (flags & NSShiftKeyMask)
4386         emacs_event->modifiers |= shift_modifier;
4388       if (flags & NSCommandKeyMask)
4389         {
4390           emacs_event->modifiers |= parse_solitary_modifier (ns_command_modifier);
4391           /* if super (default), take input manager's word so things like
4392              dvorak / qwerty layout work */
4393           if (EQ (ns_command_modifier, Qsuper)
4394               && !fnKeysym
4395               && [[theEvent characters] length] != 0)
4396             {
4397               /* XXX: the code we get will be unshifted, so if we have
4398                  a shift modifier, must convert ourselves */
4399               if (!(flags & NSShiftKeyMask))
4400                 code = [[theEvent characters] characterAtIndex: 0];
4401 #if 0
4402               /* this is ugly and also requires linking w/Carbon framework
4403                  (for LMGetKbdType) so for now leave this rare (?) case
4404                  undealt with.. in future look into CGEvent methods */
4405               else
4406                 {
4407                   long smv = GetScriptManagerVariable (smKeyScript);
4408                   Handle uchrHandle = GetResource
4409                     ('uchr', GetScriptVariable (smv, smScriptKeys));
4410                   UInt32 dummy = 0;
4411                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
4412                                  [[theEvent characters] characterAtIndex: 0],
4413                                  kUCKeyActionDisplay,
4414                                  (flags & ~NSCommandKeyMask) >> 8,
4415                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
4416                                  &dummy, 1, &dummy, &code);
4417                   code &= 0xFF;
4418                 }
4419 #endif
4420             }
4421         }
4423       if (flags & NSControlKeyMask)
4424           emacs_event->modifiers |=
4425             parse_solitary_modifier (ns_control_modifier);
4427       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
4428           emacs_event->modifiers |=
4429             parse_solitary_modifier (ns_function_modifier);
4431       if (flags & NSAlternateKeyMask) /* default = meta */
4432         {
4433           if ((NILP (ns_alternate_modifier) || EQ (ns_alternate_modifier, Qnone))
4434               && !fnKeysym)
4435             {   /* accept pre-interp alt comb */
4436               if ([[theEvent characters] length] > 0)
4437                 code = [[theEvent characters] characterAtIndex: 0];
4438               /*HACK: clear lone shift modifier to stop next if from firing */
4439               if (emacs_event->modifiers == shift_modifier)
4440                 emacs_event->modifiers = 0;
4441             }
4442           else
4443               emacs_event->modifiers |=
4444                 parse_solitary_modifier (ns_alternate_modifier);
4445         }
4447   if (NS_KEYLOG)
4448     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
4449              code, fnKeysym, flags, emacs_event->modifiers);
4451       /* if it was a function key or had modifiers, pass it directly to emacs */
4452       if (fnKeysym || (emacs_event->modifiers
4453                        && [[theEvent charactersIgnoringModifiers] length] > 0))
4454 /*[[theEvent characters] length] */
4455         {
4456           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4457           if (code < 0x20)
4458             code |= (1<<28)|(3<<16);
4459           else if (code == 0x7f)
4460             code |= (1<<28)|(3<<16);
4461           else if (!fnKeysym)
4462             emacs_event->kind = code > 0xFF
4463               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4465           emacs_event->code = code;
4466           EV_TRAILER (theEvent);
4467           return;
4468         }
4469     }
4471   /* if we get here we should send the key for input manager processing */
4472   if (firstTime && [[NSInputManager currentInputManager]
4473                      wantsToDelayTextChangeNotifications] == NO)
4474     fprintf (stderr,
4475           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
4476   firstTime = NO;
4478   if (NS_KEYLOG && !processingCompose)
4479     fprintf (stderr, "keyDown: Begin compose sequence.\n");
4481   processingCompose = YES;
4482   [nsEvArray addObject: theEvent];
4483   [self interpretKeyEvents: nsEvArray];
4484   [nsEvArray removeObject: theEvent];
4488 #ifdef NS_IMPL_COCOA
4489 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
4490    decided not to send key-down for.
4491    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
4492    This only applies on Tiger and earlier.
4493    If it matches one of these, send it on to keyDown. */
4494 -(void)keyUp: (NSEvent *)theEvent
4496   int flags = [theEvent modifierFlags];
4497   int code = [theEvent keyCode];
4498   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
4499       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
4500     {
4501       if (NS_KEYLOG)
4502         fprintf (stderr, "keyUp: passed test");
4503       ns_fake_keydown = YES;
4504       [self keyDown: theEvent];
4505     }
4507 #endif
4510 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
4513 /* <NSTextInput>: called when done composing;
4514    NOTE: also called when we delete over working text, followed immed.
4515          by doCommandBySelector: deleteBackward: */
4516 - (void)insertText: (id)aString
4518   int code;
4519   int len = [(NSString *)aString length];
4520   int i;
4522   if (NS_KEYLOG)
4523     NSLog (@"insertText '%@'\tlen = %d", aString, len);
4524   processingCompose = NO;
4526   if (!emacs_event)
4527     return;
4529   /* first, clear any working text */
4530   if (workingText != nil)
4531     [self deleteWorkingText];
4533   /* now insert the string as keystrokes */
4534   for (i =0; i<len; i++)
4535     {
4536       code = [aString characterAtIndex: i];
4537       /* TODO: still need this? */
4538       if (code == 0x2DC)
4539         code = '~'; /* 0x7E */
4540       emacs_event->modifiers = 0;
4541       emacs_event->kind
4542         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4543       emacs_event->code = code;
4544       EV_TRAILER ((id)nil);
4545     }
4549 /* <NSTextInput>: inserts display of composing characters */
4550 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
4552   NSString *str = [aString respondsToSelector: @selector (string)] ?
4553     [aString string] : aString;
4554   if (NS_KEYLOG)
4555     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
4556            selRange.length, selRange.location);
4558   if (workingText != nil)
4559     [self deleteWorkingText];
4560   if ([str length] == 0)
4561     return;
4563   if (!emacs_event)
4564     return;
4566   processingCompose = YES;
4567   workingText = [str copy];
4568   ns_working_text = build_string ([workingText UTF8String]);
4570   emacs_event->kind = NS_TEXT_EVENT;
4571   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
4572   EV_TRAILER ((id)nil);
4576 /* delete display of composing characters [not in <NSTextInput>] */
4577 - (void)deleteWorkingText
4579   if (workingText == nil)
4580     return;
4581   if (NS_KEYLOG)
4582     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
4583   [workingText release];
4584   workingText = nil;
4585   processingCompose = NO;
4587   if (!emacs_event)
4588     return;
4590   emacs_event->kind = NS_TEXT_EVENT;
4591   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
4592   EV_TRAILER ((id)nil);
4596 - (BOOL)hasMarkedText
4598   return workingText != nil;
4602 - (NSRange)markedRange
4604   NSRange rng = workingText != nil
4605     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
4606   if (NS_KEYLOG)
4607     NSLog (@"markedRange request");
4608   return rng;
4612 - (void)unmarkText
4614   if (NS_KEYLOG)
4615     NSLog (@"unmark (accept) text");
4616   [self deleteWorkingText];
4617   processingCompose = NO;
4621 /* used to position char selection windows, etc. */
4622 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
4624   NSRect rect;
4625   NSPoint pt;
4626   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
4627   if (NS_KEYLOG)
4628     NSLog (@"firstRectForCharRange request");
4630   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
4631   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
4632   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
4633   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
4634                                        +FRAME_LINE_HEIGHT (emacsframe));
4636   pt = [self convertPoint: pt toView: nil];
4637   pt = [[self window] convertBaseToScreen: pt];
4638   rect.origin = pt;
4639   return rect;
4643 - (long)conversationIdentifier
4645   return (long)self;
4649 - (void)doCommandBySelector: (SEL)aSelector
4651   if (NS_KEYLOG)
4652     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
4654   if (aSelector == @selector (deleteBackward:))
4655     {
4656       /* happens when user backspaces over an ongoing composition:
4657          throw a 'delete' into the event queue */
4658       if (!emacs_event)
4659         return;
4660       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4661       emacs_event->code = 0xFF08;
4662       EV_TRAILER ((id)nil);
4663     }
4666 - (NSArray *)validAttributesForMarkedText
4668   static NSArray *arr = nil;
4669   if (arr == nil) arr = [NSArray new];
4670  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
4671   return arr;
4674 - (NSRange)selectedRange
4676   if (NS_KEYLOG)
4677     NSLog (@"selectedRange request");
4678   return NSMakeRange (NSNotFound, 0);
4681 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
4683   if (NS_KEYLOG)
4684     NSLog (@"characterIndexForPoint request");
4685   return 0;
4688 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
4690   static NSAttributedString *str = nil;
4691   if (str == nil) str = [NSAttributedString new];
4692   if (NS_KEYLOG)
4693     NSLog (@"attributedSubstringFromRange request");
4694   return str;
4697 /* End <NSTextInput> impl. */
4698 /*****************************************************************************/
4701 /* This is what happens when the user presses a mouse button.  */
4702 - (void)mouseDown: (NSEvent *)theEvent
4704   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
4705   Lisp_Object window;
4707   NSTRACE (mouseDown);
4709   [self deleteWorkingText];
4711   if (!emacs_event)
4712     return;
4714   last_mouse_frame = emacsframe;
4715   /* appears to be needed to prevent spurious movement events generated on
4716      button clicks */
4717   last_mouse_frame->mouse_moved = 0;
4719   if ([theEvent type] == NSScrollWheel)
4720     {
4721       float delta = [theEvent deltaY];
4722       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
4723       if (delta == 0)
4724         return;
4725       emacs_event->kind = WHEEL_EVENT;
4726       emacs_event->code = 0;
4727       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
4728         ((delta > 0) ? up_modifier : down_modifier);
4729     }
4730   else
4731     {
4732       emacs_event->kind = MOUSE_CLICK_EVENT;
4733       emacs_event->code = EV_BUTTON (theEvent);
4734       emacs_event->modifiers = EV_MODIFIERS (theEvent)
4735                              | EV_UDMODIFIERS (theEvent);
4736     }
4737   XSETINT (emacs_event->x, lrint (p.x));
4738   XSETINT (emacs_event->y, lrint (p.y));
4739   EV_TRAILER (theEvent);
4743 - (void)rightMouseDown: (NSEvent *)theEvent
4745   NSTRACE (rightMouseDown);
4746   [self mouseDown: theEvent];
4750 - (void)otherMouseDown: (NSEvent *)theEvent
4752   NSTRACE (otherMouseDown);
4753   [self mouseDown: theEvent];
4757 - (void)mouseUp: (NSEvent *)theEvent
4759   NSTRACE (mouseUp);
4760   [self mouseDown: theEvent];
4764 - (void)rightMouseUp: (NSEvent *)theEvent
4766   NSTRACE (rightMouseUp);
4767   [self mouseDown: theEvent];
4771 - (void)otherMouseUp: (NSEvent *)theEvent
4773   NSTRACE (otherMouseUp);
4774   [self mouseDown: theEvent];
4778 - (void) scrollWheel: (NSEvent *)theEvent
4780   NSTRACE (scrollWheel);
4781   [self mouseDown: theEvent];
4785 /* Tell emacs the mouse has moved. */
4786 - (void)mouseMoved: (NSEvent *)e
4788   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
4789   Lisp_Object frame;
4791 //  NSTRACE (mouseMoved);
4793   last_mouse_movement_time = EV_TIMESTAMP (e);
4794   last_mouse_motion_position
4795     = [self convertPoint: [e locationInWindow] fromView: nil];
4797   /* update any mouse face */
4798   if (dpyinfo->mouse_face_hidden)
4799     {
4800       dpyinfo->mouse_face_hidden = 0;
4801       clear_mouse_face (dpyinfo);
4802     }
4804   /* tooltip handling */
4805   previous_help_echo_string = help_echo_string;
4806   help_echo_string = Qnil;
4808   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
4809                             last_mouse_motion_position.y))
4810     help_echo_string = previous_help_echo_string;
4812   XSETFRAME (frame, emacsframe);
4813   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
4814     {
4815       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
4816          (note_mouse_highlight), which is called through the
4817          note_mouse_movement () call above */
4818       gen_help_event (help_echo_string, frame, help_echo_window,
4819                       help_echo_object, help_echo_pos);
4820     }
4821   else
4822     {
4823       help_echo_string = Qnil;
4824       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
4825     }
4827   if (emacsframe->mouse_moved && send_appdefined)
4828     ns_send_appdefined (-1);
4832 - (void)mouseDragged: (NSEvent *)e
4834   NSTRACE (mouseDragged);
4835   [self mouseMoved: e];
4839 - (void)rightMouseDragged: (NSEvent *)e
4841   NSTRACE (rightMouseDragged);
4842   [self mouseMoved: e];
4846 - (void)otherMouseDragged: (NSEvent *)e
4848   NSTRACE (otherMouseDragged);
4849   [self mouseMoved: e];
4853 - (BOOL)windowShouldClose: (id)sender
4855   NSEvent *e =[[self window] currentEvent];
4857   NSTRACE (windowShouldClose);
4858   windowClosing = YES;
4859   if (!emacs_event)
4860     return NO;
4861   emacs_event->kind = DELETE_WINDOW_EVENT;
4862   emacs_event->modifiers = 0;
4863   emacs_event->code = 0;
4864   EV_TRAILER (e);
4865   /* Don't close this window, let this be done from lisp code.  */
4866   return NO;
4870 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
4871 /* normalize frame to gridded text size */
4873   NSTRACE (windowWillResize);
4874 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
4876   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
4877 #ifdef NS_IMPL_GNUSTEP
4878                                         frameSize.width + 3);
4879 #else
4880                                         frameSize.width);
4881 #endif
4882   if (cols < MINWIDTH)
4883     cols = MINWIDTH;
4884   frameSize.width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (emacsframe, cols);
4886   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, frameSize.height
4887 #ifdef NS_IMPL_GNUSTEP
4888       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + 3
4889         - FRAME_TOOLBAR_HEIGHT (emacsframe));
4890 #else
4891       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
4892         - FRAME_TOOLBAR_HEIGHT (emacsframe));
4893 #endif
4894   if (rows < MINHEIGHT)
4895     rows = MINHEIGHT;
4896   frameSize.height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows)
4897                        + FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
4898                        + FRAME_TOOLBAR_HEIGHT (emacsframe);
4899 #ifdef NS_IMPL_COCOA
4900   {
4901     /* this sets window title to have size in it; the wm does this under GS */
4902     NSRect r = [[self window] frame];
4903     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
4904       {
4905         if (old_title != 0)
4906           {
4907             xfree (old_title);
4908             old_title = 0;
4909           }
4910       }
4911     else
4912       {
4913         char *size_title;
4914         NSWindow *window = [self window];
4915         if (old_title == 0)
4916           {
4917             const char *t = [[[self window] title] UTF8String];
4918             char *pos = strstr (t, "  â€”  ");
4919             if (pos)
4920               *pos = '\0';
4921             old_title = (char *) xmalloc (strlen (t) + 1);
4922             strcpy (old_title, t);
4923           }
4924         size_title = xmalloc (strlen (old_title) + 40);
4925         sprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
4926         [window setTitle: [NSString stringWithUTF8String: size_title]];
4927         [window display];
4928         xfree (size_title);
4929       }
4930   }
4931 #endif /* NS_IMPL_COCOA */
4932 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
4934   return frameSize;
4938 - (void)windowDidResize: (NSNotification *)notification
4940   NSWindow *theWindow = [notification object];
4942 #ifdef NS_IMPL_GNUSTEP
4943    /* in GNUstep, at least currently, it's possible to get a didResize
4944       without getting a willResize.. therefore we need to act as if we got
4945       the willResize now */
4946   NSSize sz = [theWindow frame].size;
4947   sz = [self windowWillResize: theWindow toSize: sz];
4948 #endif /* NS_IMPL_GNUSTEP */
4950   NSTRACE (windowDidResize);
4951 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
4953 #ifdef NS_IMPL_COCOA
4954   if (old_title != 0)
4955     {
4956       xfree (old_title);
4957       old_title = 0;
4958     }
4959 #endif /* NS_IMPL_COCOA */
4961   /* Avoid loop under GNUstep due to call at beginning of this function.
4962      (x_set_window_size causes a resize which causes
4963      a "windowDidResize" which calls x_set_window_size).  */
4964 #ifndef NS_IMPL_GNUSTEP
4965   if (cols > 0 && rows > 0)
4966      x_set_window_size (emacsframe, 0, cols, rows);
4967 #endif
4969   ns_send_appdefined (-1);
4973 - (void)windowDidBecomeKey: (NSNotification *)notification
4974 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
4976   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
4977   struct frame *old_focus = dpyinfo->x_focus_frame;
4979   NSTRACE (windowDidBecomeKey);
4981   if (emacsframe != old_focus)
4982     dpyinfo->x_focus_frame = emacsframe;
4984   ns_frame_rehighlight (emacsframe);
4986   if (emacs_event)
4987     {
4988       emacs_event->kind = FOCUS_IN_EVENT;
4989       EV_TRAILER ((id)nil);
4990     }
4994 - (void)windowDidResignKey: (NSNotification *)notification
4995 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
4997   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
4998   NSTRACE (windowDidResignKey);
5000   if (dpyinfo->x_focus_frame == emacsframe)
5001     dpyinfo->x_focus_frame = 0;
5003   ns_frame_rehighlight (emacsframe);
5005   /* FIXME: for some reason needed on second and subsequent clicks away
5006             from sole-frame Emacs to get hollow box to show */
5007   if (!windowClosing && [[self window] isVisible] == YES)
5008     {
5009       x_update_cursor (emacsframe, 1);
5010       x_set_frame_alpha (emacsframe);
5011     }
5013   if (emacs_event)
5014     {
5015       [self deleteWorkingText];
5016       emacs_event->kind = FOCUS_IN_EVENT;
5017       EV_TRAILER ((id)nil);
5018     }
5022 - (void)windowWillMiniaturize: sender
5024   NSTRACE (windowWillMiniaturize);
5028 - (BOOL)isFlipped
5030   return YES;
5034 - (BOOL)isOpaque
5036   return NO;
5040 - initFrameFromEmacs: (struct frame *)f
5042   NSRect r, wr;
5043   Lisp_Object tem;
5044   NSWindow *win;
5045   NSButton *toggleButton;
5046   int vbextra = NS_SCROLL_BAR_WIDTH (f);
5047   NSSize sz;
5048   NSColor *col;
5049   NSString *name;
5051   NSTRACE (initFrameFromEmacs);
5053   windowClosing = NO;
5054   processingCompose = NO;
5055   scrollbarsNeedingUpdate = 0;
5057 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5059   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5060                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5061   [self initWithFrame: r];
5062   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5064   FRAME_NS_VIEW (f) = self;
5065   emacsframe = f;
5066   old_title = 0;
5068   win = [[EmacsWindow alloc]
5069             initWithContentRect: r
5070                       styleMask: (NSResizableWindowMask |
5071                                   NSMiniaturizableWindowMask |
5072                                   NSClosableWindowMask)
5073                         backing: NSBackingStoreBuffered
5074                           defer: YES];
5076   wr = [win frame];
5077   f->border_width = wr.size.width - r.size.width;
5078   FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5080   [win setAcceptsMouseMovedEvents: YES];
5081   [win setDelegate: self];
5082   [win useOptimizedDrawing: YES];
5084   sz.width = FRAME_COLUMN_WIDTH (f);
5085   sz.height = FRAME_LINE_HEIGHT (f);
5086   [win setResizeIncrements: sz];
5088   [[win contentView] addSubview: self];
5090   if (ns_drag_types)
5091     [self registerForDraggedTypes: ns_drag_types];
5093   tem = f->name;
5094   name = [NSString stringWithUTF8String:
5095                    NILP (tem) ? (unsigned char *)"Emacs" : SDATA (tem)];
5096   [win setTitle: name];
5098   /* toolbar support */
5099   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5100                          [NSString stringWithFormat: @"Emacs Frame %d",
5101                                    ns_window_num]];
5102   [win setToolbar: toolbar];
5103   [toolbar setVisible: NO];
5104 #ifdef NS_IMPL_COCOA
5105   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5106   [toggleButton setTarget: self];
5107   [toggleButton setAction: @selector (toggleToolbar: )];
5108 #endif
5109   FRAME_TOOLBAR_HEIGHT (f) = 0;
5111   tem = f->icon_name;
5112   if (!NILP (tem))
5113     [win setMiniwindowTitle:
5114            [NSString stringWithUTF8String: SDATA (tem)]];
5116   {
5117     NSScreen *screen = [win screen];
5119     if (screen != 0)
5120       [win setFrameTopLeftPoint: NSMakePoint
5121            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5122             IN_BOUND (-SCREENMAX,
5123                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5124   }
5126   [win makeFirstResponder: self];
5128   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5129                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5130   [win setBackgroundColor: col];
5131   if ([col alphaComponent] != 1.0)
5132     [win setOpaque: NO];
5134   [self allocateGState];
5136   ns_window_num++;
5137   return self;
5141 - (void)windowDidMove: sender
5143   NSWindow *win = [self window];
5144   NSRect r = [win frame];
5145   NSScreen *screen = [win screen];
5147   NSTRACE (windowDidMove);
5149   if (!emacsframe->output_data.ns)
5150     return;
5151   if (screen != nil)
5152     {
5153       emacsframe->left_pos = r.origin.x;
5154       emacsframe->top_pos =
5155         [screen frame].size.height - (r.origin.y + r.size.height);
5156     }
5160 /* Called AFTER method below, but before our windowWillResize call there leads
5161    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5162    location so set_window_size moves the frame. */
5163 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5165   NSTRACE (windowShouldZoom);
5166   emacsframe->left_pos = (int)newFrame.origin.x;
5167   emacsframe->top_pos = [[sender screen] frame].size.height
5168                             - (newFrame.origin.y+newFrame.size.height);
5169   return YES;
5173 /* Override to do something slightly nonstandard, but nice.  First click on
5174    zoom button will zoom vertically.  Second will zoom completely.  Third
5175    returns to original. */
5176 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5177                         defaultFrame:(NSRect)defaultFrame
5179   NSRect result = [sender frame];
5180   static NSRect ns_userRect = { 0, 0, 0, 0 };
5182   NSTRACE (windowWillUseStandardFrame);
5184   if (abs (defaultFrame.size.height - result.size.height)
5185       > FRAME_LINE_HEIGHT (emacsframe))
5186     {
5187       /* first click */
5188       ns_userRect = result;
5189       result.size.height = defaultFrame.size.height;
5190       result.origin.y = defaultFrame.origin.y;
5191     }
5192   else
5193     {
5194       if (abs (defaultFrame.size.width - result.size.width)
5195           > FRAME_COLUMN_WIDTH (emacsframe))
5196         result = defaultFrame;  /* second click */
5197       else
5198         result = ns_userRect.size.height ? ns_userRect : result;  /* restore */
5199     }
5201   [self windowWillResize: sender toSize: result.size];
5202   return result;
5206 - (void)windowDidDeminiaturize: sender
5208   NSTRACE (windowDidDeminiaturize);
5209   if (!emacsframe->output_data.ns)
5210     return;
5211   emacsframe->async_iconified = 0;
5212   emacsframe->async_visible   = 1;
5213   windows_or_buffers_changed++;
5215   if (emacs_event)
5216     {
5217       emacs_event->kind = ICONIFY_EVENT;
5218       EV_TRAILER ((id)nil);
5219     }
5223 - (void)windowDidExpose: sender
5225   NSTRACE (windowDidExpose);
5226   if (!emacsframe->output_data.ns)
5227     return;
5228   emacsframe->async_visible = 1;
5229   SET_FRAME_GARBAGED (emacsframe);
5231   if (send_appdefined)
5232     ns_send_appdefined (-1);
5236 - (void)windowDidMiniaturize: sender
5238   NSTRACE (windowDidMiniaturize);
5239   if (!emacsframe->output_data.ns)
5240     return;
5242   emacsframe->async_iconified = 1;
5243   emacsframe->async_visible = 0;
5245   if (emacs_event)
5246     {
5247       emacs_event->kind = ICONIFY_EVENT;
5248       EV_TRAILER ((id)nil);
5249     }
5253 - (void)mouseEntered: (NSEvent *)theEvent
5255   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5256   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5257   NSTRACE (mouseEntered);
5259   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5263 - (void)mouseExited: (NSEvent *)theEvent
5265   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5266   NSRect r;
5267   struct ns_display_info *dpyinfo
5268     = emacsframe ? FRAME_NS_DISPLAY_INFO (emacsframe) : NULL;
5270   NSTRACE (mouseExited);
5272   if (dpyinfo || !emacsframe)
5273     return;
5275   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5277   if (emacsframe == dpyinfo->mouse_face_mouse_frame)
5278     {
5279       clear_mouse_face (dpyinfo);
5280       dpyinfo->mouse_face_mouse_frame = 0;
5281     }
5285 - menuDown: sender
5287   NSTRACE (menuDown);
5288   if (context_menu_value == -1)
5289     context_menu_value = [sender tag];
5290   else
5291     find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
5292                                   emacsframe->menu_bar_vector,
5293                                   (void *)[sender tag]);
5294   ns_send_appdefined (-1);
5295   return self;
5299 - (EmacsToolbar *)toolbar
5301   return toolbar;
5305 /* this gets called on toolbar button click */
5306 - toolbarClicked: (id)item
5308   NSEvent *theEvent;
5309   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
5311   NSTRACE (toolbarClicked);
5313   if (!emacs_event)
5314     return self;
5316   /* send first event (for some reason two needed) */
5317   theEvent = [[self window] currentEvent];
5318   emacs_event->kind = TOOL_BAR_EVENT;
5319   XSETFRAME (emacs_event->arg, emacsframe);
5320   EV_TRAILER (theEvent);
5322   emacs_event->kind = TOOL_BAR_EVENT;
5323 /*   XSETINT (emacs_event->code, 0); */
5324   emacs_event->arg = AREF (emacsframe->tool_bar_items,
5325                           idx + TOOL_BAR_ITEM_KEY);
5326   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5327   EV_TRAILER (theEvent);
5328   return self;
5332 - toggleToolbar: (id)sender
5334   if (!emacs_event)
5335     return self;
5337   emacs_event->kind = NS_NONKEY_EVENT;
5338   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
5339   EV_TRAILER ((id)nil);
5340   return self;
5344 - (void)drawRect: (NSRect)rect
5346   int x = NSMinX (rect), y = NSMinY (rect);
5347   int width = NSWidth (rect), height = NSHeight (rect);
5349   NSTRACE (drawRect);
5351   if (!emacsframe || !emacsframe->output_data.ns || ns_in_resize)
5352     return;
5354   ns_clear_frame_area (emacsframe, x, y, width, height);
5355   expose_frame (emacsframe, x, y, width, height);
5357   /*
5358     drawRect: may be called (at least in OS X 10.5) for invisible
5359     views as well for some reason.  Thus, do not infer visibility 
5360     here.
5362     emacsframe->async_visible = 1;
5363     emacsframe->async_iconified = 0;
5364   */
5368 /* NSDraggingDestination protocol methods.  Actually this is not really a
5369    protocol, but a category of Object.  O well...  */
5371 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
5373   NSTRACE (draggingEntered);
5374   return NSDragOperationGeneric;
5378 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
5380   return YES;
5384 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
5386   id pb;
5387   int x, y;
5388   NSString *type;
5389   NSEvent *theEvent = [[self window] currentEvent];
5390   NSPoint position;
5392   NSTRACE (performDragOperation);
5394   if (!emacs_event)
5395     return;
5397   position = [self convertPoint: [sender draggingLocation] fromView: nil];
5398   x = lrint (position.x);  y = lrint (position.y);
5400   pb = [sender draggingPasteboard];
5401   type = [pb availableTypeFromArray: ns_drag_types];
5402   if (type == 0)
5403     {
5404       return NO;
5405     }
5406   else if ([type isEqualToString: NSFilenamesPboardType])
5407     {
5408       NSArray *files;
5409       NSEnumerator *fenum;
5410       NSString *file;
5412       if (!(files = [pb propertyListForType: type]))
5413         return NO;
5415       fenum = [files objectEnumerator];
5416       while ( (file = [fenum nextObject]) )
5417         {
5418           emacs_event->kind = NS_NONKEY_EVENT;
5419           emacs_event->code = KEY_NS_DRAG_FILE;
5420           XSETINT (emacs_event->x, x);
5421           XSETINT (emacs_event->y, y);
5422           ns_input_file = append2 (ns_input_file,
5423                                    build_string ([file UTF8String]));
5424           emacs_event->modifiers = EV_MODIFIERS (theEvent);
5425           EV_TRAILER (theEvent);
5426         }
5427       return YES;
5428     }
5429   else if ([type isEqualToString: NSURLPboardType])
5430     {
5431       NSString *file;
5432       NSURL *fileURL;
5434       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
5435           [fileURL isFileURL] == NO)
5436         return NO;
5438       file = [fileURL path];
5439       emacs_event->kind = NS_NONKEY_EVENT;
5440       emacs_event->code = KEY_NS_DRAG_FILE;
5441       XSETINT (emacs_event->x, x);
5442       XSETINT (emacs_event->y, y);
5443       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
5444       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5445       EV_TRAILER (theEvent);
5446       return YES;
5447     }
5448   else if ([type isEqualToString: NSStringPboardType]
5449            || [type isEqualToString: NSTabularTextPboardType])
5450     {
5451       NSString *data;
5453       if (! (data = [pb stringForType: type]))
5454         return NO;
5456       emacs_event->kind = NS_NONKEY_EVENT;
5457       emacs_event->code = KEY_NS_DRAG_TEXT;
5458       XSETINT (emacs_event->x, x);
5459       XSETINT (emacs_event->y, y);
5460       ns_input_text = build_string ([data UTF8String]);
5461       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5462       EV_TRAILER (theEvent);
5463       return YES;
5464     }
5465   else if ([type isEqualToString: NSColorPboardType])
5466     {
5467       NSColor *c = [NSColor colorFromPasteboard: pb];
5468       emacs_event->kind = NS_NONKEY_EVENT;
5469       emacs_event->code = KEY_NS_DRAG_COLOR;
5470       XSETINT (emacs_event->x, x);
5471       XSETINT (emacs_event->y, y);
5472       ns_input_color = ns_color_to_lisp (c);
5473       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5474       EV_TRAILER (theEvent);
5475       return YES;
5476     }
5477   else if ([type isEqualToString: NSFontPboardType])
5478     {
5479       /* impl based on GNUstep NSTextView.m */
5480       NSData *data = [pb dataForType: NSFontPboardType];
5481       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
5482       NSFont *font = [dict objectForKey: NSFontAttributeName];
5483       char fontSize[10];
5485       if (font == nil)
5486         return NO;
5488       emacs_event->kind = NS_NONKEY_EVENT;
5489       emacs_event->code = KEY_NS_CHANGE_FONT;
5490       XSETINT (emacs_event->x, x);
5491       XSETINT (emacs_event->y, y);
5492       ns_input_font = build_string ([[font fontName] UTF8String]);
5493       snprintf (fontSize, 10, "%f", [font pointSize]);
5494       ns_input_fontsize = build_string (fontSize);
5495       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5496       EV_TRAILER (theEvent);
5497       return YES;
5498     }
5499   else
5500     {
5501       error ("Invalid data type in dragging pasteboard.");
5502       return NO;
5503     }
5507 - validRequestorForSendType: (NSString *)typeSent
5508                  returnType: (NSString *)typeReturned
5510   NSTRACE (validRequestorForSendType);
5511   if ([ns_send_types indexOfObjectIdenticalTo: typeSent] != NSNotFound &&
5512       [ns_return_types indexOfObjectIdenticalTo: typeSent] != NSNotFound)
5513     return self;
5515   return [super validRequestorForSendType: typeSent
5516                                returnType: typeReturned];
5520 /* The next two methods are part of NSServicesRequests informal protocol,
5521    supposedly called when a services menu item is chosen from this app.
5522    But this should not happen because we override the services menu with our
5523    own entries which call ns-perform-service.
5524    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
5525    So let's at least stub them out until further investigation can be done. */
5527 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
5529   /* we could call ns_string_from_pasteboard(pboard) here but then it should
5530      be written into the buffer in place of the existing selection..
5531      ordinary service calls go through functions defined in ns-win.el */
5532   return NO;
5535 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
5537   /* supposed to write for as many of types as we are able */
5538   return NO;
5542 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
5543    (gives a miniaturized version of the window); currently we use the latter for
5544    frames whose active buffer doesn't correspond to any file
5545    (e.g., '*scratch*') */
5546 - setMiniwindowImage: (BOOL) setMini
5548   id image = [[self window] miniwindowImage];
5549   NSTRACE (setMiniwindowImage);
5551   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
5552      about "AppleDockIconEnabled" notwithstanding, however the set message
5553      below has its effect nonetheless. */
5554   if (image != emacsframe->output_data.ns->miniimage)
5555     {
5556       if (image && [image isKindOfClass: [EmacsImage class]])
5557         [image release];
5558       [[self window] setMiniwindowImage:
5559                        setMini ? emacsframe->output_data.ns->miniimage : nil];
5560     }
5562   return self;
5566 - (void) setRows: (int) r andColumns: (int) c
5568   rows = r;
5569   cols = c;
5572 @end  /* EmacsView */
5576 /* ==========================================================================
5578     EmacsWindow implementation
5580    ========================================================================== */
5582 @implementation EmacsWindow
5584 /* called only on resize clicks by special case in EmacsApp-sendEvent */
5585 - (void)mouseDown: (NSEvent *)theEvent
5587   if (ns_in_resize)
5588     {
5589       NSSize size = [[theEvent window] frame].size;
5590       grabOffset = [theEvent locationInWindow];
5591       grabOffset.x = size.width - grabOffset.x;
5592     }
5593   else
5594     [super mouseDown: theEvent];
5598 /* stop resizing */
5599 - (void)mouseUp: (NSEvent *)theEvent
5601   if (ns_in_resize)
5602     {
5603       struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
5604       ns_in_resize = NO;
5605       ns_set_name_as_filename (f);
5606       [self display];
5607       ns_send_appdefined (-1);
5608     }
5609   else
5610     [super mouseUp: theEvent];
5614 /* send resize events */
5615 - (void)mouseDragged: (NSEvent *)theEvent
5617   if (ns_in_resize)
5618     {
5619       NSPoint p = [theEvent locationInWindow];
5620       NSSize size, vettedSize, origSize = [self frame].size;
5622       size.width = p.x + grabOffset.x;
5623       size.height = origSize.height - p.y + grabOffset.y;
5625       if (size.width == origSize.width && size.height == origSize.height)
5626         return;
5628       vettedSize = [[self delegate] windowWillResize: self toSize: size];
5629       if (vettedSize.width != size.width || vettedSize.height != size.height)
5630         {
5631           [[NSNotificationCenter defaultCenter]
5632             postNotificationName: NSWindowDidResizeNotification
5633                           object: self];
5634         }
5635     }
5636   else
5637     [super mouseDragged: theEvent];
5640 @end /* EmacsWindow */
5643 /* ==========================================================================
5645     EmacsScroller implementation
5647    ========================================================================== */
5650 @implementation EmacsScroller
5652 /* for repeat button push */
5653 #define SCROLL_BAR_FIRST_DELAY 0.5
5654 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
5656 + (CGFloat) scrollerWidth
5658   /* TODO: if we want to allow variable widths, this is the place to do it,
5659            however neither GNUstep nor Cocoa support it very well */
5660   return [NSScroller scrollerWidth];
5664 - initFrame: (NSRect )r window: (Lisp_Object)nwin
5666   NSTRACE (EmacsScroller_initFrame);
5668   r.size.width = [EmacsScroller scrollerWidth];
5669   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
5670   [self setContinuous: YES];
5671   [self setEnabled: YES];
5673   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
5674      locked against the top and bottom edges, and right edge on OS X, where
5675      scrollers are on right. */
5676 #ifdef NS_IMPL_GNUSTEP
5677   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
5678 #else
5679   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
5680 #endif
5682   win = nwin;
5683   condemned = NO;
5684   pixel_height = NSHeight (r);
5685   min_portion = 20 / pixel_height;
5687   frame = XFRAME (XWINDOW (win)->frame);
5688   if (FRAME_LIVE_P (frame))
5689     {
5690       int i;
5691       EmacsView *view = FRAME_NS_VIEW (frame);
5692       NSView *sview = [[view window] contentView];
5693       NSArray *subs = [sview subviews];
5695       /* disable optimization stopping redraw of other scrollbars */
5696       view->scrollbarsNeedingUpdate = 0;
5697       for (i =[subs count]-1; i >= 0; i--)
5698         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
5699           view->scrollbarsNeedingUpdate++;
5700       [sview addSubview: self];
5701     }
5703 /*  [self setFrame: r]; */
5705   return self;
5709 - (void)setFrame: (NSRect)newRect
5711   NSTRACE (EmacsScroller_setFrame);
5712 /*  BLOCK_INPUT; */
5713   pixel_height = NSHeight (newRect);
5714   min_portion = 20 / pixel_height;
5715   [super setFrame: newRect];
5716   [self display];
5717 /*  UNBLOCK_INPUT; */
5721 - (void)dealloc
5723   NSTRACE (EmacsScroller_dealloc);
5724   if (!NILP (win))
5725     XWINDOW (win)->vertical_scroll_bar = Qnil;
5726   [super dealloc];
5730 - condemn
5732   NSTRACE (condemn);
5733   condemned =YES;
5734   return self;
5738 - reprieve
5740   NSTRACE (reprieve);
5741   condemned =NO;
5742   return self;
5746 - judge
5748   NSTRACE (judge);
5749   if (condemned)
5750     {
5751       EmacsView *view;
5752       BLOCK_INPUT;
5753       /* ensure other scrollbar updates after deletion */
5754       view = (EmacsView *)FRAME_NS_VIEW (frame);
5755       if (view != nil)
5756         view->scrollbarsNeedingUpdate++;
5757       [self removeFromSuperview];
5758       [self release];
5759       UNBLOCK_INPUT;
5760     }
5761   return self;
5765 - (void)resetCursorRects
5767   NSRect visible = [self visibleRect];
5768   NSTRACE (resetCursorRects);
5770   if (!NSIsEmptyRect (visible))
5771     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
5772   [[NSCursor arrowCursor] setOnMouseEntered: YES];
5776 - (int) checkSamePosition: (int) position portion: (int) portion
5777                     whole: (int) whole
5779   return em_position ==position && em_portion ==portion && em_whole ==whole
5780     && portion != whole; /* needed for resize empty buf */
5784 - setPosition: (int)position portion: (int)portion whole: (int)whole
5786   NSTRACE (setPosition);
5788   em_position = position;
5789   em_portion = portion;
5790   em_whole = whole;
5792   if (portion >= whole)
5793     [self setFloatValue: 0.0 knobProportion: 1.0];
5794   else
5795     {
5796       float pos, por;
5797       portion = max ((float)whole*min_portion/pixel_height, portion);
5798       pos = (float)position / (whole - portion);
5799       por = (float)portion/whole;
5800       [self setFloatValue: pos knobProportion: por];
5801     }
5802   return self;
5805 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
5806      drag events will go directly to the EmacsScroller.  Leaving in for now. */
5807 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
5808                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
5810   *part = last_hit_part;
5811   *window = win;
5812   XSETINT (*y, pixel_height);
5813   if ([self floatValue] > 0.999)
5814     XSETINT (*x, pixel_height);
5815   else
5816     XSETINT (*x, pixel_height * [self floatValue]);
5820 /* set up emacs_event */
5821 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
5823   if (!emacs_event)
5824     return;
5826   emacs_event->part = last_hit_part;
5827   emacs_event->code = 0;
5828   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
5829   emacs_event->frame_or_window = win;
5830   emacs_event->timestamp = EV_TIMESTAMP (e);
5831   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
5832   emacs_event->arg = Qnil;
5833   XSETINT (emacs_event->x, loc * pixel_height);
5834   XSETINT (emacs_event->y, pixel_height-20);
5836   n_emacs_events_pending++;
5837   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
5838   EVENT_INIT (*emacs_event);
5839   ns_send_appdefined (-1);
5843 /* called manually thru timer to implement repeated button action w/hold-down */
5844 - repeatScroll: (NSTimer *)scrollEntry
5846   NSEvent *e = [[self window] currentEvent];
5847   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
5848   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
5850   /* clear timer if need be */
5851   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
5852     {
5853         [scroll_repeat_entry invalidate];
5854         [scroll_repeat_entry release];
5855         scroll_repeat_entry = nil;
5857         if (inKnob)
5858           return self;
5860         scroll_repeat_entry
5861           = [[NSTimer scheduledTimerWithTimeInterval:
5862                         SCROLL_BAR_CONTINUOUS_DELAY
5863                                             target: self
5864                                           selector: @selector (repeatScroll:)
5865                                           userInfo: 0
5866                                            repeats: YES]
5867               retain];
5868     }
5870   [self sendScrollEventAtLoc: 0 fromEvent: e];
5871   return self;
5875 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
5876    mouseDragged events without going into a modal loop. */
5877 - (void)mouseDown: (NSEvent *)e
5879   NSRect sr, kr;
5880   /* hitPart is only updated AFTER event is passed on */
5881   NSScrollerPart part = [self testPart: [e locationInWindow]];
5882   double inc = 0.0, loc, kloc, pos;
5883   int edge = 0;
5885   NSTRACE (EmacsScroller_mouseDown);
5887   switch (part)
5888     {
5889     case NSScrollerDecrementPage:
5890         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
5891     case NSScrollerIncrementPage:
5892         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
5893     case NSScrollerDecrementLine:
5894       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
5895     case NSScrollerIncrementLine:
5896       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
5897     case NSScrollerKnob:
5898       last_hit_part = scroll_bar_handle; break;
5899     case NSScrollerKnobSlot:  /* GNUstep-only */
5900       last_hit_part = scroll_bar_move_ratio; break;
5901     default:  /* NSScrollerNoPart? */
5902       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
5903                (long) part);
5904       return;
5905     }
5907   if (inc != 0.0)
5908     {
5909       pos = 0;      /* ignored */
5911       /* set a timer to repeat, as we can't let superclass do this modally */
5912       scroll_repeat_entry
5913         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
5914                                             target: self
5915                                           selector: @selector (repeatScroll:)
5916                                           userInfo: 0
5917                                            repeats: YES]
5918             retain];
5919     }
5920   else
5921     {
5922       /* handle, or on GNUstep possibly slot */
5923       NSEvent *fake_event;
5925       /* compute float loc in slot and mouse offset on knob */
5926       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
5927                       toView: nil];
5928       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
5929       if (loc <= 0.0)
5930         {
5931           loc = 0.0;
5932           edge = -1;
5933         }
5934       else if (loc >= NSHeight (sr))
5935         {
5936           loc = NSHeight (sr);
5937           edge = 1;
5938         }
5940       if (edge)
5941         kloc = 0.5 * edge;
5942       else
5943         {
5944           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
5945                           toView: nil];
5946           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
5947         }
5948       last_mouse_offset = kloc;
5950       /* if knob, tell emacs a location offset by knob pos
5951          (to indicate top of handle) */
5952       if (part == NSScrollerKnob)
5953           pos = (loc - last_mouse_offset) / NSHeight (sr);
5954       else
5955         /* else this is a slot click on GNUstep: go straight there */
5956         pos = loc / NSHeight (sr);
5958       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
5959       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
5960                                       location: [e locationInWindow]
5961                                  modifierFlags: [e modifierFlags]
5962                                      timestamp: [e timestamp]
5963                                   windowNumber: [e windowNumber]
5964                                        context: [e context]
5965                                    eventNumber: [e eventNumber]
5966                                     clickCount: [e clickCount]
5967                                       pressure: [e pressure]];
5968       [super mouseUp: fake_event];
5969     }
5971   if (part != NSScrollerKnob)
5972     [self sendScrollEventAtLoc: pos fromEvent: e];
5976 /* Called as we manually track scroller drags, rather than superclass. */
5977 - (void)mouseDragged: (NSEvent *)e
5979     NSRect sr;
5980     double loc, pos;
5981     int edge = 0;
5983     NSTRACE (EmacsScroller_mouseDragged);
5985       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
5986                       toView: nil];
5987       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
5989       if (loc <= 0.0)
5990         {
5991           loc = 0.0;
5992           edge = -1;
5993         }
5994       else if (loc >= NSHeight (sr) + last_mouse_offset)
5995         {
5996           loc = NSHeight (sr) + last_mouse_offset;
5997           edge = 1;
5998         }
6000       pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
6001       [self sendScrollEventAtLoc: pos fromEvent: e];
6005 - (void)mouseUp: (NSEvent *)e
6007   if (scroll_repeat_entry)
6008     {
6009       [scroll_repeat_entry invalidate];
6010       [scroll_repeat_entry release];
6011       scroll_repeat_entry = nil;
6012     }
6013   last_hit_part = 0;
6017 /* treat scrollwheel events in the bar as though they were in the main window */
6018 - (void) scrollWheel: (NSEvent *)theEvent
6020   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
6021   [view mouseDown: theEvent];
6024 @end  /* EmacsScroller */
6029 /* ==========================================================================
6031    Font-related functions; these used to be in nsfaces.m
6033    ========================================================================== */
6036 Lisp_Object
6037 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
6039   struct font *font = XFONT_OBJECT (font_object);
6041   if (fontset < 0)
6042     fontset = fontset_from_font (font_object);
6043   FRAME_FONTSET (f) = fontset;
6045   if (FRAME_FONT (f) == font)
6046     /* This font is already set in frame F.  There's nothing more to
6047        do.  */
6048     return font_object;
6050   FRAME_FONT (f) = font;
6052   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
6053   FRAME_COLUMN_WIDTH (f) = font->average_width;
6054   FRAME_SPACE_WIDTH (f) = font->space_width;
6055   FRAME_LINE_HEIGHT (f) = font->height;
6057   compute_fringe_widths (f, 1);
6059   /* Compute the scroll bar width in character columns.  */
6060   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6061     {
6062       int wid = FRAME_COLUMN_WIDTH (f);
6063       FRAME_CONFIG_SCROLL_BAR_COLS (f)
6064         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
6065     }
6066   else
6067     {
6068       int wid = FRAME_COLUMN_WIDTH (f);
6069       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6070     }
6072   /* Now make the frame display the given font.  */
6073   if (FRAME_NS_WINDOW (f) != 0)
6074         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6076   return font_object;
6080 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
6081 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
6082          in 1.43. */
6084 const char *
6085 ns_xlfd_to_fontname (const char *xlfd)
6086 /* --------------------------------------------------------------------------
6087     Convert an X font name (XLFD) to an NS font name.
6088     Only family is used.
6089     The string returned is temporarily allocated.
6090    -------------------------------------------------------------------------- */
6092   char *name = xmalloc (180);
6093   int i, len;
6094   const char *ret;
6096   if (!strncmp (xlfd, "--", 2))
6097     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
6098   else
6099     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
6101   /* stopgap for malformed XLFD input */
6102   if (strlen (name) == 0)
6103     strcpy (name, "Monaco");
6105   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
6106      also uppercase after '-' or ' ' */
6107   name[0] = toupper (name[0]);
6108   for (len =strlen (name), i =0; i<len; i++)
6109     {
6110       if (name[i] == '$')
6111         {
6112           name[i] = '-';
6113           if (i+1<len)
6114             name[i+1] = toupper (name[i+1]);
6115         }
6116       else if (name[i] == '_')
6117         {
6118           name[i] = ' ';
6119           if (i+1<len)
6120             name[i+1] = toupper (name[i+1]);
6121         }
6122     }
6123 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
6124   ret = [[NSString stringWithUTF8String: name] UTF8String];
6125   xfree (name);
6126   return ret;
6130 void
6131 syms_of_nsterm (void)
6133   NSTRACE (syms_of_nsterm);
6135   ns_antialias_threshold = 10.0;
6137   /* from 23+ we need to tell emacs what modifiers there are.. */
6138   DEFSYM (Qmodifier_value, "modifier-value");
6139   DEFSYM (Qalt, "alt");
6140   DEFSYM (Qhyper, "hyper");
6141   DEFSYM (Qmeta, "meta");
6142   DEFSYM (Qsuper, "super");
6143   DEFSYM (Qcontrol, "control");
6144   DEFSYM (Qnone, "none");
6145   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
6146   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
6147   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
6148   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
6149   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
6151   DEFVAR_LISP ("ns-input-file", &ns_input_file,
6152               "The file specified in the last NS event.");
6153   ns_input_file =Qnil;
6155   DEFVAR_LISP ("ns-input-text", &ns_input_text,
6156               "The data received in the last NS text drag event.");
6157   ns_input_text =Qnil;
6159   DEFVAR_LISP ("ns-working-text", &ns_working_text,
6160               "String for visualizing working composition sequence.");
6161   ns_working_text =Qnil;
6163   DEFVAR_LISP ("ns-input-font", &ns_input_font,
6164               "The font specified in the last NS event.");
6165   ns_input_font =Qnil;
6167   DEFVAR_LISP ("ns-input-fontsize", &ns_input_fontsize,
6168               "The fontsize specified in the last NS event.");
6169   ns_input_fontsize =Qnil;
6171   DEFVAR_LISP ("ns-input-line", &ns_input_line,
6172                "The line specified in the last NS event.");
6173   ns_input_line =Qnil;
6175   DEFVAR_LISP ("ns-input-color", &ns_input_color,
6176                "The color specified in the last NS event.");
6177   ns_input_color =Qnil;
6179   DEFVAR_LISP ("ns-input-spi-name", &ns_input_spi_name,
6180                "The service name specified in the last NS event.");
6181   ns_input_spi_name =Qnil;
6183   DEFVAR_LISP ("ns-input-spi-arg", &ns_input_spi_arg,
6184                "The service argument specified in the last NS event.");
6185   ns_input_spi_arg =Qnil;
6187   DEFVAR_LISP ("ns-alternate-modifier", &ns_alternate_modifier,
6188                "This variable describes the behavior of the alternate or option key.\n\
6189 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6190 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6191 at all, allowing it to be used at a lower level for accented character entry.");
6192   ns_alternate_modifier = Qmeta;
6194   DEFVAR_LISP ("ns-command-modifier", &ns_command_modifier,
6195                "This variable describes the behavior of the command key.\n\
6196 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6197   ns_command_modifier = Qsuper;
6199   DEFVAR_LISP ("ns-control-modifier", &ns_control_modifier,
6200                "This variable describes the behavior of the control key.\n\
6201 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6202   ns_control_modifier = Qcontrol;
6204   DEFVAR_LISP ("ns-function-modifier", &ns_function_modifier,
6205                "This variable describes the behavior of the function key (on laptops).\n\
6206 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6207 Set to none means that the function key is not interpreted by Emacs at all,\n\
6208 allowing it to be used at a lower level for accented character entry.");
6209   ns_function_modifier = Qnone;
6211   DEFVAR_LISP ("ns-antialias-text", &ns_antialias_text,
6212                "Non-nil (the default) means to render text antialiased. Only has an effect on OS X Panther and above.");
6213   ns_antialias_text = Qt;
6215   DEFVAR_LISP ("ns-confirm-quit", &ns_confirm_quit,
6216                "Whether to confirm application quit using dialog.");
6217   ns_confirm_quit = Qnil;
6219   staticpro (&ns_display_name_list);
6220   ns_display_name_list = Qnil;
6222   staticpro (&last_mouse_motion_frame);
6223   last_mouse_motion_frame = Qnil;
6225   /* TODO: move to common code */
6226   DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
6227                doc: /* If not nil, Emacs uses toolkit scroll bars.  */);
6228 #ifdef USE_TOOLKIT_SCROLL_BARS
6229   Vx_toolkit_scroll_bars = Qt;
6230 #else
6231   Vx_toolkit_scroll_bars = Qnil;
6232 #endif
6234   /* these are unsupported but we need the declarations to avoid whining
6235      messages from cus-start.el */
6236   DEFVAR_BOOL ("x-use-underline-position-properties",
6237                &x_use_underline_position_properties,
6238      doc: /* NOT SUPPORTED UNDER NS.
6239 *Non-nil means make use of UNDERLINE_POSITION font properties.
6240 A value of nil means ignore them.  If you encounter fonts with bogus
6241 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
6242 to 4.1, set this to nil.
6244 NOTE: Not supported on Mac yet.  */);
6245   x_use_underline_position_properties = 0;
6247   DEFVAR_BOOL ("x-underline-at-descent-line",
6248                &x_underline_at_descent_line,
6249      doc: /* NOT SUPPORTED UNDER NS.
6250 *Non-nil means to draw the underline at the same place as the descent line.
6251 A value of nil means to draw the underline according to the value of the
6252 variable `x-use-underline-position-properties', which is usually at the
6253 baseline level.  The default value is nil.  */);
6254   x_underline_at_descent_line = 0;
6256   /* Tell emacs about this window system. */
6257   Fprovide (intern ("ns"), Qnil);
6261 // arch-tag: 6eaa8f7d-a69b-4e1c-b43d-ab31defbe0d2