* keyboard.c (Fset_input_meta_mode): Doc fix.
[emacs.git] / src / nsterm.m
blob5085679e04a198a941cb1ea83241b4d632349235
1 /* NeXT/Open/GNUstep / MacOSX communication module.
2    Copyright (C) 1989, 1993, 1994, 2005, 2006, 2008, 2009
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>
38 #include "lisp.h"
39 #include "blockinput.h"
40 #include "sysselect.h"
41 #include "nsterm.h"
42 #include "systime.h"
43 #include "character.h"
44 #include "fontset.h"
45 #include "composite.h"
46 #include "ccl.h"
48 #include "termhooks.h"
49 #include "termopts.h"
50 #include "termchar.h"
52 #include "window.h"
53 #include "keyboard.h"
55 #include "font.h"
57 /* call tracing */
58 #if 0
59 int term_trace_num = 0;
60 #define NSTRACE(x)        fprintf (stderr, "%s:%d: [%d] " #x "\n",         \
61                                 __FILE__, __LINE__, ++term_trace_num)
62 #else
63 #define NSTRACE(x)
64 #endif
67 /* ==========================================================================
69     Local declarations
71    ========================================================================== */
73 /* Convert a symbol indexed with an NSxxx value to a value as defined
74    in keyboard.c (lispy_function_key). I hope this is a correct way
75    of doing things... */
76 static unsigned convert_ns_to_X_keysym[] =
78   NSHomeFunctionKey,            0x50,
79   NSLeftArrowFunctionKey,       0x51,
80   NSUpArrowFunctionKey,         0x52,
81   NSRightArrowFunctionKey,      0x53,
82   NSDownArrowFunctionKey,       0x54,
83   NSPageUpFunctionKey,          0x55,
84   NSPageDownFunctionKey,        0x56,
85   NSEndFunctionKey,             0x57,
86   NSBeginFunctionKey,           0x58,
87   NSSelectFunctionKey,          0x60,
88   NSPrintFunctionKey,           0x61,
89   NSExecuteFunctionKey,         0x62,
90   NSInsertFunctionKey,          0x63,
91   NSUndoFunctionKey,            0x65,
92   NSRedoFunctionKey,            0x66,
93   NSMenuFunctionKey,            0x67,
94   NSFindFunctionKey,            0x68,
95   NSHelpFunctionKey,            0x6A,
96   NSBreakFunctionKey,           0x6B,
98   NSF1FunctionKey,              0xBE,
99   NSF2FunctionKey,              0xBF,
100   NSF3FunctionKey,              0xC0,
101   NSF4FunctionKey,              0xC1,
102   NSF5FunctionKey,              0xC2,
103   NSF6FunctionKey,              0xC3,
104   NSF7FunctionKey,              0xC4,
105   NSF8FunctionKey,              0xC5,
106   NSF9FunctionKey,              0xC6,
107   NSF10FunctionKey,             0xC7,
108   NSF11FunctionKey,             0xC8,
109   NSF12FunctionKey,             0xC9,
110   NSF13FunctionKey,             0xCA,
111   NSF14FunctionKey,             0xCB,
112   NSF15FunctionKey,             0xCC,
114   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
115   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
116   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
118   NSTabCharacter,               0x09,
119   0x19,                         0x09,  /* left tab->regular since pass shift */
120   NSCarriageReturnCharacter,    0x0D,
121   NSNewlineCharacter,           0x0D,
122   NSEnterCharacter,             0x8D,
124   0x1B,                         0x1B   /* escape */
128 /* Lisp communications */
129 Lisp_Object ns_input_file, ns_input_font, ns_input_fontsize, ns_input_line;
130 Lisp_Object ns_input_color, ns_input_text, ns_working_text;
131 Lisp_Object ns_input_spi_name, ns_input_spi_arg;
132 Lisp_Object Vx_toolkit_scroll_bars;
133 static Lisp_Object Qmodifier_value;
134 /* TODO: unsure why these defined in term files, anyway we need in keymap.c */
135 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper;
136 extern Lisp_Object Qcursor_color, Qcursor_type, Qns;
139 /* Some preferences equivalent to those set by X resources under X are
140    managed through the OpenStep defaults system. We depart from X
141    behavior and refuse to read defaults when started under these
142    options. */
144 /* Set in emacs.c. */
145 char ns_no_defaults;
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 /* Controls use of an undocumented CG function to do Quickdraw-style font
172    smoothing (less heavy) instead of regular Quartz smoothing. */
173 Lisp_Object ns_use_qd_smoothing;
175 /* Used to pick up AppleHighlightColor on OS X */
176 Lisp_Object ns_use_system_highlight_color;
177 NSString *ns_selection_color;
179 /* Confirm on exit. */
180 Lisp_Object ns_confirm_quit;
182 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
184 /* Display variables */
185 struct ns_display_info *x_display_list; /* Chain of existing displays */
186 Lisp_Object ns_display_name_list;
187 long context_menu_value = 0;
189 /* display update */
190 NSPoint last_mouse_motion_position;
191 static NSRect last_mouse_glyph;
192 static unsigned long last_mouse_movement_time = 0;
193 static Lisp_Object last_mouse_motion_frame;
194 static EmacsScroller *last_mouse_scroll_bar = nil;
195 static struct frame *ns_updating_frame;
196 static NSView *focus_view = NULL;
197 static int ns_window_num =0;
198 static NSRect uRect;
199 static BOOL gsaved = NO;
200 BOOL ns_in_resize = NO;
201 static BOOL ns_fake_keydown = NO;
202 int ns_tmp_flags; /* FIXME */
203 struct nsfont_info *ns_tmp_font; /* FIXME */
204 /*static int debug_lock = 0; */
206 #ifdef NS_IMPL_COCOA
207 /* This undocumented Quartz function controls how fonts are anti-aliased.
208    (Found from code in Mac wxWindows impl, discovered by running `nm' on
209    the "QD" framework.)
210    Mode 0 is normal anti-aliasing, mode 1 is no anti-aliasing, and mode 2 is
211    4-bit pixel-aligned anti-aliasing (the old QuickDraw standard). */
212 extern void CGContextSetFontRenderingMode (CGContextRef cg, int v);
213 #endif
216 /* event loop */
217 static BOOL send_appdefined = YES;
218 static NSEvent *last_appdefined_event = 0;
219 static NSTimer *timed_entry = 0;
220 static NSTimer *fd_entry = nil;
221 static NSTimer *scroll_repeat_entry = nil;
222 static fd_set select_readfds, t_readfds;
223 static struct timeval select_timeout;
224 static int select_nfds;
225 static NSAutoreleasePool *outerpool;
226 static struct input_event *emacs_event = NULL;
227 static struct input_event *q_event_ptr = NULL;
228 static int n_emacs_events_pending = 0;
229 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
230   *ns_pending_service_args;
231 static BOOL inNsSelect = 0;
233 /* Convert modifiers in a NeXTSTEP event to emacs style modifiers.  */
234 #define NS_FUNCTION_KEY_MASK 0x800000
235 #define EV_MODIFIERS(e)                               \
236     ((([e modifierFlags] & NSHelpKeyMask) ?           \
237            hyper_modifier : 0)                        \
238      | (([e modifierFlags] & NSAlternateKeyMask) ?    \
239            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
240      | (([e modifierFlags] & NSShiftKeyMask) ?        \
241            shift_modifier : 0)                        \
242      | (([e modifierFlags] & NSControlKeyMask) ?      \
243            parse_solitary_modifier (ns_control_modifier) : 0)     \
244      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
245            parse_solitary_modifier (ns_function_modifier) : 0)    \
246      | (([e modifierFlags] & NSCommandKeyMask) ?      \
247            parse_solitary_modifier (ns_command_modifier):0))
249 #define EV_UDMODIFIERS(e)                                      \
250     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
251      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
252      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
253      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
254      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
255      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
256      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
257      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
258      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
260 #define EV_BUTTON(e)                                                         \
261     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
262       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
263      [e buttonNumber] - 1)
265 /* Convert the time field to a timestamp in milliseconds. */
266 #ifdef NS_IMPL_GNUSTEP
267 /* Apple says timestamp is in seconds, but GNUstep seems to be returning msec */
268 #define EV_TIMESTAMP(e) ([e timestamp])
269 #else
270 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
271 #endif /* not gnustep */
273 /* This is a piece of code which is common to all the event handling
274    methods.  Maybe it should even be a function.  */
275 #define EV_TRAILER(e)                                         \
276   {                                                           \
277   XSETFRAME (emacs_event->frame_or_window, emacsframe);       \
278   if (e) emacs_event->timestamp = EV_TIMESTAMP (e);           \
279   n_emacs_events_pending++;                                   \
280   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);     \
281   EVENT_INIT (*emacs_event);                                  \
282   ns_send_appdefined (-1);                                    \
283   }
285 void x_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
287 /* TODO: get rid of need for these forward declarations */
288 static void ns_condemn_scroll_bars (struct frame *f);
289 static void ns_judge_scroll_bars (struct frame *f);
290 void x_set_frame_alpha (struct frame *f);
292 /* unused variables needed for compatibility reasons */
293 int x_use_underline_position_properties, x_underline_at_descent_line;
294 /* FIXME: figure out what to do with underline_minimum_offset. */
297 /* ==========================================================================
299     Utilities
301    ========================================================================== */
304 static Lisp_Object
305 append2 (Lisp_Object list, Lisp_Object item)
306 /* --------------------------------------------------------------------------
307    Utility to append to a list
308    -------------------------------------------------------------------------- */
310   Lisp_Object array[2];
311   array[0] = list;
312   array[1] = Fcons (item, Qnil);
313   return Fnconc (2, &array[0]);
317 void
318 ns_init_paths ()
319 /* --------------------------------------------------------------------------
320    Used to allow emacs to find its resources under Emacs.app
321    Called from emacs.c at startup.
322    -------------------------------------------------------------------------- */
324   NSBundle *bundle = [NSBundle mainBundle];
325   NSString *binDir = [bundle bundlePath], *resourceDir = [bundle resourcePath];
326   NSString *resourcePath, *resourcePaths;
327   NSRange range;
328   BOOL onWindows = NO; /* how do I determine this? */
329   NSString *pathSeparator = onWindows ? @";" : @":";
330   NSFileManager *fileManager = [NSFileManager defaultManager];
331   BOOL isDir;
332 /*NSLog (@"ns_init_paths: '%@'\n%@\n", [[NSBundle mainBundle] bundlePath], [[NSBundle mainBundle] resourcePath]); */
334   /* get bindir from base */
335   range = [resourceDir rangeOfString: @"Contents"];
336   if (range.location != NSNotFound)
337     {
338       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
339 #ifdef NS_IMPL_COCOA
340       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
341 #endif
342     }
344   /* the following based on Andrew Choi's init_mac_osx_environment () */
345   if (!getenv ("EMACSLOADPATH"))
346     {
347       NSArray *paths = [resourceDir stringsByAppendingPaths:
348                                   [NSArray arrayWithObjects:
349                                          @"site-lisp", @"lisp", @"leim", nil]];
350       NSEnumerator *pathEnum = [paths objectEnumerator];
351       resourcePaths = @"";
352       while (resourcePath = [pathEnum nextObject])
353         {
354           if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
355             if (isDir)
356               {
357                 if ([resourcePaths length] > 0)
358                   resourcePaths
359                     = [resourcePaths stringByAppendingString: pathSeparator];
360                 resourcePaths
361                   = [resourcePaths stringByAppendingString: resourcePath];
362               }
363         }
364       if ([resourcePaths length] > 0)
365         setenv ("EMACSLOADPATH", [resourcePaths UTF8String], 1);
366 /*NSLog (@"loadPath: '%s'\n", resourcePaths); */
367     }
369   if (!getenv ("EMACSPATH"))
370     {
371       NSArray *paths = [binDir stringsByAppendingPaths:
372                                   [NSArray arrayWithObjects: @"bin",
373                                                              @"lib-exec", nil]];
374       NSEnumerator *pathEnum = [paths objectEnumerator];
375       resourcePaths = @"";
376       while (resourcePath = [pathEnum nextObject])
377         {
378           if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
379             if (isDir)
380               {
381                 if ([resourcePaths length] > 0)
382                   resourcePaths
383                     = [resourcePaths stringByAppendingString: pathSeparator];
384                 resourcePaths
385                   = [resourcePaths stringByAppendingString: resourcePath];
386               }
387         }
388       if ([resourcePaths length] > 0)
389         setenv ("EMACSPATH", [resourcePaths UTF8String], 1);
390     }
392   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
393   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
394     {
395       if (isDir)
396         {
397           if (!getenv ("EMACSDATA"))
398             setenv ("EMACSDATA", [resourcePath UTF8String], 1);
399           if (!getenv ("EMACSDOC"))
400             setenv ("EMACSDOC", [resourcePath UTF8String], 1);
401         }
402     }
404   if (!getenv ("INFOPATH"))
405     {
406       resourcePath = [resourceDir stringByAppendingPathComponent: @"info"];
407       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
408         if (isDir)
409           setenv ("INFOPATH", [resourcePath UTF8String], 1);
410     }
414 static int
415 timeval_subtract (struct timeval *result, struct timeval x, struct timeval y)
416 /* --------------------------------------------------------------------------
417    Subtract the `struct timeval' values X and Y, storing the result in RESULT.
418    Return 1 if the difference is negative, otherwise 0.
419    -------------------------------------------------------------------------- */
421   /* Perform the carry for the later subtraction by updating y.
422      This is safer because on some systems
423      the tv_sec member is unsigned.  */
424   if (x.tv_usec < y.tv_usec)
425     {
426       int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
427       y.tv_usec -= 1000000 * nsec;
428       y.tv_sec += nsec;
429     }
430   if (x.tv_usec - y.tv_usec > 1000000)
431     {
432       int nsec = (y.tv_usec - x.tv_usec) / 1000000;
433       y.tv_usec += 1000000 * nsec;
434       y.tv_sec -= nsec;
435     }
437   /* Compute the time remaining to wait.  tv_usec is certainly positive.  */
438   result->tv_sec = x.tv_sec - y.tv_sec;
439   result->tv_usec = x.tv_usec - y.tv_usec;
441   /* Return indication of whether the result should be considered negative.  */
442   return x.tv_sec < y.tv_sec;
445 static void
446 ns_timeout (int usecs)
447 /* --------------------------------------------------------------------------
448      Blocking timer utility used by ns_ring_bell
449    -------------------------------------------------------------------------- */
451   struct timeval wakeup;
453   EMACS_GET_TIME (wakeup);
455   /* Compute time to wait until, propagating carry from usecs.  */
456   wakeup.tv_usec += usecs;
457   wakeup.tv_sec += (wakeup.tv_usec / 1000000);
458   wakeup.tv_usec %= 1000000;
460   /* Keep waiting until past the time wakeup.  */
461   while (1)
462     {
463       struct timeval timeout;
465       EMACS_GET_TIME (timeout);
467       /* In effect, timeout = wakeup - timeout.
468          Break if result would be negative.  */
469       if (timeval_subtract (&timeout, wakeup, timeout))
470         break;
472       /* Try to wait that long--but we might wake up sooner.  */
473       select (0, NULL, NULL, NULL, &timeout);
474     }
478 void
479 ns_release_object (void *obj)
480 /* --------------------------------------------------------------------------
481     Release an object (callable from C)
482    -------------------------------------------------------------------------- */
484     [(id)obj release];
488 void
489 ns_retain_object (void *obj)
490 /* --------------------------------------------------------------------------
491     Retain an object (callable from C)
492    -------------------------------------------------------------------------- */
494     [(id)obj retain];
498 void *
499 ns_alloc_autorelease_pool ()
500 /* --------------------------------------------------------------------------
501      Allocate a pool for temporary objects (callable from C)
502    -------------------------------------------------------------------------- */
504   return [[NSAutoreleasePool alloc] init];
508 void
509 ns_release_autorelease_pool (void *pool)
510 /* --------------------------------------------------------------------------
511      Free a pool and temporary objects it refers to (callable from C)
512    -------------------------------------------------------------------------- */
514   ns_release_object (pool);
519 /* ==========================================================================
521     Focus (clipping) and screen update
523    ========================================================================== */
525 static NSRect
526 ns_resize_handle_rect (NSWindow *window)
528   NSRect r = [window frame];
529   r.origin.x = r.size.width - RESIZE_HANDLE_SIZE;
530   r.origin.y = 0;
531   r.size.width = r.size.height = RESIZE_HANDLE_SIZE;
532   return r;
536 static void
537 ns_update_begin (struct frame *f)
538 /* --------------------------------------------------------------------------
539    Prepare for a grouped sequence of drawing calls
540    external (RIF) call; whole frame, called before update_window_begin
541    -------------------------------------------------------------------------- */
543   NSView *view = FRAME_NS_VIEW (f);
544   NSTRACE (ns_update_begin);
546   ns_updating_frame = f;
547   [view lockFocus];
549 #ifdef NS_IMPL_GNUSTEP
550   uRect = NSMakeRect (0, 0, 0, 0);
551 #endif
555 static void
556 ns_update_window_begin (struct window *w)
557 /* --------------------------------------------------------------------------
558    Prepare for a grouped sequence of drawing calls
559    external (RIF) call; for one window, called after update_begin
560    -------------------------------------------------------------------------- */
562   struct frame *f = XFRAME (WINDOW_FRAME (w));
563   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
564   NSTRACE (ns_update_window_begin);
566   updated_window = w;
567   set_output_cursor (&w->cursor);
569   BLOCK_INPUT;
571   if (f == dpyinfo->mouse_face_mouse_frame)
572     {
573       /* Don't do highlighting for mouse motion during the update.  */
574       dpyinfo->mouse_face_defer = 1;
576         /* If the frame needs to be redrawn,
577            simply forget about any prior mouse highlighting.  */
578       if (FRAME_GARBAGED_P (f))
579         dpyinfo->mouse_face_window = Qnil;
581       /* (further code for mouse faces ifdef'd out in other terms elided) */
582     }
584   UNBLOCK_INPUT;
588 static void
589 ns_update_window_end (struct window *w, int cursor_on_p,
590                       int mouse_face_overwritten_p)
591 /* --------------------------------------------------------------------------
592    Finished a grouped sequence of drawing calls
593    external (RIF) call; for one window called before update_end
594    -------------------------------------------------------------------------- */
596   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (XFRAME (w->frame));
598   /* note: this fn is nearly identical in all terms */
599   if (!w->pseudo_window_p)
600     {
601       BLOCK_INPUT;
603       if (cursor_on_p)
604         display_and_set_cursor (w, 1,
605                                 output_cursor.hpos, output_cursor.vpos,
606                                 output_cursor.x, output_cursor.y);
608       if (draw_window_fringes (w, 1))
609         x_draw_vertical_border (w);
611       UNBLOCK_INPUT;
612     }
614   /* If a row with mouse-face was overwritten, arrange for
615      frame_up_to_date to redisplay the mouse highlight.  */
616   if (mouse_face_overwritten_p)
617     {
618       dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
619       dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
620       dpyinfo->mouse_face_window = Qnil;
621     }
623   updated_window = NULL;
624   NSTRACE (update_window_end);
628 static void
629 ns_update_end (struct frame *f)
630 /* --------------------------------------------------------------------------
631    Finished a grouped sequence of drawing calls
632    external (RIF) call; for whole frame, called after update_window_end
633    -------------------------------------------------------------------------- */
635   NSView *view = FRAME_NS_VIEW (f);
637 /*   if (f == FRAME_NS_DISPLAY_INFO (f)->mouse_face_mouse_frame) */
638     FRAME_NS_DISPLAY_INFO (f)->mouse_face_defer = 0;
640   BLOCK_INPUT;
642 #ifdef NS_IMPL_GNUSTEP
643   /* trigger flush only in the rectangle we tracked as being drawn */
644   [view unlockFocusNeedsFlush: NO];
645 /*fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", uRect.origin.x, uRect.origin.y, uRect.size.width, uRect.size.height); */
646   [view lockFocusInRect: uRect];
647 #endif
649   [view unlockFocus];
650   [[view window] flushWindow];
652   UNBLOCK_INPUT;
653   ns_updating_frame = NULL;
654   NSTRACE (ns_update_end);
658 static void
659 ns_flush (struct frame *f)
660 /* --------------------------------------------------------------------------
661    external (RIF) call
662    NS impl is no-op since currently we flush in ns_update_end and elsewhere
663    -------------------------------------------------------------------------- */
665     NSTRACE (ns_flush);
669 static void
670 ns_focus (struct frame *f, NSRect *r, int n)
671 /* --------------------------------------------------------------------------
672    Internal: Focus on given frame.  During small local updates this is used to
673      draw, however during large updates, ns_update_begin and ns_update_end are
674      called to wrap the whole thing, in which case these calls are stubbed out.
675      Except, on GNUstep, we accumulate the rectangle being drawn into, because
676      the back end won't do this automatically, and will just end up flushing
677      the entire window.
678    -------------------------------------------------------------------------- */
680 //  NSTRACE (ns_focus);
681 #ifdef NS_IMPL_GNUSTEP
682   NSRect u;
683     if (n == 2)
684       u = NSUnionRect (r[0], r[1]);
685     else if (r)
686       u = *r;
687 #endif
688 /* static int c =0;
689    fprintf (stderr, "focus: %d", c++);
690    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
691    fprintf (stderr, "\n"); */
693   if (f != ns_updating_frame)
694     {
695       NSView *view = FRAME_NS_VIEW (f);
696       if (view != focus_view)
697         {
698           if (focus_view != NULL)
699             {
700               [focus_view unlockFocus];
701               [[focus_view window] flushWindow];
702 /*debug_lock--; */
703             }
705           if (view)
706 #ifdef NS_IMPL_GNUSTEP
707             r ? [view lockFocusInRect: u] : [view lockFocus];
708 #else
709             [view lockFocus];
710 #endif
711           focus_view = view;
712 /*if (view) debug_lock++; */
713         }
714 #ifdef NS_IMPL_GNUSTEP
715       else
716         {
717           /* more than one rect being drawn into */
718           if (view && r)
719             {
720               [view unlockFocus]; /* add prev rect to redraw list */
721               [view lockFocusInRect: u]; /* focus for draw in new rect */
722             }
723         }
724 #endif
725     }
726 #ifdef NS_IMPL_GNUSTEP
727   else
728     {
729       /* in batch mode, but in GNUstep must still track rectangles explicitly */
730       uRect = (r ? NSUnionRect (uRect, u) : [FRAME_NS_VIEW (f) visibleRect]);
731     }
732 #endif
734   /* clipping */
735   if (r)
736     {
737       [[NSGraphicsContext currentContext] saveGraphicsState];
738       if (n == 2)
739         NSRectClipList (r, 2);
740       else
741         NSRectClip (*r);
742       gsaved = YES;
743     }
747 static void
748 ns_unfocus (struct frame *f)
749 /* --------------------------------------------------------------------------
750      Internal: Remove focus on given frame
751    -------------------------------------------------------------------------- */
753 //  NSTRACE (ns_unfocus);
755   if (gsaved)
756     {
757       [[NSGraphicsContext currentContext] restoreGraphicsState];
758       gsaved = NO;
759     }
761   if (f != ns_updating_frame)
762     {
763       if (focus_view != NULL)
764         {
765           [focus_view unlockFocus];
766           [[focus_view window] flushWindow];
767           focus_view = NULL;
768 /*debug_lock--; */
769         }
770     }
774 static void
775 ns_clip_to_row (struct window *w, struct glyph_row *row, int area, BOOL gc)
776 /* --------------------------------------------------------------------------
777      Internal (but parallels other terms): Focus drawing on given row
778    -------------------------------------------------------------------------- */
780   struct frame *f = XFRAME (WINDOW_FRAME (w));
781   NSRect clip_rect;
782   int window_x, window_y, window_width;
784   window_box (w, area, &window_x, &window_y, &window_width, 0);
786   clip_rect.origin.x = window_x - FRAME_INTERNAL_BORDER_WIDTH (f);
787   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
788   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
789   clip_rect.size.width = window_width + 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
790   clip_rect.size.height = row->visible_height;
792   /* allow a full-height row at the top when requested
793      (used to draw fringe all the way through internal border area) */
794   if (gc && clip_rect.origin.y < 5)
795     {
796       clip_rect.origin.y -= FRAME_INTERNAL_BORDER_WIDTH (f);
797       clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
798     }
800   /* likewise at bottom */
801   if (gc &&
802       FRAME_PIXEL_HEIGHT (f) - (clip_rect.origin.y + clip_rect.size.height) < 5)
803     clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
805   ns_focus (f, &clip_rect, 1);
809 static void
810 ns_ring_bell ()
811 /* --------------------------------------------------------------------------
812      "Beep" routine
813    -------------------------------------------------------------------------- */
815   NSTRACE (ns_ring_bell);
816   if (visible_bell)
817     {
818       NSAutoreleasePool *pool;
819       struct frame *frame = SELECTED_FRAME ();
820       NSView *view;
822       BLOCK_INPUT;
823       pool = [[NSAutoreleasePool alloc] init];
825       view = FRAME_NS_VIEW (frame);
826       if (view != nil)
827         {
828           NSRect r, surr;
829           NSPoint dim = NSMakePoint (128, 128);
831           r = [view bounds];
832           r.origin.x += (r.size.width - dim.x) / 2;
833           r.origin.y += (r.size.height - dim.y) / 2;
834           r.size.width = dim.x;
835           r.size.height = dim.y;
836           surr = NSInsetRect (r, -2, -2);
837           ns_focus (frame, &surr, 1);
838           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
839           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
840                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
841           NSRectFill (r);
842           [[view window] flushWindow];
843           ns_timeout (150000);
844           [[view window] restoreCachedImage];
845           [[view window] flushWindow];
846           ns_unfocus (frame);
847         }
848       [pool release];
849       UNBLOCK_INPUT;
850     }
851   else
852     {
853       NSBeep ();
854     }
858 static void
859 ns_reset_terminal_modes (struct terminal *terminal)
860 /*  Externally called as hook */
862   NSTRACE (ns_reset_terminal_modes);
865 static void
866 ns_set_terminal_modes (struct terminal *terminal)
867 /*  Externally called as hook */
869   NSTRACE (ns_set_terminal_modes);
874 /* ==========================================================================
876     Frame / window manager related functions
878    ========================================================================== */
881 static void
882 ns_raise_frame (struct frame *f)
883 /* --------------------------------------------------------------------------
884      Bring window to foreground and make it active
885    -------------------------------------------------------------------------- */
887   NSView *view = FRAME_NS_VIEW (f);
888   check_ns ();
889   BLOCK_INPUT;
890   [[view window] makeKeyAndOrderFront: NSApp];
891   UNBLOCK_INPUT;
895 static void
896 ns_lower_frame (struct frame *f)
897 /* --------------------------------------------------------------------------
898      Send window to back
899    -------------------------------------------------------------------------- */
901   NSView *view = FRAME_NS_VIEW (f);
902   check_ns ();
903   BLOCK_INPUT;
904   [[view window] orderBack: NSApp];
905   UNBLOCK_INPUT;
909 static void
910 ns_frame_raise_lower (struct frame *f, int raise)
911 /* --------------------------------------------------------------------------
912      External (hook)
913    -------------------------------------------------------------------------- */
915   NSTRACE (ns_frame_raise_lower);
917   if (raise)
918     ns_raise_frame (f);
919   else
920     ns_lower_frame (f);
924 static void
925 ns_frame_rehighlight (struct frame *frame)
926 /* --------------------------------------------------------------------------
927      External (hook): called on things like window switching within frame
928    -------------------------------------------------------------------------- */
930   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
931   struct frame *old_highlight = dpyinfo->x_highlight_frame;
933   NSTRACE (ns_frame_rehighlight);
934   if (dpyinfo->x_focus_frame)
935     {
936       dpyinfo->x_highlight_frame
937         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
938            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
939            : dpyinfo->x_focus_frame);
940       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
941         {
942           FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
943           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
944         }
945     }
946   else
947       dpyinfo->x_highlight_frame = 0;
949   if (dpyinfo->x_highlight_frame &&
950          dpyinfo->x_highlight_frame != old_highlight)
951     {
952       if (old_highlight)
953         {
954           x_update_cursor (old_highlight, 1);
955           x_set_frame_alpha (old_highlight);
956         }
957       if (dpyinfo->x_highlight_frame)
958         {
959           x_update_cursor (dpyinfo->x_highlight_frame, 1);
960           x_set_frame_alpha (dpyinfo->x_highlight_frame);
961         }
962     }
966 void
967 x_make_frame_visible (struct frame *f)
968 /* --------------------------------------------------------------------------
969      External: Show the window (X11 semantics)
970    -------------------------------------------------------------------------- */
972   NSTRACE (x_make_frame_visible);
973   /* XXX: at some points in past this was not needed, as the only place that
974      called this (frame.c:Fraise_frame ()) also called raise_lower;
975      if this ends up the case again, comment this out again. */
976   if (!FRAME_VISIBLE_P (f))
977     ns_raise_frame (f);
981 void
982 x_make_frame_invisible (struct frame *f)
983 /* --------------------------------------------------------------------------
984      External: Hide the window (X11 semantics)
985    -------------------------------------------------------------------------- */
987   NSView * view = FRAME_NS_VIEW (f);
988   NSTRACE (x_make_frame_invisible);
989   check_ns ();
990   [[view window] orderOut: NSApp];
991   f->async_visible = 0;
992   f->async_iconified = 0;
996 void
997 x_iconify_frame (struct frame *f)
998 /* --------------------------------------------------------------------------
999      External: Iconify window
1000    -------------------------------------------------------------------------- */
1002   NSView * view = FRAME_NS_VIEW (f);
1003   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1004   NSTRACE (x_iconify_frame);
1005   check_ns ();
1007   if (dpyinfo->x_highlight_frame == f)
1008     dpyinfo->x_highlight_frame = 0;
1010   if ([[view window] windowNumber] <= 0)
1011     {
1012       /* the window is still deferred.  Make it very small, bring it
1013          on screen and order it out. */
1014       NSRect s = { { 100, 100}, {0, 0} };
1015       NSRect t;
1016       t = [[view window] frame];
1017       [[view window] setFrame: s display: NO];
1018       [[view window] orderBack: NSApp];
1019       [[view window] orderOut: NSApp];
1020       [[view window] setFrame: t display: NO];
1021     }
1022   [[view window] miniaturize: NSApp];
1026 void
1027 x_destroy_window (struct frame *f)
1028 /* --------------------------------------------------------------------------
1029      External: Delete the window
1030    -------------------------------------------------------------------------- */
1032   NSView *view = FRAME_NS_VIEW (f);
1033   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1034   NSTRACE (x_destroy_window);
1035   check_ns ();
1037   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1039   BLOCK_INPUT;
1041   free_frame_menubar (f);
1043   if (FRAME_FACE_CACHE (f))
1044     free_frame_faces (f);
1046   if (f == dpyinfo->x_focus_frame)
1047     dpyinfo->x_focus_frame = 0;
1048   if (f == dpyinfo->x_highlight_frame)
1049     dpyinfo->x_highlight_frame = 0;
1050   if (f == dpyinfo->mouse_face_mouse_frame)
1051     {
1052       dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
1053       dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
1054       dpyinfo->mouse_face_window = Qnil;
1055       dpyinfo->mouse_face_deferred_gc = 0;
1056       dpyinfo->mouse_face_mouse_frame = 0;
1057     }
1059   xfree (f->output_data.ns);
1061   [[view window] close];
1062   [view release];
1064   ns_window_num--;
1065   UNBLOCK_INPUT;
1069 void
1070 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1071 /* --------------------------------------------------------------------------
1072      External: Position the window
1073    -------------------------------------------------------------------------- */
1075   NSScreen *screen;
1076   NSView *view = FRAME_NS_VIEW (f);
1078   NSTRACE (x_set_offset);
1080   BLOCK_INPUT;
1082   f->left_pos = xoff;
1083   f->top_pos = yoff;
1084 #ifdef NS_IMPL_GNUSTEP
1085   if (xoff < 100)
1086     f->left_pos = 100;  /* don't overlap menu */
1087 #endif
1088   if (view != nil && (screen = [[view window] screen]))
1089     [[view window] setFrameTopLeftPoint:
1090         NSMakePoint (SCREENMAXBOUND (f->left_pos),
1091                      SCREENMAXBOUND ([screen frame].size.height
1092                                      - NS_TOP_POS (f)))];
1093   UNBLOCK_INPUT;
1097 void
1098 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1099 /* --------------------------------------------------------------------------
1100      Adjust window pixel size based on given character grid size
1101      Impl is a bit more complex than other terms, need to do some
1102      internal clipping and also pay attention to screen constraints.
1103    -------------------------------------------------------------------------- */
1105   EmacsView *view = FRAME_NS_VIEW (f);
1106   EmacsToolbar *toolbar = [view toolbar];
1107   NSWindow *window = [view window];
1108   NSScreen *screen = [window screen];
1109   NSRect wr = [window frame];
1110   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1111   int pixelwidth, pixelheight;
1112   static int oldRows, oldCols, oldFontWidth, oldFontHeight;
1113   static int oldTB;
1114   static struct frame *oldF;
1116   NSTRACE (x_set_window_size);
1118   if (view == nil ||
1119       (f == oldF
1120        && rows == oldRows && cols == oldCols
1121        && oldFontWidth == FRAME_COLUMN_WIDTH (f)
1122        && oldFontHeight == FRAME_LINE_HEIGHT (f)
1123        && oldTB == tb))
1124     return;
1126 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1128   BLOCK_INPUT;
1130   check_frame_size (f, &rows, &cols);
1131   oldF = f;
1132   oldRows = rows;
1133   oldCols = cols;
1134   oldFontWidth = FRAME_COLUMN_WIDTH (f);
1135   oldFontHeight = FRAME_LINE_HEIGHT (f);
1136   oldTB = tb;
1138   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1139   compute_fringe_widths (f, 0);
1141   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1142   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1144   /* If we have a toolbar, take its height into account. */
1145   /* XXX: GNUstep has not yet implemented the first method below, added
1146           in Panther, however the second is incorrect under Cocoa. */
1147   if (tb)
1148     FRAME_NS_TOOLBAR_HEIGHT (f) =
1149 #ifdef NS_IMPL_COCOA
1150       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1151       /* NOTE: previously this would generate wrong result if toolbar not
1152                yet displayed and fixing toolbar_height=32 helped, but
1153                now (200903) seems no longer needed */
1154 #else
1155       NSHeight ([NSWindow frameRectForContentRect: NSMakeRect (0, 0, 0, 0)
1156                                         styleMask: [window styleMask]])
1157 #endif
1158             - FRAME_NS_TITLEBAR_HEIGHT (f);
1159   else
1160     FRAME_NS_TOOLBAR_HEIGHT (f) = 0;
1162   wr.size.width = pixelwidth + f->border_width;
1163   wr.size.height = pixelheight + FRAME_NS_TITLEBAR_HEIGHT (f) 
1164                   + FRAME_NS_TOOLBAR_HEIGHT (f);
1166   /* constrain to screen if we can */
1167   if (screen)
1168     {
1169       NSSize sz = [screen visibleFrame].size;
1170       NSSize ez = { wr.size.width - sz.width, wr.size.height - sz.height };
1171       if (ez.width > 0)
1172         {
1173           int cr = ez.width / FRAME_COLUMN_WIDTH (f) + 1;
1174           cols -= cr;
1175           oldCols = cols;
1176           wr.size.width -= cr * FRAME_COLUMN_WIDTH (f);
1177           pixelwidth -= cr * FRAME_COLUMN_WIDTH (f);
1178         }
1179       if (ez.height > 0)
1180         {
1181           int rr = ez.height / FRAME_LINE_HEIGHT (f) + 1;
1182           rows -= rr;
1183           oldRows = rows;
1184           wr.size.height -= rr * FRAME_LINE_HEIGHT (f);
1185           pixelheight -= rr * FRAME_LINE_HEIGHT (f);
1186         }
1187       wr.origin.x = f->left_pos;
1188       wr.origin.y = [screen frame].size.height - NS_TOP_POS (f)
1189         - wr.size.height;
1190     }
1192   [view setRows: rows andColumns: cols];
1193   [window setFrame: wr display: YES];
1195 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1197   /* This is a trick to compensate for Emacs' managing the scrollbar area
1198      as a fixed number of standard character columns.  Instead of leaving
1199      blank space for the extra, we chopped it off above.  Now for
1200      left-hand scrollbars, we shift all rendering to the left by the
1201      difference between the real width and Emacs' imagined one.  For
1202      right-hand bars, don't worry about it since the extra is never used.
1203      (Obviously doesn't work for vertically split windows tho..) */
1204   NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1205     ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1206                   - NS_SCROLL_BAR_WIDTH (f), 0)
1207     : NSMakePoint (0, 0);
1208   [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1209   [view setBoundsOrigin: origin];
1211   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1212   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1213   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1214 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1216   mark_window_cursors_off (XWINDOW (f->root_window));
1217   cancel_mouse_face (f);
1219   UNBLOCK_INPUT;
1224 /* ==========================================================================
1226     Color management
1228    ========================================================================== */
1231 NSColor *
1232 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1234   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1235   return color_table->colors[idx];
1239 unsigned long
1240 ns_index_color (NSColor *color, struct frame *f)
1242   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1243   int idx;
1244   NSNumber *index;
1246   if (!color_table->colors)
1247     {
1248       color_table->size = NS_COLOR_CAPACITY;
1249       color_table->avail = 1; /* skip idx=0 as marker */
1250       color_table->colors
1251         = (NSColor **)xmalloc (color_table->size * sizeof (NSColor *));
1252       color_table->empty_indices = [[NSMutableSet alloc] init];
1253     }
1255   /* do we already have this color ? */
1256   {
1257     int i;
1258     for (i = 1; i < color_table->avail; i++)
1259       {
1260         if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1261           {
1262             [color_table->colors[i] retain];
1263             return i;
1264           }
1265       }
1266   }
1268   if ([color_table->empty_indices count] > 0)
1269     {
1270       index = [color_table->empty_indices anyObject];
1271       [color_table->empty_indices removeObject: index];
1272       idx = [index unsignedIntValue];
1273     }
1274   else
1275     {
1276       if (color_table->avail == color_table->size)
1277         {
1278           color_table->size += NS_COLOR_CAPACITY;
1279           color_table->colors
1280             = (NSColor **)xrealloc (color_table->colors,
1281                                     color_table->size * sizeof (NSColor *));
1282         }
1283       idx = color_table->avail++;
1284     }
1286   color_table->colors[idx] = color;
1287   [color retain];
1288 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1289   return idx;
1293 void
1294 ns_free_indexed_color (unsigned long idx, struct frame *f)
1296   struct ns_color_table *color_table;
1297   NSColor *color;
1298   NSNumber *index;
1300   if (!f)
1301     return;
1303   color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1305   if (idx <= 0 || idx >= color_table->size) {
1306     message1("ns_free_indexed_color: Color index out of range.\n");
1307     return;
1308   }
1310   index = [NSNumber numberWithUnsignedInt: idx];
1311   if ([color_table->empty_indices containsObject: index]) {
1312     message1("ns_free_indexed_color: attempt to free already freed color.\n");
1313     return;
1314   }
1316   color = color_table->colors[idx];
1317   [color release];
1318   color_table->colors[idx] = nil;
1319   [color_table->empty_indices addObject: [NSNumber numberWithUnsignedInt: idx]];
1320 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1324 static int
1325 ns_get_color (const char *name, NSColor **col)
1326 /* --------------------------------------------------------------------------
1327      Parse a color name
1328 /* --------------------------------------------------------------------------
1329 /* On *Step, we recognize several color formats, in addition to a catalog
1330    of colors found in the file Emacs.clr. Color formats include:
1331    - #rrggbb or RGBrrggbb where rr, gg, bb specify red, green and blue in hex
1332    - ARGBaarrggbb is similar, with aa being the alpha channel (FF = opaque)
1333    - HSVhhssvv and AHSVaahhssvv (or HSB/AHSB) are similar for hue, saturation,
1334      value;
1335    - CMYKccmmyykk is similar for cyan, magenta, yellow, black. */
1337   NSColor * new = nil;
1338   const char *hex = NULL;
1339   enum { rgb, argb, hsv, ahsv, cmyk, gray } color_space;
1340   NSString *nsname = [NSString stringWithUTF8String: name];
1342 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1343   BLOCK_INPUT;
1345   if ([nsname isEqualToString: @"ns_selection_color"])
1346     {
1347       nsname = ns_selection_color;
1348       name = [ns_selection_color UTF8String];
1349     }
1351   if (name[0] == '0' || name[0] == '1' || name[0] == '.')
1352     {
1353       /* RGB decimal */
1354       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1355       float r, g, b;
1356       [scanner scanFloat: &r];
1357       [scanner scanFloat: &g];
1358       [scanner scanFloat: &b];
1359       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1360       UNBLOCK_INPUT;
1361       return 0;
1362     }
1364   /*  FIXME: emacs seems to downcase everything before passing it here,
1365         which we can work around, except for GRAY, since gray##, where ## is
1366         decimal between 0 and 99, is also an X11 colorname. */
1367   if (name[0] == '#')             /* X11 format */
1368     {
1369       hex = name + 1;
1370       color_space = rgb;
1371     }
1372   else if (!memcmp (name, "RGB", 3) || !memcmp (name, "rgb", 3))
1373     {
1374       hex = name + 3;
1375       color_space = rgb;
1376     }
1377   else if (!memcmp (name, "ARGB", 4) || !memcmp (name, "argb", 4))
1378     {
1379       hex = name + 4;
1380       color_space = argb;
1381     }
1382   else if (!memcmp (name, "HSV", 3) || !memcmp (name, "hsv", 3) || 
1383            !memcmp (name, "HSB", 3) || !memcmp (name, "hsb", 3))
1384     {
1385       hex = name + 3;
1386       color_space = hsv;
1387     }
1388   else if (!memcmp (name, "AHSV", 4) || !memcmp (name, "ahsv", 4) ||
1389            !memcmp (name, "AHSB", 4) || !memcmp (name, "ahsb", 4))
1390     {
1391       hex = name + 4;
1392       color_space = ahsv;
1393     }
1394   else if (!memcmp (name, "CMYK", 4) || !memcmp (name, "cmyk", 4))
1395     {
1396       hex = name + 4;
1397       color_space = cmyk;
1398     }
1399   else if (!memcmp (name, "GRAY", 4) /*|| !memcmp (name, "gray", 4)*/)
1400     {
1401       hex = name + 4;
1402       color_space = gray;
1403     }
1405   /* Direct colors (hex values) */
1406   if (hex)
1407     {
1408       unsigned long long color = 0;
1409       if (sscanf (hex, "%x", &color))
1410         {
1411           float f1, f2, f3, f4;
1412           /* Assume it's either 1 byte or 2 per channel... */
1413           if (strlen(hex) > 8) {
1414             f1 = ((color >> 48) & 0xffff) / 65535.0;
1415             f2 = ((color >> 32) & 0xffff) / 65535.0;
1416             f3 = ((color >> 16) & 0xffff) / 65535.0;
1417             f4 = ((color      ) & 0xffff) / 65535.0;
1418           } else {
1419             f1 = ((color >> 24) & 0xff) / 255.0;
1420             f2 = ((color >> 16) & 0xff) / 255.0;
1421             f3 = ((color >>  8) & 0xff) / 255.0;
1422             f4 = ((color      ) & 0xff) / 255.0;
1423           }
1425           switch (color_space)
1426             {
1427             case rgb:
1428               *col = [NSColor colorWithCalibratedRed: f2
1429                                                green: f3
1430                                                 blue: f4
1431                                                alpha: 1.0];
1432               break;
1433             case argb:
1434               *col = [NSColor colorWithCalibratedRed: f2
1435                                                green: f3
1436                                                 blue: f4
1437                                                alpha: f1];
1438               break;
1439             case hsv:
1440               *col = [NSColor colorWithCalibratedHue: f2
1441                                           saturation: f3
1442                                           brightness: f4
1443                                                alpha: 1.0];
1444               break;
1445             case ahsv:
1446               *col = [NSColor colorWithCalibratedHue: f2
1447                                           saturation: f3
1448                                           brightness: f4
1449                                                alpha: f1];
1450               break;
1451             case gray:
1452               *col = [NSColor colorWithCalibratedWhite: f3 alpha: f4];
1453               break;
1454             case cmyk:
1455               *col = [NSColor colorWithDeviceCyan: f1
1456                                           magenta: f2
1457                                            yellow: f3
1458                                             black: f4
1459                                             alpha: 1.0];
1460               break;
1461             }
1462           *col = [*col colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1463           UNBLOCK_INPUT;
1464           return 0;
1465         }
1466     }
1468   /* Otherwise, color is expected to be from a list */
1469   {
1470     NSEnumerator *lenum, *cenum;
1471     NSString *name;
1472     NSColorList *clist;
1474 #ifdef NS_IMPL_GNUSTEP
1475     /* XXX: who is wrong, the requestor or the implementation? */
1476     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1477         == NSOrderedSame)
1478       nsname = @"highlightColor";
1479 #endif
1481     lenum = [[NSColorList availableColorLists] objectEnumerator];
1482     while ( (clist = [lenum nextObject]) && new == nil)
1483       {
1484         cenum = [[clist allKeys] objectEnumerator];
1485         while ( (name = [cenum nextObject]) && new == nil )
1486           {
1487             if ([name compare: nsname
1488                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1489               new = [clist colorWithKey: name];
1490           }
1491       }
1492   }
1494   if ( new )
1495     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1496 /*     else
1497        NSLog (@"Failed to find color '%@'", nsname); */
1498   UNBLOCK_INPUT;
1499   return new ? 0 : 1;
1503 static NSColor *
1504 ns_get_color_default (const char *name, NSColor *dflt)
1505 /* --------------------------------------------------------------------------
1506      Parse a color or use a default value
1507    -------------------------------------------------------------------------- */
1509   NSColor * col;
1511   if (ns_get_color (name, &col))
1512     return dflt;
1513   else
1514     return col;
1519 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1520 /* --------------------------------------------------------------------------
1521      Convert a Lisp string object to a NS color
1522    -------------------------------------------------------------------------- */
1524   NSTRACE (ns_lisp_to_color);
1525   if (STRINGP (color))
1526     return ns_get_color (SDATA (color), col);
1527   else if (SYMBOLP (color))
1528     return ns_get_color (SDATA (SYMBOL_NAME (color)), col);
1529   return 1;
1533 Lisp_Object
1534 ns_color_to_lisp (NSColor *col)
1535 /* --------------------------------------------------------------------------
1536      Convert a color to a lisp string with the RGB equivalent
1537    -------------------------------------------------------------------------- */
1539   float red, green, blue, alpha, gray;
1540   char buf[1024];
1541   const char *str;
1542   NSTRACE (ns_color_to_lisp);
1544   BLOCK_INPUT;
1545   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1547       if ((str =[[col colorNameComponent] UTF8String]))
1548         {
1549           UNBLOCK_INPUT;
1550           return build_string ((char *)str);
1551         }
1553     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1554         getRed: &red green: &green blue: &blue alpha: &alpha];
1555   if (red ==green && red ==blue)
1556     {
1557       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1558             getWhite: &gray alpha: &alpha];
1559       snprintf (buf, sizeof (buf), "GRAY%02.2lx%02.2lx",
1560                lrint (gray * 0xff), lrint (alpha * 0xff));
1561       UNBLOCK_INPUT;
1562       return build_string (buf);
1563     }
1565   snprintf (buf, sizeof (buf), "ARGB%02.2lx%02.2lx%02.2lx%02.2lx",
1566             lrint (alpha*0xff),
1567             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1569   UNBLOCK_INPUT;
1570   return build_string (buf);
1574 void
1575 ns_query_color(void *col, XColor *color_def, int setPixel)
1576 /* --------------------------------------------------------------------------
1577          Get ARGB values out of NSColor col and put them into color_def.
1578          If setPixel, set the pixel to a concatenated version.
1579          and set color_def pixel to the resulting index.
1580    -------------------------------------------------------------------------- */
1582   float r, g, b, a;
1584   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1585   color_def->red   = r * 65535;
1586   color_def->green = g * 65535;
1587   color_def->blue  = b * 65535;
1589   if (setPixel == YES)
1590     color_def->pixel
1591       = ARGB_TO_ULONG((int)(a*255),
1592                       (int)(r*255), (int)(g*255), (int)(b*255));
1597 ns_defined_color (struct frame *f, char *name, XColor *color_def, int alloc,
1598                   char makeIndex)
1599 /* --------------------------------------------------------------------------
1600          Return 1 if named color found, and set color_def rgb accordingly.
1601          If makeIndex and alloc are nonzero put the color in the color_table,
1602          and set color_def pixel to the resulting index.
1603          If makeIndex is zero, set color_def pixel to ARGB.
1604          Return 0 if not found
1605    -------------------------------------------------------------------------- */
1607   NSColor *temp;
1608   int notFound = ns_get_color (name, &temp);
1610   NSTRACE (ns_defined_color);
1612   if (notFound)
1613     return 0;
1615   if (makeIndex && alloc)
1616       color_def->pixel = ns_index_color(temp, f); /* [temp retain]; */
1618   ns_query_color (temp, color_def, !makeIndex);
1620   return 1;
1624 unsigned long
1625 ns_get_rgb_color (struct frame *f, float r, float g, float b, float a)
1626 /* --------------------------------------------------------------------------
1627     return an autoreleased RGB color
1628    -------------------------------------------------------------------------- */
1630 /*static int c = 1; fprintf (stderr, "color request %d\n", c++); */
1631   if (r < 0.0) r = 0.0;
1632   else if (r > 1.0) r = 1.0;
1633   if (g < 0.0) g = 0.0;
1634   else if (g > 1.0) g = 1.0;
1635   if (b < 0.0) b = 0.0;
1636   else if (b > 1.0) b = 1.0;
1637   if (a < 0.0) a = 0.0;
1638   else if (a > 1.0) a = 1.0;
1639   return (unsigned long) ns_index_color(
1640     [NSColor colorWithCalibratedRed: r green: g blue: b alpha: a], f);
1644 void
1645 x_set_frame_alpha (struct frame *f)
1646 /* --------------------------------------------------------------------------
1647      change the entire-frame transparency
1648    -------------------------------------------------------------------------- */
1650   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1651   EmacsView *view = FRAME_NS_VIEW (f);
1652   double alpha = 1.0;
1653   double alpha_min = 1.0;
1655   if (dpyinfo->x_highlight_frame == f)
1656     alpha = f->alpha[0];
1657   else
1658     alpha = f->alpha[1];
1660   if (FLOATP (Vframe_alpha_lower_limit))
1661     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1662   else if (INTEGERP (Vframe_alpha_lower_limit))
1663     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1665   if (alpha < 0.0)
1666     return;
1667   else if (1.0 < alpha)
1668     alpha = 1.0;
1669   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1670     alpha = alpha_min;
1672 #ifdef NS_IMPL_COCOA
1673   [[view window] setAlphaValue: alpha];
1674 #endif
1678 /* ==========================================================================
1680     Mouse handling
1682    ========================================================================== */
1685 void
1686 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1687 /* --------------------------------------------------------------------------
1688      Programmatically reposition mouse pointer in pixel coordinates
1689    -------------------------------------------------------------------------- */
1691   NSTRACE (x_set_mouse_pixel_position);
1692   ns_raise_frame (f);
1693 #if 0
1694   /* FIXME: this does not work, and what about GNUstep? */
1695 #ifdef NS_IMPL_COCOA
1696   [FRAME_NS_VIEW (f) lockFocus];
1697   PSsetmouse ((float)pix_x, (float)pix_y);
1698   [FRAME_NS_VIEW (f) unlockFocus];
1699 #endif
1700 #endif
1704 void
1705 x_set_mouse_position (struct frame *f, int h, int v)
1706 /* --------------------------------------------------------------------------
1707      Programmatically reposition mouse pointer in character coordinates
1708    -------------------------------------------------------------------------- */
1710   int pix_x, pix_y;
1712   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1713   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1715   if (pix_x < 0) pix_x = 0;
1716   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1718   if (pix_y < 0) pix_y = 0;
1719   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1721   x_set_mouse_pixel_position (f, pix_x, pix_y);
1725 static int
1726 note_mouse_movement (struct frame *frame, float x, float y)
1727 /*   ------------------------------------------------------------------------
1728      Called by EmacsView on mouseMovement events.  Passes on
1729      to emacs mainstream code if we moved off of a rect of interest
1730      known as last_mouse_glyph.
1731      ------------------------------------------------------------------------ */
1733 //  NSTRACE (note_mouse_movement);
1735   XSETFRAME (last_mouse_motion_frame, frame);
1737   /* Note, this doesn't get called for enter/leave, since we don't have a
1738      position.  Those are taken care of in the corresponding NSView methods. */
1740   /* has movement gone beyond last rect we were tracking? */
1741   if (x < last_mouse_glyph.origin.x ||
1742       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1743       y < last_mouse_glyph.origin.y ||
1744       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1745     {
1746       frame->mouse_moved = 1;
1747       note_mouse_highlight (frame, x, y);
1748       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1749       return 1;
1750     }
1752   return 0;
1756 static void
1757 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1758                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1759                    unsigned long *time)
1760 /* --------------------------------------------------------------------------
1761     External (hook): inform emacs about mouse position and hit parts.
1762     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1763     x & y should be position in the scrollbar (the whole bar, not the handle)
1764     and length of scrollbar respectively
1765    -------------------------------------------------------------------------- */
1767   id view;
1768   NSPoint position;
1769   int xchar, ychar;
1770   Lisp_Object frame, tail;
1771   struct frame *f;
1772   struct ns_display_info *dpyinfo;
1774   NSTRACE (ns_mouse_position);
1776   if (*fp == NULL)
1777     {
1778       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1779       return;
1780     }
1782   dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1784   BLOCK_INPUT;
1786   if (last_mouse_scroll_bar != nil && insist == 0)
1787     {
1788       /* TODO: we do not use this path at the moment because drag events will
1789            go directly to the EmacsScroller.  Leaving code in for now. */
1790       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1791                                               x: x y: y];
1792       if (time) *time = last_mouse_movement_time;
1793       last_mouse_scroll_bar = nil;
1794     }
1795   else
1796     {
1797       /* Clear the mouse-moved flag for every frame on this display.  */
1798       FOR_EACH_FRAME (tail, frame)
1799         if (FRAME_NS_P (XFRAME (frame))
1800             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1801           XFRAME (frame)->mouse_moved = 0;
1803       last_mouse_scroll_bar = nil;
1804       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1805         f = last_mouse_frame;
1806       else
1807         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1808                                     : SELECTED_FRAME ();
1810       if (f && f->output_data.ns)  /* TODO: 2nd check no longer needed? */
1811         {
1812           view = FRAME_NS_VIEW (*fp);
1814           position = [[view window] mouseLocationOutsideOfEventStream];
1815           position = [view convertPoint: position fromView: nil];
1816           remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1817 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1819           if (bar_window) *bar_window = Qnil;
1820           if (part) *part = 0; /*scroll_bar_handle; */
1822           if (x) XSETINT (*x, lrint (position.x));
1823           if (y) XSETINT (*y, lrint (position.y));
1824           if (time) *time = last_mouse_movement_time;
1825           *fp = f;
1826         }
1827     }
1829   UNBLOCK_INPUT;
1833 static void
1834 ns_frame_up_to_date (struct frame *f)
1835 /* --------------------------------------------------------------------------
1836     External (hook): Fix up mouse highlighting right after a full update.
1837     Some highlighting was deferred if GC was happening during
1838     note_mouse_highlight (), while other highlighting was deferred for update.
1839    -------------------------------------------------------------------------- */
1841   NSTRACE (ns_frame_up_to_date);
1843   if (FRAME_NS_P (f))
1844     {
1845       struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1846       if ((dpyinfo->mouse_face_deferred_gc||f ==dpyinfo->mouse_face_mouse_frame)
1847       /*&& dpyinfo->mouse_face_mouse_frame*/)
1848         {
1849           BLOCK_INPUT;
1850           if (dpyinfo->mouse_face_mouse_frame)
1851             note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
1852                                   dpyinfo->mouse_face_mouse_x,
1853                                   dpyinfo->mouse_face_mouse_y);
1854           dpyinfo->mouse_face_deferred_gc = 0;
1855           UNBLOCK_INPUT;
1856         }
1857     }
1861 void
1862 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1863 /* --------------------------------------------------------------------------
1864     External (RIF): set frame mouse pointer type.
1865    -------------------------------------------------------------------------- */
1867   NSTRACE (ns_define_frame_cursor);
1868   if (FRAME_POINTER_TYPE (f) != cursor)
1869     {
1870       EmacsView *view = FRAME_NS_VIEW (f);
1871       FRAME_POINTER_TYPE (f) = cursor;
1872       [[view window] invalidateCursorRectsForView: view];
1873     }
1878 /* ==========================================================================
1880     Keyboard handling
1882    ========================================================================== */
1885 static unsigned
1886 ns_convert_key (unsigned code)
1887 /* --------------------------------------------------------------------------
1888     Internal call used by NSView-keyDown.
1889    -------------------------------------------------------------------------- */
1891   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1892                                 / sizeof (convert_ns_to_X_keysym[0]));
1893   unsigned keysym;
1894   /* An array would be faster, but less easy to read. */
1895   for (keysym = 0; keysym < last_keysym; keysym += 2)
1896     if (code == convert_ns_to_X_keysym[keysym])
1897       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1898   return 0;
1899 /* if decide to use keyCode and Carbon table, use this line:
1900      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1904 char *
1905 x_get_keysym_name (int keysym)
1906 /* --------------------------------------------------------------------------
1907     Called by keyboard.c.  Not sure if the return val is important, except
1908     that it be unique.
1909    -------------------------------------------------------------------------- */
1911   static char value[16];
1912   NSTRACE (x_get_keysym_name);
1913   sprintf (value, "%d", keysym);
1914   return value;
1919 /* ==========================================================================
1921     Block drawing operations
1923    ========================================================================== */
1926 static void
1927 ns_redraw_scroll_bars (struct frame *f)
1929   int i;
1930   id view;
1931   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1932   NSTRACE (ns_judge_scroll_bars);
1933   for (i =[subviews count]-1; i >= 0; i--)
1934     {
1935       view = [subviews objectAtIndex: i];
1936       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1937       [view display];
1938     }
1942 void
1943 ns_clear_frame (struct frame *f)
1944 /* --------------------------------------------------------------------------
1945       External (hook): Erase the entire frame
1946    -------------------------------------------------------------------------- */
1948   NSView *view = FRAME_NS_VIEW (f);
1949   NSRect r;
1951   NSTRACE (ns_clear_frame);
1952   if (ns_in_resize)
1953     return;
1955  /* comes on initial frame because we have
1956     after-make-frame-functions = select-frame */
1957  if (!FRAME_DEFAULT_FACE (f))
1958    return;
1960   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
1962   output_cursor.hpos = output_cursor.vpos = 0;
1963   output_cursor.x = -1;
1965   r = [view bounds];
1967   BLOCK_INPUT;
1968   ns_focus (f, &r, 1);
1969   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
1970   NSRectFill (r);
1971   ns_unfocus (f);
1973 #ifdef NS_IMPL_COCOA
1974   [[view window] display];  /* redraw resize handle */
1975 #endif
1977   /* as of 2006/11 or so this is now needed */
1978   ns_redraw_scroll_bars (f);
1979   UNBLOCK_INPUT;
1983 void
1984 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
1985 /* --------------------------------------------------------------------------
1986     External (RIF):  Clear section of frame
1987    -------------------------------------------------------------------------- */
1989   NSRect r = NSMakeRect (x, y, width, height);
1990   NSView *view = FRAME_NS_VIEW (f);
1991   struct face *face = FRAME_DEFAULT_FACE (f);
1993   if (!view || !face)
1994     return;
1996   NSTRACE (ns_clear_frame_area);
1998   r = NSIntersectionRect (r, [view frame]);
1999   ns_focus (f, &r, 1);
2000   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2002 #ifdef NS_IMPL_COCOA
2003   {
2004     /* clip out the resize handle */
2005     NSWindow *window = [FRAME_NS_VIEW (f) window];
2006     NSRect ir
2007       = [view convertRect: ns_resize_handle_rect (window) fromView: nil];
2009     ir = NSIntersectionRect (r, ir);
2010     if (NSIsEmptyRect (ir))
2011       {
2012 #endif
2014   NSRectFill (r);
2016 #ifdef NS_IMPL_COCOA
2017       }
2018     else
2019       {
2020         NSRect r1 = r, r2 = r; /* upper and lower non-intersecting */
2021         r1.size.height -= ir.size.height;
2022         r2.origin.y += r1.size.height;
2023         r2.size.width -= ir.size.width;
2024         r2.size.height = ir.size.height;
2025         NSRectFill (r1);
2026         NSRectFill (r2);
2027       }
2028   }
2029 #endif
2031   ns_unfocus (f);
2032   return;
2036 static void
2037 ns_scroll_run (struct window *w, struct run *run)
2038 /* --------------------------------------------------------------------------
2039     External (RIF):  Insert or delete n lines at line vpos
2040    -------------------------------------------------------------------------- */
2042   struct frame *f = XFRAME (w->frame);
2043   int x, y, width, height, from_y, to_y, bottom_y;
2045   NSTRACE (ns_scroll_run);
2047   /* begin copy from other terms */
2048   /* Get frame-relative bounding box of the text display area of W,
2049      without mode lines.  Include in this box the left and right
2050      fringe of W.  */
2051   window_box (w, -1, &x, &y, &width, &height);
2053   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2054   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2055   bottom_y = y + height;
2057   if (to_y < from_y)
2058     {
2059       /* Scrolling up.  Make sure we don't copy part of the mode
2060          line at the bottom.  */
2061       if (from_y + run->height > bottom_y)
2062         height = bottom_y - from_y;
2063       else
2064         height = run->height;
2065     }
2066   else
2067     {
2068       /* Scolling down.  Make sure we don't copy over the mode line.
2069          at the bottom.  */
2070       if (to_y + run->height > bottom_y)
2071         height = bottom_y - to_y;
2072       else
2073         height = run->height;
2074     }
2075   /* end copy from other terms */
2077   if (height == 0)
2078       return;
2080   BLOCK_INPUT;
2082   updated_window = w;
2083   x_clear_cursor (w);
2085   {
2086     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2087     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2088     NSPoint dstOrigin = NSMakePoint (x, to_y);
2090     ns_focus (f, &dstRect, 1);
2091     NSCopyBits (0, srcRect , dstOrigin);
2092     ns_unfocus (f);
2093   }
2095   UNBLOCK_INPUT;
2099 static void
2100 ns_after_update_window_line (struct glyph_row *desired_row)
2101 /* --------------------------------------------------------------------------
2102     External (RIF): preparatory to fringe update after text was updated
2103    -------------------------------------------------------------------------- */
2105   struct window *w = updated_window;
2106   struct frame *f;
2107   int width, height;
2109   NSTRACE (ns_after_update_window_line);
2111   /* begin copy from other terms */
2112   xassert (w);
2114   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2115     desired_row->redraw_fringe_bitmaps_p = 1;
2117   /* When a window has disappeared, make sure that no rest of
2118      full-width rows stays visible in the internal border.
2119      Under NS this is drawn inside the fringes. */
2120   if (windows_or_buffers_changed
2121       && (f = XFRAME (w->frame),
2122           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2123           width != 0)
2124       && (height = desired_row->visible_height,
2125           height > 0))
2126     {
2127       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2129       /* Internal border is drawn below the tool bar.  */
2130       if (WINDOWP (f->tool_bar_window)
2131           && w == XWINDOW (f->tool_bar_window))
2132         y -= width;
2133       /* end copy from other terms */
2135       BLOCK_INPUT;
2136       if (!desired_row->full_width_p)
2137         {
2138           int x1 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2139             + WINDOW_LEFT_FRINGE_WIDTH (w);
2140           int x2 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2141             + FRAME_PIXEL_WIDTH (f) - NS_SCROLL_BAR_WIDTH (f)
2142             - WINDOW_RIGHT_FRINGE_WIDTH (w)
2143             - FRAME_INTERNAL_BORDER_WIDTH (f);
2144           ns_clear_frame_area (f, x1, y, width, height);
2145           ns_clear_frame_area (f, x2, y, width, height);
2146         }
2147       UNBLOCK_INPUT;
2148     }
2152 static void
2153 ns_shift_glyphs_for_insert (struct frame *f,
2154                            int x, int y, int width, int height,
2155                            int shift_by)
2156 /* --------------------------------------------------------------------------
2157     External (RIF): copy an area horizontally, don't worry about clearing src
2158    -------------------------------------------------------------------------- */
2160   NSRect srcRect = NSMakeRect (x, y, width, height);
2161   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2162   NSPoint dstOrigin = dstRect.origin;
2164   NSTRACE (ns_shift_glyphs_for_insert);
2166   ns_focus (f, &dstRect, 1);
2167   NSCopyBits (0, srcRect, dstOrigin);
2168   ns_unfocus (f);
2173 /* ==========================================================================
2175     Character encoding and metrics
2177    ========================================================================== */
2180 static inline void
2181 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2182 /* --------------------------------------------------------------------------
2183      External (RIF); compute left/right overhang of whole string and set in s
2184    -------------------------------------------------------------------------- */
2186   struct face *face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2187   struct font *font = s->font; /*face->font; */
2189   if (s->char2b)
2190     {
2191       struct font_metrics metrics;
2192       unsigned int codes[2];
2193       codes[0] = *(s->char2b);
2194       codes[1] = *(s->char2b + s->nchars - 1);
2196       font->driver->text_extents (font, codes, 2, &metrics);
2197       s->left_overhang = -metrics.lbearing;
2198       s->right_overhang
2199         = metrics.rbearing > metrics.width
2200         ? metrics.rbearing - metrics.width : 0;
2201     }
2202   else
2203     {
2204       s->left_overhang = 0;
2205       s->right_overhang = ((struct nsfont_info *)font)->ital ?
2206         FONT_HEIGHT (font) * 0.2 : 0;
2207     }
2212 /* ==========================================================================
2214     Fringe and cursor drawing
2216    ========================================================================== */
2219 extern int max_used_fringe_bitmap;
2220 static void
2221 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2222                       struct draw_fringe_bitmap_params *p)
2223 /* --------------------------------------------------------------------------
2224     External (RIF); fringe-related
2225    -------------------------------------------------------------------------- */
2227   struct frame *f = XFRAME (WINDOW_FRAME (w));
2228   struct face *face = p->face;
2229   int rowY;
2230   static EmacsImage **bimgs = NULL;
2231   static int nBimgs = 0;
2232   /* NS-specific: move internal border inside fringe */
2233   int x = p->bx < 0 ? p->x : p->bx;
2234   int wd = p->bx < 0 ? p->wd : p->nx;
2235   BOOL fringeOnVeryLeft
2236     = x - WINDOW_LEFT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w)
2237       - FRAME_INTERNAL_BORDER_WIDTH (f) < 10;
2238   BOOL fringeOnVeryRight
2239     = FRAME_PIXEL_WIDTH (f) - x - wd - FRAME_INTERNAL_BORDER_WIDTH (f)
2240       - WINDOW_RIGHT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w) < 10;
2241   int xAdjust = FRAME_INTERNAL_BORDER_WIDTH (f) *
2242     (fringeOnVeryLeft ? -1 : (fringeOnVeryRight ? 1 : 0));
2244   /* grow bimgs if needed */
2245   if (nBimgs < max_used_fringe_bitmap)
2246     {
2247       EmacsImage **newBimgs
2248         = xmalloc (max_used_fringe_bitmap * sizeof (EmacsImage *));
2249       bzero (newBimgs, max_used_fringe_bitmap * sizeof (EmacsImage *));
2251       if (nBimgs)
2252         {
2253           bcopy (bimgs, newBimgs, nBimgs * sizeof (EmacsImage *));
2254           xfree (bimgs);
2255         }
2257       bimgs = newBimgs;
2258       nBimgs = max_used_fringe_bitmap;
2259     }
2261   /* Must clip because of partially visible lines.  */
2262   rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2263   if (p->y < rowY)
2264     {
2265       /* Adjust position of "bottom aligned" bitmap on partially
2266          visible last row.  */
2267       int oldY = row->y;
2268       int oldVH = row->visible_height;
2269       row->visible_height = p->h;
2270       row->y -= rowY - p->y;
2271       ns_clip_to_row (w, row, -1, NO);
2272       row->y = oldY;
2273       row->visible_height = oldVH;
2274     }
2275   else
2276     ns_clip_to_row (w, row, -1, YES);
2278   if (p->bx >= 0 && !p->overlay_p)
2279     {
2280       int yAdjust = rowY - FRAME_INTERNAL_BORDER_WIDTH (f) < 5 ?
2281         -FRAME_INTERNAL_BORDER_WIDTH (f) : 0;
2282       int yIncr = FRAME_PIXEL_HEIGHT (f) - (p->by+yAdjust + p->ny) < 5 ?
2283         FRAME_INTERNAL_BORDER_WIDTH (f) : 0;
2284       if (yAdjust)
2285         yIncr += FRAME_INTERNAL_BORDER_WIDTH (f);
2286       NSRect r = NSMakeRect (p->bx+xAdjust, p->by+yAdjust, p->nx, p->ny+yIncr);
2287       NSRectClip (r);
2288       [ns_lookup_indexed_color(face->background, f) set];
2289       NSRectFill (r);
2290     }
2292   if (p->which)
2293     {
2294       NSRect r = NSMakeRect (p->x+xAdjust, p->y, p->wd, p->h);
2295       NSPoint pt = r.origin;
2296       EmacsImage *img = bimgs[p->which - 1];
2298       if (!img)
2299         {
2300           unsigned short *bits = p->bits + p->dh;
2301           int len = 8 * p->h/8;
2302           int i;
2303           unsigned char *cbits = xmalloc (len);
2305           for (i =0; i<len; i++)
2306             cbits[i] = ~(bits[i] & 0xff);
2307           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2308                                            flip: NO];
2309           bimgs[p->which - 1] = img;
2310           xfree (cbits);
2311         }
2313       NSRectClip (r);
2314       /* Since we composite the bitmap instead of just blitting it, we need
2315          to erase the whole background. */
2316       [ns_lookup_indexed_color(face->background, f) set];
2317       NSRectFill (r);
2318       pt.y += p->h;
2319       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2320       [img compositeToPoint: pt operation: NSCompositeSourceOver];
2321     }
2322   ns_unfocus (f);
2326 void
2327 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2328                        int x, int y, int cursor_type, int cursor_width,
2329                        int on_p, int active_p)
2330 /* --------------------------------------------------------------------------
2331      External call (RIF): draw cursor
2332      (modeled after x_draw_window_cursor
2333      FIXME: cursor_width is effectively bogus -- it sometimes gets set
2334      in xdisp.c set_frame_cursor_types, sometimes left uninitialized;
2335      DON'T USE IT (no other terms do)
2336    -------------------------------------------------------------------------- */
2338   NSRect r, s;
2339   int fx, fy, h;
2340   struct frame *f = WINDOW_XFRAME (w);
2341   struct glyph *phys_cursor_glyph;
2342   int overspill, cursorToDraw;
2344   NSTRACE (dumpcursor);
2345 //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);
2347   if (!on_p)
2348         return;
2350   w->phys_cursor_type = cursor_type;
2351   w->phys_cursor_on_p = on_p;
2353   if (cursor_type == NO_CURSOR)
2354     {
2355       w->phys_cursor_width = 0;
2356       return;
2357     }
2359   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2360     {
2361       if (glyph_row->exact_window_width_line_p
2362           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2363         {
2364           glyph_row->cursor_in_fringe_p = 1;
2365           draw_fringe_bitmap (w, glyph_row, 0);
2366         }
2367       return;
2368     }
2370   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2372   r.origin.x = fx, r.origin.y = fy;
2373   r.size.height = h;
2374   r.size.width = w->phys_cursor_width;
2376   /* FIXME: if we overwrite the internal border area, it does not get erased;
2377      fix by truncating cursor, but better would be to erase properly */
2378   overspill = r.origin.x + r.size.width -
2379     WINDOW_TEXT_TO_FRAME_PIXEL_X (w, WINDOW_BOX_RIGHT_EDGE_X (w) 
2380       - WINDOW_TOTAL_FRINGE_WIDTH (w) - FRAME_INTERNAL_BORDER_WIDTH (f));
2381   if (overspill > 0)
2382     r.size.width -= overspill;
2384   /* TODO: only needed in rare cases with last-resort font in HELLO..
2385      should we do this more efficiently? */
2386   ns_clip_to_row (w, glyph_row, -1, NO); /* do ns_focus(f, &r, 1); if remove */
2387   [FRAME_CURSOR_COLOR (f) set];
2389 #ifdef NS_IMPL_COCOA
2390   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2391            atomic.  Cleaner ways of doing this should be investigated.
2392            One way would be to set a global variable DRAWING_CURSOR
2393            when making the call to draw_phys..(), don't focus in that
2394            case, then move the ns_unfocus() here after that call. */
2395   NSDisableScreenUpdates ();
2396 #endif
2398   cursorToDraw = active_p ? cursor_type : HOLLOW_BOX_CURSOR;
2399   switch (cursorToDraw)
2400     {
2401     case NO_CURSOR:
2402       break;
2403     case FILLED_BOX_CURSOR:
2404       NSRectFill (r);
2405       break;
2406     case HOLLOW_BOX_CURSOR:
2407       NSRectFill (r);
2408       [FRAME_BACKGROUND_COLOR (f) set];
2409       NSRectFill (NSInsetRect (r, 1, 1));
2410       [FRAME_CURSOR_COLOR (f) set];
2411       break;
2412     case HBAR_CURSOR:
2413       s = r;
2414       s.origin.y += lrint (0.75 * s.size.height);
2415       s.size.height = lrint (s.size.height * 0.25);
2416       NSRectFill (s);
2417       break;
2418     case BAR_CURSOR:
2419       s = r;
2420       s.size.width = min (cursor_width, 2); //FIXME(see above)
2421       NSRectFill (s);
2422       break;
2423     }
2424   ns_unfocus (f);
2426   /* draw the character under the cursor */
2427   if (cursorToDraw != NO_CURSOR)
2428     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2430 #ifdef NS_IMPL_COCOA
2431   NSEnableScreenUpdates ();
2432 #endif
2437 static void
2438 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2439 /* --------------------------------------------------------------------------
2440      External (RIF): Draw a vertical line.
2441    -------------------------------------------------------------------------- */
2443   struct frame *f = XFRAME (WINDOW_FRAME (w));
2444   struct face *face;
2445   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2447   NSTRACE (ns_draw_vertical_window_border);
2449   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2450   if (face)
2451       [ns_lookup_indexed_color(face->foreground, f) set];
2453   ns_focus (f, &r, 1);
2454   NSRectFill(r);
2455   ns_unfocus (f);
2459 void
2460 show_hourglass (struct atimer *timer)
2462   if (hourglass_shown_p)
2463     return;
2465   BLOCK_INPUT;
2467   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2469   hourglass_shown_p = 1;
2470   UNBLOCK_INPUT;
2474 void
2475 hide_hourglass ()
2477   if (!hourglass_shown_p)
2478     return;
2480   BLOCK_INPUT;
2482   /* TODO: remove NSProgressIndicator from all frames */
2484   hourglass_shown_p = 0;
2485   UNBLOCK_INPUT;
2490 /* ==========================================================================
2492     Glyph drawing operations
2494    ========================================================================== */
2497 static inline NSRect
2498 ns_fix_rect_ibw (NSRect r, int fibw, int frame_pixel_width)
2499 /* --------------------------------------------------------------------------
2500     Under NS we draw internal borders inside fringes, and want full-width
2501     rendering to go all the way to edge.  This function makes that correction.
2502    -------------------------------------------------------------------------- */
2504   if (r.origin.y <= fibw+1)
2505     {
2506       r.size.height += r.origin.y;
2507       r.origin.y = 0;
2508     }
2509   if (r.origin.x <= fibw+1)
2510     {
2511       r.size.width += r.origin.x;
2512       r.origin.x = 0;
2513     }
2514   if (frame_pixel_width - (r.origin.x+r.size.width) <= fibw+1)
2515     r.size.width += fibw;
2517   return r;
2521 static int
2522 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2523 /* --------------------------------------------------------------------------
2524     Wrapper utility to account for internal border width on full-width lines,
2525     and allow top full-width rows to hit the frame top.  nr should be pointer
2526     to two successive NSRects.  Number of rects actually used is returned.
2527    -------------------------------------------------------------------------- */
2529   int n = get_glyph_string_clip_rects (s, nr, 2);
2530   if (s->row->full_width_p)
2531     {
2532       *nr = ns_fix_rect_ibw (*nr, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2533                             FRAME_PIXEL_WIDTH (s->f));
2534       if (n == 2)
2535         *nr = ns_fix_rect_ibw (*(nr+1), FRAME_INTERNAL_BORDER_WIDTH (s->f),
2536                               FRAME_PIXEL_WIDTH (s->f));
2537     }
2538   return n;
2542 static void
2543 ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char right_p)
2544 /* --------------------------------------------------------------------------
2545     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2546     Note we can't just use an NSDrawRect command, because of the possibility
2547     of some sides not being drawn, and because the rect will be filled.
2548    -------------------------------------------------------------------------- */
2550   NSRect s = r;
2551   [col set];
2553   /* top, bottom */
2554   s.size.height = thickness;
2555   NSRectFill (s);
2556   s.origin.y += r.size.height - thickness;
2557   NSRectFill (s);
2559   s.size.height = r.size.height;
2560   s.origin.y = r.origin.y;
2562   /* left, right (optional) */
2563   s.size.width = thickness;
2564   if (left_p)
2565     NSRectFill (s);
2566   if (right_p)
2567     {
2568       s.origin.x += r.size.width - thickness;
2569       NSRectFill (s);
2570     }
2574 static void
2575 ns_draw_relief (NSRect r, int thickness, char raised_p,
2576                char top_p, char bottom_p, char left_p, char right_p,
2577                struct glyph_string *s)
2578 /* --------------------------------------------------------------------------
2579     Draw a relief rect inside r, optionally leaving some sides open.
2580     Note we can't just use an NSDrawBezel command, because of the possibility
2581     of some sides not being drawn, and because the rect will be filled.
2582    -------------------------------------------------------------------------- */
2584   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2585   NSColor *newBaseCol = nil;
2586   NSRect sr = r;
2588   NSTRACE (ns_draw_relief);
2590   /* set up colors */
2592   if (s->face->use_box_color_for_shadows_p)
2593     {
2594       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2595     }
2596 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2597            && s->img->pixmap
2598            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2599        {
2600          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2601        } */
2602   else
2603     {
2604       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2605     }
2607   if (newBaseCol == nil)
2608     newBaseCol = [NSColor grayColor];
2610   if (newBaseCol != baseCol)  /* TODO: better check */
2611     {
2612       [baseCol release];
2613       baseCol = [newBaseCol retain];
2614       [lightCol release];
2615       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2616       [darkCol release];
2617       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2618     }
2620   [(raised_p ? lightCol : darkCol) set];
2622   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2624   /* top */
2625   sr.size.height = thickness;
2626   if (top_p) NSRectFill (sr);
2628   /* left */
2629   sr.size.height = r.size.height;
2630   sr.size.width = thickness;
2631   if (left_p) NSRectFill (sr);
2633   [(raised_p ? darkCol : lightCol) set];
2635   /* bottom */
2636   sr.size.width = r.size.width;
2637   sr.size.height = thickness;
2638   sr.origin.y += r.size.height - thickness;
2639   if (bottom_p) NSRectFill (sr);
2641   /* right */
2642   sr.size.height = r.size.height;
2643   sr.origin.y = r.origin.y;
2644   sr.size.width = thickness;
2645   sr.origin.x += r.size.width - thickness;
2646   if (right_p) NSRectFill (sr);
2650 static void
2651 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2652 /* --------------------------------------------------------------------------
2653       Function modeled after x_draw_glyph_string_box ().
2654       Sets up parameters for drawing.
2655    -------------------------------------------------------------------------- */
2657   int right_x, last_x;
2658   char left_p, right_p;
2659   struct glyph *last_glyph;
2660   NSRect r;
2661   int thickness;
2662   struct face *face;
2664   if (s->hl == DRAW_MOUSE_FACE)
2665     {
2666       face = FACE_FROM_ID
2667         (s->f, FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
2668       if (!face)
2669         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2670     }
2671   else
2672     face = s->face;
2674   thickness = face->box_line_width;
2676   NSTRACE (ns_dumpglyphs_box_or_relief);
2678   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2679             ? WINDOW_RIGHT_EDGE_X (s->w)
2680             : window_box_right (s->w, s->area));
2681   last_glyph = (s->cmp || s->img
2682                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2684   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2685               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2687   left_p = (s->first_glyph->left_box_line_p
2688             || (s->hl == DRAW_MOUSE_FACE
2689                 && (s->prev == NULL || s->prev->hl != s->hl)));
2690   right_p = (last_glyph->right_box_line_p
2691              || (s->hl == DRAW_MOUSE_FACE
2692                  && (s->next == NULL || s->next->hl != s->hl)));
2694   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2696   /* expand full-width row over internal borders */
2697   if (s->row->full_width_p)
2698     r = ns_fix_rect_ibw (r, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2699                         FRAME_PIXEL_WIDTH (s->f));
2701   if (s->face->box == FACE_SIMPLE_BOX)
2702     {
2703       xassert (s->face->box_color != nil);
2704       ns_draw_box (r, abs (thickness),
2705                    ns_lookup_indexed_color (face->box_color, s->f),
2706                   left_p, right_p);
2707     }
2708   else
2709     {
2710       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2711                      1, 1, left_p, right_p, s);
2712     }
2716 static void
2717 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2718 /* --------------------------------------------------------------------------
2719       Modeled after x_draw_glyph_string_background, which draws BG in
2720       certain cases.  Others are left to the text rendering routine.
2721    -------------------------------------------------------------------------- */
2723   NSTRACE (ns_maybe_dumpglyphs_background);
2725   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2726     {
2727       int box_line_width = max (s->face->box_line_width, 0);
2728       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2729           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2730         {
2731           struct face *face;
2732           if (s->hl == DRAW_MOUSE_FACE)
2733             {
2734               face = FACE_FROM_ID
2735                 (s->f, FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
2736               if (!face)
2737                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2738             }
2739           else
2740             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2741           if (!face->stipple)
2742             [(NS_FACE_BACKGROUND (face) != 0
2743               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2744               : FRAME_BACKGROUND_COLOR (s->f)) set];
2745           else
2746             {
2747               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2748               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2749             }
2751           if (s->hl != DRAW_CURSOR)
2752             {
2753               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2754                                     s->background_width,
2755                                     s->height-2*box_line_width);
2757               /* expand full-width row over internal borders */
2758               if (s->row->full_width_p)
2759                 {
2760                   int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2761                   if (r.origin.y <= fibw+1 + box_line_width)
2762                     {
2763                       r.size.height += r.origin.y;
2764                       r.origin.y = 0;
2765                     }
2766                   if (r.origin.x <= fibw+1)
2767                     {
2768                       r.size.width += 2*r.origin.x;
2769                       r.origin.x = 0;
2770                     }
2771                   if (FRAME_PIXEL_WIDTH (s->f) - (r.origin.x + r.size.width)
2772                       <= fibw+1)
2773                     r.size.width += fibw;
2774                 }
2776               NSRectFill (r);
2777             }
2779           s->background_filled_p = 1;
2780         }
2781     }
2785 static void
2786 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2787 /* --------------------------------------------------------------------------
2788       Renders an image and associated borders.
2789    -------------------------------------------------------------------------- */
2791   EmacsImage *img = s->img->pixmap;
2792   int box_line_vwidth = max (s->face->box_line_width, 0);
2793   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2794   int bg_x, bg_y, bg_height;
2795   int th;
2796   char raised_p;
2797   NSRect br;
2799   NSTRACE (ns_dumpglyphs_image);
2801   if (s->face->box != FACE_NO_BOX
2802       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2803     x += abs (s->face->box_line_width);
2805   bg_x = x;
2806   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2807   bg_height = s->height;
2808   /* other terms have this, but was causing problems w/tabbar mode */
2809   /* - 2 * box_line_vwidth; */
2811   if (s->slice.x == 0) x += s->img->hmargin;
2812   if (s->slice.y == 0) y += s->img->vmargin;
2814   /* Draw BG: if we need larger area than image itself cleared, do that,
2815      otherwise, since we composite the image under NS (instead of mucking
2816      with its background color), we must clear just the image area. */
2817   [ns_lookup_indexed_color (NS_FACE_BACKGROUND
2818             (FACE_FROM_ID (s->f, s->first_glyph->face_id)), s->f) set];
2820   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2821       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2822     {
2823       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
2824       s->background_filled_p = 1;
2825     }
2826   else
2827     {
2828       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
2829     }
2831   /* expand full-width row over internal borders */
2832   if (s->row->full_width_p)
2833     {
2834       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2835       if (br.origin.y <= fibw+1 + box_line_vwidth)
2836         {
2837           br.size.height += br.origin.y;
2838           br.origin.y = 0;
2839         }
2840       if (br.origin.x <= fibw+1 + box_line_vwidth)
2841         {
2842           br.size.width += br.origin.x;
2843           br.origin.x = 0;
2844         }
2845       if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) <= fibw+1)
2846         br.size.width += fibw;
2847     }
2849   NSRectFill (br);
2851   /* Draw the image.. do we need to draw placeholder if img ==nil? */
2852   if (img != nil)
2853     [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
2854                 operation: NSCompositeSourceOver];
2856   /* Draw relief, if requested */
2857   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
2858     {
2859       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
2860         {
2861           th = tool_bar_button_relief >= 0 ?
2862             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
2863           raised_p = (s->hl == DRAW_IMAGE_RAISED);
2864         }
2865       else
2866         {
2867           th = abs (s->img->relief);
2868           raised_p = (s->img->relief > 0);
2869         }
2871       r.origin.x = x - th;
2872       r.origin.y = y - th;
2873       r.size.width = s->slice.width + 2*th-1;
2874       r.size.height = s->slice.height + 2*th-1;
2875       ns_draw_relief (r, th, raised_p,
2876                       s->slice.y == 0,
2877                       s->slice.y + s->slice.height == s->img->height,
2878                       s->slice.x == 0,
2879                       s->slice.x + s->slice.width == s->img->width, s);
2880     }
2884 static void
2885 ns_dumpglyphs_stretch (struct glyph_string *s)
2887   NSRect r[2];
2888   int n, i;
2890   if (!s->background_filled_p)
2891     {
2892       n = ns_get_glyph_string_clip_rect (s, r);
2893       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
2895       for (i=0; i<n; i++)
2896         {
2897           if (!s->row->full_width_p)
2898             {
2899               /* truncate to avoid overwriting fringe and/or scrollbar */
2900               int overrun = max (0, (s->x + s->background_width)
2901                                   - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
2902                                     - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
2903               r[i].size.width -= overrun;
2905               /* XXX: Try to work between problem where a stretch glyph on
2906                  a partially-visible bottom row will clear part of the
2907                  modeline, and another where list-buffers headers and similar
2908                  rows erroneously have visible_height set to 0.  Not sure
2909                  where this is coming from as other terms seem not to show. */
2910               r[i].size.height = min (s->height, s->row->visible_height);
2911             }
2913           /* expand full-width rows over internal borders */
2914           else
2915             {
2916               r[i] = ns_fix_rect_ibw (r[i], FRAME_INTERNAL_BORDER_WIDTH (s->f),
2917                                       FRAME_PIXEL_WIDTH (s->f));
2918             }
2920           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
2921              overwriting cursor (usually when cursor on a tab) */
2922           if (s->hl == DRAW_CURSOR)
2923             {
2924               r[i].origin.x += s->width;
2925               r[i].size.width -= s->width;
2926             }
2927         }
2929       ns_focus (s->f, r, n);
2930       [ns_lookup_indexed_color (NS_FACE_BACKGROUND
2931            (FACE_FROM_ID (s->f, s->first_glyph->face_id)), s->f) set];
2932       NSRectFill (r[0]);
2933       NSRectFill (r[1]);
2934       ns_unfocus (s->f);
2935       s->background_filled_p = 1;
2936     }
2940 static void
2941 ns_draw_glyph_string (struct glyph_string *s)
2942 /* --------------------------------------------------------------------------
2943       External (RIF): Main draw-text call.
2944    -------------------------------------------------------------------------- */
2946   /* TODO (optimize): focus for box and contents draw */
2947   NSRect r[2];
2948   int n;
2949   char box_drawn_p = 0;
2951   NSTRACE (ns_draw_glyph_string);
2953   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
2954     {
2955       int width;
2956       struct glyph_string *next;
2958       for (width = 0, next = s->next;
2959            next && width < s->right_overhang;
2960            width += next->width, next = next->next)
2961         if (next->first_glyph->type != IMAGE_GLYPH)
2962           {
2963             if (next->first_glyph->type != STRETCH_GLYPH)
2964               {
2965                 n = ns_get_glyph_string_clip_rect (s->next, r);
2966                 ns_focus (s->f, r, n);
2967                 ns_maybe_dumpglyphs_background (s->next, 1);
2968                 ns_unfocus (s->f);
2969               }
2970             else
2971               {
2972                 ns_dumpglyphs_stretch (s->next);
2973               }
2974             next->num_clips = 0;
2975           }
2976     }
2978   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
2979         && (s->first_glyph->type == CHAR_GLYPH
2980             || s->first_glyph->type == COMPOSITE_GLYPH))
2981     {
2982       n = ns_get_glyph_string_clip_rect (s, r);
2983       ns_focus (s->f, r, n);
2984       ns_maybe_dumpglyphs_background (s, 1);
2985       ns_dumpglyphs_box_or_relief (s);
2986       ns_unfocus (s->f);
2987       box_drawn_p = 1;
2988     }
2990   switch (s->first_glyph->type)
2991     {
2993     case IMAGE_GLYPH:
2994       n = ns_get_glyph_string_clip_rect (s, r);
2995       ns_focus (s->f, r, n);
2996       ns_dumpglyphs_image (s, r[0]);
2997       ns_unfocus (s->f);
2998       break;
3000     case STRETCH_GLYPH:
3001       ns_dumpglyphs_stretch (s);
3002       break;
3004     case CHAR_GLYPH:
3005     case COMPOSITE_GLYPH:
3006       n = ns_get_glyph_string_clip_rect (s, r);
3007       ns_focus (s->f, r, n);
3009       if (s->for_overlaps || (s->cmp_from > 0
3010                               && ! s->first_glyph->u.cmp.automatic))
3011         s->background_filled_p = 1;
3012       else      /* 1 */
3013         ns_maybe_dumpglyphs_background
3014           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3016       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3017                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3018                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3019                       NS_DUMPGLYPH_NORMAL));
3020       ns_tmp_font = (struct nsfont_info *)s->face->font;
3021       if (ns_tmp_font == NULL)
3022           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
3024       ns_tmp_font->font.driver->draw
3025         (s, 0, s->nchars, s->x, s->y,
3026          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3027          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
3029       ns_unfocus (s->f);
3030       break;
3032     default:
3033       abort ();
3034     }
3036   /* Draw box if not done already. */
3037   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3038     {
3039       n = ns_get_glyph_string_clip_rect (s, r);
3040       ns_focus (s->f, r, n);
3041       ns_dumpglyphs_box_or_relief (s);
3042       ns_unfocus (s->f);
3043     }
3045   s->num_clips = 0;
3050 /* ==========================================================================
3052     Event loop
3054    ========================================================================== */
3057 static void
3058 ns_send_appdefined (int value)
3059 /* --------------------------------------------------------------------------
3060     Internal: post an appdefined event which EmacsApp-sendEvent will
3061               recognize and take as a command to halt the event loop.
3062    -------------------------------------------------------------------------- */
3064   /*NSTRACE (ns_send_appdefined); */
3066   /* Only post this event if we haven't already posted one.  This will end
3067        the [NXApp run] main loop after having processed all events queued at
3068        this moment.  */
3069   if (send_appdefined)
3070     {
3071       NSEvent *nxev;
3073       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3074       send_appdefined = NO;
3076       /* Don't need wakeup timer any more */
3077       if (timed_entry)
3078         {
3079           [timed_entry invalidate];
3080           [timed_entry release];
3081           timed_entry = nil;
3082         }
3084       /* Ditto for file descriptor poller */
3085       if (fd_entry)
3086         {
3087           [fd_entry invalidate];
3088           [fd_entry release];
3089           fd_entry = nil;
3090         }
3092       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3093                                 location: NSMakePoint (0, 0)
3094                            modifierFlags: 0
3095                                timestamp: 0
3096                             windowNumber: [[NSApp mainWindow] windowNumber]
3097                                  context: [NSApp context]
3098                                  subtype: 0
3099                                    data1: value
3100                                    data2: 0];
3102       /* Post an application defined event on the event queue.  When this is
3103          received the [NXApp run] will return, thus having processed all
3104          events which are currently queued.  */
3105       [NSApp postEvent: nxev atStart: NO];
3106     }
3110 static int
3111 ns_read_socket (struct terminal *terminal, int expected,
3112                 struct input_event *hold_quit)
3113 /* --------------------------------------------------------------------------
3114      External (hook): Post an event to ourself and keep reading events until
3115      we read it back again.  In effect process all events which were waiting.
3116      From 21+ we have to manage the event buffer ourselves.
3117    -------------------------------------------------------------------------- */
3119   struct input_event ev;
3120   int nevents;
3121   static NSDate *lastCheck = nil;
3123 /* NSTRACE (ns_read_socket); */
3125   if (interrupt_input_blocked)
3126     {
3127       interrupt_input_pending = 1;
3128 #ifdef SYNC_INPUT
3129       pending_signals = 1;
3130 #endif
3131       return -1;
3132     }
3134   interrupt_input_pending = 0;
3135 #ifdef SYNC_INPUT
3136   pending_signals = pending_atimers;
3137 #endif
3139   BLOCK_INPUT;
3140   n_emacs_events_pending = 0;
3141   EVENT_INIT (ev);
3142   emacs_event = &ev;
3143   q_event_ptr = hold_quit;
3145   /* we manage autorelease pools by allocate/reallocate each time around
3146      the loop; strict nesting is occasionally violated but seems not to
3147      matter.. earlier methods using full nesting caused major memory leaks */
3148   [outerpool release];
3149   outerpool = [[NSAutoreleasePool alloc] init];
3151   /* If have pending open-file requests, attend to the next one of those. */
3152   if (ns_pending_files && [ns_pending_files count] != 0
3153       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3154     {
3155       [ns_pending_files removeObjectAtIndex: 0];
3156     }
3157   /* Deal with pending service requests. */
3158   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3159     && [(EmacsApp *)
3160          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3161                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3162     {
3163       [ns_pending_service_names removeObjectAtIndex: 0];
3164       [ns_pending_service_args removeObjectAtIndex: 0];
3165     }
3166   else
3167     {
3168       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3169          to ourself, otherwise [NXApp run] will never exit.  */
3170       send_appdefined = YES;
3172       /* If called via ns_select, this is called once with expected=1,
3173          because we expect either the timeout or file descriptor activity.
3174          In this case the first event through will either be real input or
3175          one of these.  read_avail_input() then calls once more with expected=0
3176          and in that case we need to return quickly if there is nothing.
3177          If we're being called outside of that, it's also OK to return quickly
3178          after one iteration through the event loop, since other terms do
3179          this and emacs expects it. */
3180       if (!(inNsSelect && expected))  // (!inNsSelect || !expected)
3181         {
3182           /* Post an application defined event on the event queue.  When this is
3183              received the [NXApp run] will return, thus having processed all
3184              events which are currently queued, if any.  */
3185           ns_send_appdefined (-1);
3186         }
3188       [NSApp run];
3189     }
3191   nevents = n_emacs_events_pending;
3192   n_emacs_events_pending = 0;
3193   emacs_event = q_event_ptr = NULL;
3194   UNBLOCK_INPUT;
3196   return nevents;
3201 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3202            fd_set *exceptfds, struct timeval *timeout)
3203 /* --------------------------------------------------------------------------
3204      Replacement for select, checking for events
3205    -------------------------------------------------------------------------- */
3207   int result;
3208   double time;
3209   NSEvent *ev;
3210 /*  NSTRACE (ns_select); */
3212   if (NSApp == nil || inNsSelect == 1 /* || ([NSApp isActive] == NO &&
3213                       [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil
3214  inMode:NSDefaultRunLoopMode dequeue:NO] == nil) */)
3215     return select (nfds, readfds, writefds, exceptfds, timeout);
3217   /* Save file descriptor set, which gets overwritten in calls to select ()
3218      Note, this is called from process.c, and only readfds is ever set */
3219   if (readfds)
3220     {
3221       memcpy (&select_readfds, readfds, sizeof (fd_set));
3222       select_nfds = nfds;
3223     }
3224   else
3225     select_nfds = 0;
3227     /* Try an initial select for pending data on input files */
3228   select_timeout.tv_sec = select_timeout.tv_usec = 0;
3229   result = select (nfds, readfds, writefds, exceptfds, &select_timeout);
3230   if (result)
3231     return result;
3233   /* if (!timeout || timed_entry || fd_entry)
3234        fprintf (stderr, "assertion failed: timeout null or timed_entry/fd_entry non-null in ns_select\n"); */
3236     /* set a timeout and run the main AppKit event loop while continuing
3237        to monitor the files */
3238   time = ((double) timeout->tv_sec) + ((double) timeout->tv_usec)/1000000.0;
3239   timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3240                                            target: NSApp
3241                                          selector: @selector (timeout_handler:)
3242                                          userInfo: 0
3243                                           repeats: YES] /* for safe removal */
3244                                                          retain];
3246   /* set a periodic task to try the select () again */
3247   fd_entry = [[NSTimer scheduledTimerWithTimeInterval: 0.1
3248                                                target: NSApp
3249                                              selector: @selector (fd_handler:)
3250                                              userInfo: 0
3251                                               repeats: YES]
3252                retain];
3254   /* Let Application dispatch events until it receives an event of the type
3255      NX_APPDEFINED, which should only be sent by timeout_handler.
3256      We tell read_avail_input() that input is "expected" because we do expect
3257      either the timeout or fd handler to fire, and if they don't, the original
3258      call from process.c that got us here expects us to wait until some input
3259      comes. */
3260   inNsSelect = 1;
3261   gobble_input (1);
3262   ev = last_appdefined_event;
3263   inNsSelect = 0;
3265   if (ev)
3266     {
3267       int t;
3268       if ([ev type] != NSApplicationDefined)
3269         abort ();
3271       t = [ev data1];
3272       last_appdefined_event = 0;
3274       if (t == -2)
3275         {
3276           /* The NX_APPDEFINED event we received was a timeout. */
3277           return 0;
3278         }
3279       else if (t == -1)
3280         {
3281           /* The NX_APPDEFINED event we received was the result of
3282              at least one real input event arriving.  */
3283           errno = EINTR;
3284           return -1;
3285         }
3286       else
3287         {
3288           /* Received back from select () in fd_handler; copy the results */
3289           if (readfds)
3290             memcpy (readfds, &select_readfds, sizeof (fd_set));
3291           return t;
3292         }
3293     }
3294   /* never reached, shut compiler up */
3295   return 0;
3300 /* ==========================================================================
3302     Scrollbar handling
3304    ========================================================================== */
3307 static void
3308 ns_set_vertical_scroll_bar (struct window *window,
3309                            int portion, int whole, int position)
3310 /* --------------------------------------------------------------------------
3311       External (hook): Update or add scrollbar
3312    -------------------------------------------------------------------------- */
3314   Lisp_Object win;
3315   NSRect r, v;
3316   struct frame *f = XFRAME (WINDOW_FRAME (window));
3317   EmacsView *view = FRAME_NS_VIEW (f);
3318   int window_y, window_height;
3319   BOOL barOnVeryLeft, barOnVeryRight;
3320   int top, left, height, width, sb_width, sb_left;
3321   EmacsScroller *bar;
3322 static int count = 0;
3324   /* optimization; display engine sends WAY too many of these.. */
3325   if (!NILP (window->vertical_scroll_bar))
3326     {
3327       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3328       if ([bar checkSamePosition: position portion: portion whole: whole])
3329         {
3330           if (view->scrollbarsNeedingUpdate == 0)
3331             {
3332               if (!windows_or_buffers_changed)
3333                   return;
3334             }
3335           else
3336             view->scrollbarsNeedingUpdate--;
3337         }
3338     }
3340   NSTRACE (ns_set_vertical_scroll_bar);
3342   /* Get dimensions.  */
3343   window_box (window, -1, 0, &window_y, 0, &window_height);
3344   top = window_y;
3345   height = window_height;
3346   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3347   left = WINDOW_SCROLL_BAR_AREA_X (window);
3349   if (top < 5) /* top scrollbar adjustment */
3350     {
3351       top -= FRAME_INTERNAL_BORDER_WIDTH (f);
3352       height += FRAME_INTERNAL_BORDER_WIDTH (f);
3353     }
3355   /* allow for displaying a skinnier scrollbar than char area allotted */
3356   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3357     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3359   barOnVeryLeft = left < 5;
3360   barOnVeryRight = FRAME_PIXEL_WIDTH (f) - left - width < 5;
3361   sb_left = left + FRAME_INTERNAL_BORDER_WIDTH (f)
3362       * (barOnVeryLeft ? -1 : (barOnVeryRight ? 1 : 0));
3364   r = NSMakeRect (sb_left, top, sb_width, height);
3365   /* the parent view is flipped, so we need to flip y value */
3366   v = [view frame];
3367   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3369   XSETWINDOW (win, window);
3370   BLOCK_INPUT;
3372   /* we want at least 5 lines to display a scrollbar */
3373   if (WINDOW_TOTAL_LINES (window) < 5)
3374     {
3375       if (!NILP (window->vertical_scroll_bar))
3376         {
3377           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3378           [bar removeFromSuperview];
3379           window->vertical_scroll_bar = Qnil;
3380         }
3381       ns_clear_frame_area (f, sb_left, top, width, height);
3382       UNBLOCK_INPUT;
3383       return;
3384     }
3386   if (NILP (window->vertical_scroll_bar))
3387     {
3388       ns_clear_frame_area (f, sb_left, top, width, height);
3389       bar = [[EmacsScroller alloc] initFrame: r window: win];
3390       window->vertical_scroll_bar = make_save_value (bar, 0);
3391     }
3392   else
3393     {
3394       NSRect oldRect;
3395       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3396       oldRect = [bar frame];
3397       r.size.width = oldRect.size.width;
3398       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3399         {
3400           if (oldRect.origin.x != r.origin.x)
3401               ns_clear_frame_area (f, sb_left, top, width, height);
3402           [bar setFrame: r];
3403         }
3404     }
3406   [bar setPosition: position portion: portion whole: whole];
3407   UNBLOCK_INPUT;
3411 static void
3412 ns_condemn_scroll_bars (struct frame *f)
3413 /* --------------------------------------------------------------------------
3414      External (hook): arrange for all frame's scrollbars to be removed
3415      at next call to judge_scroll_bars, except for those redeemed.
3416    -------------------------------------------------------------------------- */
3418   int i;
3419   id view;
3420   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3422   NSTRACE (ns_condemn_scroll_bars);
3424   for (i =[subviews count]-1; i >= 0; i--)
3425     {
3426       view = [subviews objectAtIndex: i];
3427       if ([view isKindOfClass: [EmacsScroller class]])
3428         [view condemn];
3429     }
3433 static void
3434 ns_redeem_scroll_bar (struct window *window)
3435 /* --------------------------------------------------------------------------
3436      External (hook): arrange to spare this window's scrollbar
3437      at next call to judge_scroll_bars.
3438    -------------------------------------------------------------------------- */
3440   id bar;
3441   NSTRACE (ns_redeem_scroll_bar);
3442   if (!NILP (window->vertical_scroll_bar))
3443     {
3444       bar =XNS_SCROLL_BAR (window->vertical_scroll_bar);
3445       [bar reprieve];
3446     }
3450 static void
3451 ns_judge_scroll_bars (struct frame *f)
3452 /* --------------------------------------------------------------------------
3453      External (hook): destroy all scrollbars on frame that weren't
3454      redeemed after call to condemn_scroll_bars.
3455    -------------------------------------------------------------------------- */
3457   int i;
3458   id view;
3459   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3460   NSTRACE (ns_judge_scroll_bars);
3461   for (i =[subviews count]-1; i >= 0; i--)
3462     {
3463       view = [subviews objectAtIndex: i];
3464       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3465       [view judge];
3466     }
3470 void
3471 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
3473   /* XXX irrelevant under NS */
3478 /* ==========================================================================
3480     Initialization
3482    ========================================================================== */
3485 x_display_pixel_height (dpyinfo)
3486      struct ns_display_info *dpyinfo;
3488   NSScreen *screen = [NSScreen mainScreen];
3489   return [screen frame].size.height;
3493 x_display_pixel_width (dpyinfo)
3494      struct ns_display_info *dpyinfo;
3496   NSScreen *screen = [NSScreen mainScreen];
3497   return [screen frame].size.width;
3501 static Lisp_Object ns_string_to_lispmod (const char *s)
3502 /* --------------------------------------------------------------------------
3503      Convert modifier name to lisp symbol
3504    -------------------------------------------------------------------------- */
3506   if (!strncmp (SDATA (SYMBOL_NAME (Qmeta)), s, 10))
3507     return Qmeta;
3508   else if (!strncmp (SDATA (SYMBOL_NAME (Qsuper)), s, 10))
3509     return Qsuper;
3510   else if (!strncmp (SDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3511     return Qcontrol;
3512   else if (!strncmp (SDATA (SYMBOL_NAME (Qalt)), s, 10))
3513     return Qalt;
3514   else if (!strncmp (SDATA (SYMBOL_NAME (Qhyper)), s, 10))
3515     return Qhyper;
3516   else if (!strncmp (SDATA (SYMBOL_NAME (Qnone)), s, 10))
3517     return Qnone;
3518   else
3519     return Qnil;
3523 static Lisp_Object ns_mod_to_lisp (int m)
3524 /* --------------------------------------------------------------------------
3525      Convert modifier code (see lisp.h) to lisp symbol
3526    -------------------------------------------------------------------------- */
3528   if (m == CHAR_META)
3529     return Qmeta;
3530   else if (m == CHAR_SUPER)
3531     return Qsuper;
3532   else if (m == CHAR_CTL)
3533     return Qcontrol;
3534   else if (m == CHAR_ALT)
3535     return Qalt;
3536   else if (m == CHAR_HYPER)
3537     return Qhyper;
3538   else /* if (m == 0) */
3539     return Qnone;
3543 static void
3544 ns_set_default_prefs ()
3545 /* --------------------------------------------------------------------------
3546       Initialize preference variables to defaults
3547    -------------------------------------------------------------------------- */
3549   ns_alternate_modifier = Qmeta;
3550   ns_command_modifier = Qsuper;
3551   ns_control_modifier = Qcontrol;
3552   ns_function_modifier = Qnone;
3553   ns_antialias_text = Qt;
3554   ns_antialias_threshold = 10.0; /* not exposed to lisp side */
3555   ns_use_qd_smoothing = Qnil;
3556   ns_use_system_highlight_color = Qt;
3557   ns_confirm_quit = Qnil;
3561 static void
3562 ns_default (const char *parameter, Lisp_Object *result,
3563            Lisp_Object yesval, Lisp_Object noval,
3564            BOOL is_float, BOOL is_modstring)
3565 /* --------------------------------------------------------------------------
3566       Check a parameter value in user's preferences
3567    -------------------------------------------------------------------------- */
3569   const char *value;
3571   if ( (value =[[[NSUserDefaults standardUserDefaults]
3572                    stringForKey: [NSString stringWithUTF8String: parameter]]
3573                 UTF8String]) )
3574     {
3575       double f;
3576       char *pos;
3577       if (strcasecmp (value, "YES") == 0)
3578         *result = yesval;
3579       else if (strcasecmp (value, "NO") == 0)
3580         *result = noval;
3581       else if (is_float && (f = strtod (value, &pos), pos != value))
3582         *result = make_float (f);
3583       else if (is_modstring && value)
3584         *result = ns_string_to_lispmod (value);
3585       else fprintf (stderr,
3586                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3587     }
3591 void
3592 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3593 /* --------------------------------------------------------------------------
3594       Initialize global info and storage for display.
3595    -------------------------------------------------------------------------- */
3597     NSScreen *screen = [NSScreen mainScreen];
3598     NSWindowDepth depth = [screen depth];
3600     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3601     dpyinfo->resy = 72.27;
3602     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3603                                                   NSColorSpaceFromDepth (depth)]
3604                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3605                                                  NSColorSpaceFromDepth (depth)];
3606     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3607     dpyinfo->image_cache = make_image_cache ();
3608     dpyinfo->color_table
3609       = (struct ns_color_table *)xmalloc (sizeof (struct ns_color_table));
3610     dpyinfo->color_table->colors = NULL;
3611     dpyinfo->root_window = 42; /* a placeholder.. */
3613     dpyinfo->mouse_face_mouse_frame = NULL;
3614     dpyinfo->mouse_face_deferred_gc = 0;
3615     dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
3616     dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
3617     dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
3618     dpyinfo->mouse_face_window = dpyinfo->mouse_face_overlay = Qnil;
3619     dpyinfo->mouse_face_hidden = 0;
3621     dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
3622     dpyinfo->mouse_face_defer = 0;
3624     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3626     dpyinfo->n_fonts = 0;
3627     dpyinfo->smallest_font_height = 1;
3628     dpyinfo->smallest_char_width = 1;
3632 /* This and next define (many of the) public functions in this file. */
3633 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3634          with using despite presence in the "system dependent" redisplay
3635          interface.  In addition, many of the ns_ methods have code that is
3636          shared with all terms, indicating need for further refactoring. */
3637 extern frame_parm_handler ns_frame_parm_handlers[];
3638 static struct redisplay_interface ns_redisplay_interface =
3640   ns_frame_parm_handlers,
3641   x_produce_glyphs,
3642   x_write_glyphs,
3643   x_insert_glyphs,
3644   x_clear_end_of_line,
3645   ns_scroll_run,
3646   ns_after_update_window_line,
3647   ns_update_window_begin,
3648   ns_update_window_end,
3649   x_cursor_to,
3650   ns_flush,
3651   0, /* flush_display_optional */
3652   x_clear_window_mouse_face,
3653   x_get_glyph_overhangs,
3654   x_fix_overlapping_area,
3655   ns_draw_fringe_bitmap,
3656   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3657   0, /* destroy_fringe_bitmap */
3658   ns_compute_glyph_string_overhangs,
3659   ns_draw_glyph_string, /* interface to nsfont.m */
3660   ns_define_frame_cursor,
3661   ns_clear_frame_area,
3662   ns_draw_window_cursor,
3663   ns_draw_vertical_window_border,
3664   ns_shift_glyphs_for_insert
3668 static void
3669 ns_delete_display (struct ns_display_info *dpyinfo)
3671   /* TODO... */
3675 /* This function is called when the last frame on a display is deleted. */
3676 static void
3677 ns_delete_terminal (struct terminal *terminal)
3679   struct ns_display_info *dpyinfo = terminal->display_info.ns;
3680   int i;
3682   /* Protect against recursive calls.  delete_frame in
3683      delete_terminal calls us back when it deletes our last frame.  */
3684   if (!terminal->name)
3685     return;
3687   BLOCK_INPUT;
3689   x_destroy_all_bitmaps (dpyinfo);
3690   ns_delete_display (dpyinfo);
3691   UNBLOCK_INPUT;
3695 static struct terminal *
3696 ns_create_terminal (struct ns_display_info *dpyinfo)
3697 /* --------------------------------------------------------------------------
3698       Set up use of NS before we make the first connection.
3699    -------------------------------------------------------------------------- */
3701   struct terminal *terminal;
3703   NSTRACE (ns_create_terminal);
3705   terminal = create_terminal ();
3707   terminal->type = output_ns;
3708   terminal->display_info.ns = dpyinfo;
3709   dpyinfo->terminal = terminal;
3711   terminal->rif = &ns_redisplay_interface;
3713   terminal->clear_frame_hook = ns_clear_frame;
3714   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
3715   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
3716   terminal->ring_bell_hook = ns_ring_bell;
3717   terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
3718   terminal->set_terminal_modes_hook = ns_set_terminal_modes;
3719   terminal->update_begin_hook = ns_update_begin;
3720   terminal->update_end_hook = ns_update_end;
3721   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
3722   terminal->read_socket_hook = ns_read_socket;
3723   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
3724   terminal->mouse_position_hook = ns_mouse_position;
3725   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
3726   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
3728   terminal->fullscreen_hook = 0; /* see XTfullscreen_hook */
3730   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
3731   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
3732   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
3733   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
3735   terminal->delete_frame_hook = x_destroy_window;
3736   terminal->delete_terminal_hook = ns_delete_terminal;
3738   terminal->scroll_region_ok = 1;
3739   terminal->char_ins_del_ok = 1;
3740   terminal->line_ins_del_ok = 1;
3741   terminal->fast_clear_end_of_line = 1;
3742   terminal->memory_below_frame = 0;
3744   return terminal;
3748 struct ns_display_info *
3749 ns_term_init (Lisp_Object display_name)
3750 /* --------------------------------------------------------------------------
3751      Start the Application and get things rolling.
3752    -------------------------------------------------------------------------- */
3754   struct terminal *terminal;
3755   struct ns_display_info *dpyinfo;
3756   static int ns_initialized = 0;
3757   Lisp_Object tmp;
3759   NSTRACE (ns_term_init);
3761   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
3762   /*GSDebugAllocationActive (YES); */
3763   BLOCK_INPUT;
3764   handling_signal = 0;
3766   if (!ns_initialized)
3767     {
3768       baud_rate = 38400;
3769       Fset_input_interrupt_mode (Qnil);
3770       ns_initialized = 1;
3771     }
3773   ns_pending_files = [[NSMutableArray alloc] init];
3774   ns_pending_service_names = [[NSMutableArray alloc] init];
3775   ns_pending_service_args = [[NSMutableArray alloc] init];
3777   /* Start app and create the main menu, window, view.
3778      Needs to be here because ns_initialize_display_info () uses AppKit classes.
3779      The view will then ask the NSApp to stop and return to Emacs. */
3780   [EmacsApp sharedApplication];
3781   if (NSApp == nil)
3782     return NULL;
3783   [NSApp setDelegate: NSApp];
3785   /* debugging: log all notifications */
3786   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
3787                                          selector: @selector (logNotification:)
3788                                              name: nil object: nil]; */
3790   dpyinfo = (struct ns_display_info *)xmalloc (sizeof (struct ns_display_info));
3791   bzero (dpyinfo, sizeof (struct ns_display_info));
3793   ns_initialize_display_info (dpyinfo);
3794   terminal = ns_create_terminal (dpyinfo);
3796   terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
3797   init_kboard (terminal->kboard);
3798   terminal->kboard->Vwindow_system = Qns;
3799   terminal->kboard->next_kboard = all_kboards;
3800   all_kboards = terminal->kboard;
3801   /* Don't let the initial kboard remain current longer than necessary.
3802      That would cause problems if a file loaded on startup tries to
3803      prompt in the mini-buffer.  */
3804   if (current_kboard == initial_kboard)
3805     current_kboard = terminal->kboard;
3806   terminal->kboard->reference_count++;
3808   dpyinfo->next = x_display_list;
3809   x_display_list = dpyinfo;
3811   /* Put it on ns_display_name_list */
3812   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
3813                                 ns_display_name_list);
3814   dpyinfo->name_list_element = XCAR (ns_display_name_list);
3816   /* Set the name of the terminal. */
3817   terminal->name = (char *) xmalloc (SBYTES (display_name) + 1);
3818   strncpy (terminal->name, SDATA (display_name), SBYTES (display_name));
3819   terminal->name[SBYTES (display_name)] = 0;
3821   UNBLOCK_INPUT; 
3823   /* Read various user defaults. */
3824   ns_set_default_prefs ();
3825   if (!ns_no_defaults)
3826     {
3827       ns_default ("GSFontAntiAlias", &ns_antialias_text,
3828                  Qt, Qnil, NO, NO);
3829       tmp = Qnil;
3830       /* this is a standard variable */
3831       ns_default ("AppleAntiAliasingThreshold", &tmp,
3832                  make_float (10.0), make_float (6.0), YES, NO);
3833       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
3834     }
3836   ns_selection_color = [[NSUserDefaults standardUserDefaults]
3837                          stringForKey: @"AppleHighlightColor"];
3838   if (ns_selection_color == nil)
3839     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
3840   
3841   {
3842     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
3844     if ( cl == nil )
3845       {
3846         Lisp_Object color_file, color_map, color;
3847         int r,g,b;
3848         unsigned long c;
3849         char *name;
3851         color_file = Fexpand_file_name (build_string ("rgb.txt"),
3852                          Fsymbol_value (intern ("data-directory")));
3853         if (NILP (Ffile_readable_p (color_file)))
3854           fatal ("Could not find %s.\n", SDATA (color_file));
3856         color_map = Fx_load_color_file (color_file);
3857         if (NILP (color_map))
3858           fatal ("Could not read %s.\n", SDATA (color_file));
3860         cl = [[NSColorList alloc] initWithName: @"Emacs"];
3861         for ( ; CONSP (color_map); color_map = XCDR (color_map))
3862           {
3863             color = XCAR (color_map);
3864             name = SDATA (XCAR (color));
3865             c = XINT (XCDR (color));
3866             [cl setColor:
3867                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
3868                                             green: GREEN_FROM_ULONG (c) / 255.0
3869                                              blue: BLUE_FROM_ULONG (c) / 255.0
3870                                             alpha: 1.0]
3871                   forKey: [NSString stringWithUTF8String: name]];
3872           }
3873         [cl writeToFile: nil];
3874       }
3875   }
3877   {
3878     char c[128];
3879 #ifdef NS_IMPL_GNUSTEP
3880     strncpy (c, gnustep_base_version, sizeof (c));
3881 #else
3882     /*PSnextrelease (128, c); */
3883     snprintf (c, sizeof (c), "%g", NSAppKitVersionNumber);
3884 #endif
3885     Vwindow_system_version = build_string (c);
3886   }
3888   delete_keyboard_wait_descriptor (0);
3890 /* Set up OS X app menu */
3891 #ifdef NS_IMPL_COCOA
3892   {
3893     NSMenu *appMenu;
3894     NSMenuItem *item;
3895     /* set up the application menu */
3896     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
3897     [svcsMenu setAutoenablesItems: NO];
3898     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
3899     [appMenu setAutoenablesItems: NO];
3900     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
3901     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
3903     [appMenu insertItemWithTitle: @"About Emacs"
3904                           action: @selector (orderFrontStandardAboutPanel:)
3905                    keyEquivalent: @""
3906                          atIndex: 0];
3907     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
3908     [appMenu insertItemWithTitle: @"Preferences..."
3909                           action: @selector (showPreferencesWindow:)
3910                    keyEquivalent: @","
3911                          atIndex: 2];
3912     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
3913     item = [appMenu insertItemWithTitle: @"Services"
3914                                  action: @selector (menuDown:)
3915                           keyEquivalent: @""
3916                                 atIndex: 4];
3917     [appMenu setSubmenu: svcsMenu forItem: item];
3918 /*    [svcsMenu setSupercell: item]; */
3919     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
3920     [appMenu insertItemWithTitle: @"Hide Emacs"
3921                           action: @selector (hide:)
3922                    keyEquivalent: @"h"
3923                          atIndex: 6];
3924     item =  [appMenu insertItemWithTitle: @"Hide Others"
3925                           action: @selector (hideOtherApplications:)
3926                    keyEquivalent: @"h"
3927                          atIndex: 7];
3928     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
3929     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
3930     [appMenu insertItemWithTitle: @"Quit Emacs"
3931                           action: @selector (terminate:)
3932                    keyEquivalent: @"q"
3933                          atIndex: 9];
3935     item = [mainMenu insertItemWithTitle: @"Emacs"
3936                                   action: @selector (menuDown:)
3937                            keyEquivalent: @""
3938                                  atIndex: 0];
3939     [mainMenu setSubmenu: appMenu forItem: item];
3940     [dockMenu insertItemWithTitle: @"New Frame"
3941                            action: @selector (newFrame:)
3942                     keyEquivalent: @""
3943                           atIndex: 0];
3945     [NSApp setMainMenu: mainMenu];
3946     [NSApp setAppleMenu: appMenu];
3947     [NSApp setServicesMenu: svcsMenu];
3948     /* Needed at least on Cocoa, to get dock menu to show windows */
3949     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
3950   }
3951 #endif /* MAC OS X menu setup */
3953   [NSApp run];
3955   return dpyinfo;
3959 extern Lisp_Object Vauto_save_list_file_name;
3960 void
3961 ns_term_shutdown (int sig)
3963   /* code not reached in emacs.c after this is called by shut_down_emacs: */
3964   if (STRINGP (Vauto_save_list_file_name))
3965     unlink (SDATA (Vauto_save_list_file_name));
3967   if (sig == 0 || sig == SIGTERM)
3968     {
3969       [NSApp terminate: NSApp];
3970     }
3971   else // force a stack trace to happen
3972     {
3973       abort();
3974     }
3978 /* ==========================================================================
3980     EmacsApp implementation
3982    ========================================================================== */
3985 @implementation EmacsApp
3987 - (void)logNotification: (NSNotification *)notification
3989   const char *name = [[notification name] UTF8String];
3990   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
3991       && !strstr (name, "WindowNumber"))
3992     NSLog (@"notification: '%@'", [notification name]);
3996 - (void)sendEvent: (NSEvent *)theEvent
3997 /* --------------------------------------------------------------------------
3998      Called when NSApp is running for each event received.  Used to stop
3999      the loop when we choose, since there's no way to just run one iteration.
4000    -------------------------------------------------------------------------- */
4002   int type = [theEvent type];
4003   NSWindow *window = [theEvent window];
4004 /*  NSTRACE (sendEvent); */
4005 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4007   if (type == NSCursorUpdate && window == nil)
4008     {
4009       fprintf (stderr, "Dropping external cursor update event.\n");
4010       return;
4011     }
4013 #ifdef NS_IMPL_COCOA
4014   /* pass mouse down in resize handle and subsequent drags directly to
4015      EmacsWindow so we can generate continuous redisplays */
4016   if (ns_in_resize)
4017     {
4018       if (type == NSLeftMouseDragged)
4019         {
4020           [window mouseDragged: theEvent];
4021           return;
4022         }
4023       else if (type == NSLeftMouseUp)
4024         {
4025           [window mouseUp: theEvent];
4026           return;
4027         }
4028     }
4029   else if (type == NSLeftMouseDown)
4030     {
4031       NSRect r = ns_resize_handle_rect (window);
4032       if (NSPointInRect ([theEvent locationInWindow], r))
4033         {
4034           ns_in_resize = YES;
4035           [window mouseDown: theEvent];
4036           return;
4037         }
4038     }
4039 #endif
4041   if (type == NSApplicationDefined)
4042     {
4043       /* Events posted by ns_send_appdefined interrupt the run loop here.
4044          But, if a modal window is up, an appdefined can still come through,
4045          (e.g., from a makeKeyWindow event) but stopping self also stops the
4046          modal loop. Just defer it until later. */
4047       if ([NSApp modalWindow] == nil)
4048         {
4049           last_appdefined_event = theEvent;
4050           [self stop: self];
4051         }
4052       else
4053         {
4054           send_appdefined = YES;
4055         }
4056     }
4058   [super sendEvent: theEvent];
4062 - (void)showPreferencesWindow: (id)sender
4064   struct frame *emacsframe = SELECTED_FRAME ();
4065   NSEvent *theEvent = [NSApp currentEvent];
4067   if (!emacs_event)
4068     return;
4069   emacs_event->kind = NS_NONKEY_EVENT;
4070   emacs_event->code = KEY_NS_SHOW_PREFS;
4071   emacs_event->modifiers = 0;
4072   EV_TRAILER (theEvent);
4076 - (void)newFrame: (id)sender
4078   struct frame *emacsframe = SELECTED_FRAME ();
4079   NSEvent *theEvent = [NSApp currentEvent];
4081   if (!emacs_event)
4082     return;
4083   emacs_event->kind = NS_NONKEY_EVENT;
4084   emacs_event->code = KEY_NS_NEW_FRAME;
4085   emacs_event->modifiers = 0;
4086   EV_TRAILER (theEvent);
4090 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4091 - (BOOL) openFile: (NSString *)fileName
4093   struct frame *emacsframe = SELECTED_FRAME ();
4094   NSEvent *theEvent = [NSApp currentEvent];
4096   if (!emacs_event)
4097     return NO;
4099   emacs_event->kind = NS_NONKEY_EVENT;
4100   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4101   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4102   ns_input_line = Qnil; /* can be start or cons start,end */
4103   emacs_event->modifiers =0;
4104   EV_TRAILER (theEvent);
4106   return YES;
4110 /* **************************************************************************
4112       EmacsApp delegate implementation
4114    ************************************************************************** */
4116 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4117 /* --------------------------------------------------------------------------
4118      When application is loaded, terminate event loop in ns_term_init
4119    -------------------------------------------------------------------------- */
4121   NSTRACE (applicationDidFinishLaunching);
4122   [NSApp setServicesProvider: NSApp];
4123   ns_send_appdefined (-2);
4127 /* Termination sequences:
4128     C-x C-c:
4129     Cmd-Q:
4130     MenuBar | File | Exit:
4131     Select Quit from App menubar:
4132         -terminate
4133         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4134         ns_term_shutdown()
4136     Select Quit from Dock menu:
4137     Logout attempt:
4138         -appShouldTerminate
4139           Cancel -> Nothing else
4140           Accept ->
4141           
4142           -terminate
4143           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4144           ns_term_shutdown()
4148 - (void) terminate: (id)sender
4150   struct frame *emacsframe = SELECTED_FRAME ();
4151   
4152   if (!emacs_event)
4153     return;
4154   
4155   emacs_event->kind = NS_NONKEY_EVENT;
4156   emacs_event->code = KEY_NS_POWER_OFF;
4157   emacs_event->arg = Qt; /* mark as non-key event */
4158   EV_TRAILER ((id)nil);
4162 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4164   int ret;
4166   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4167     return NSTerminateNow;
4169     ret = NSRunAlertPanel([[NSProcessInfo processInfo] processName],
4170                           [NSString stringWithUTF8String:"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?"],
4171                           @"Save Buffers and Exit", @"Cancel", nil);
4173     if (ret == NSAlertDefaultReturn)
4174         return NSTerminateNow;
4175     else if (ret == NSAlertAlternateReturn)
4176         return NSTerminateCancel;
4177     return NSTerminateNow;  /* just in case */
4181 /*   Notification from the Workspace to open a file */
4182 - (BOOL)application: sender openFile: (NSString *)file
4184   [ns_pending_files addObject: file];
4185   return YES;
4189 /*   Open a file as a temporary file */
4190 - (BOOL)application: sender openTempFile: (NSString *)file
4192   [ns_pending_files addObject: file];
4193   return YES;
4197 /*   Notification from the Workspace to open a file noninteractively (?) */
4198 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4200   [ns_pending_files addObject: file];
4201   return YES;
4205 /*   Notification from the Workspace to open multiple files */
4206 - (void)application: sender openFiles: (NSArray *)fileList
4208   NSEnumerator *files = [fileList objectEnumerator];
4209   NSString *file;
4210   while ((file = [files nextObject]) != nil)
4211     [ns_pending_files addObject: file];
4213 /* TODO: when GNUstep implements this (and we require that version of
4214          GNUstep), remove. */
4215 #ifndef NS_IMPL_GNUSTEP
4216   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4217 #endif /* !NS_IMPL_GNUSTEP */
4222 /* Handle dock menu requests.  */
4223 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4225   return dockMenu;
4229 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4230 - (void)applicationWillBecomeActive: (NSNotification *)notification
4232   //ns_app_active=YES;
4234 - (void)applicationDidBecomeActive: (NSNotification *)notification
4236   //ns_app_active=YES;
4238 - (void)applicationDidResignActive: (NSNotification *)notification
4240   //ns_app_active=NO;
4241   ns_send_appdefined (-1);
4246 /* ==========================================================================
4248     EmacsApp aux handlers for managing event loop
4250    ========================================================================== */
4253 - (void)timeout_handler: (NSTimer *)timedEntry
4254 /* --------------------------------------------------------------------------
4255      The timeout specified to ns_select has passed.
4256    -------------------------------------------------------------------------- */
4258   /*NSTRACE (timeout_handler); */
4259   ns_send_appdefined (-2);
4262 extern void update_window_cursor (struct window *w, int on);
4264 - (void)fd_handler: (NSTimer *) fdEntry
4265 /* --------------------------------------------------------------------------
4266      Check data waiting on file descriptors and terminate if so
4267    -------------------------------------------------------------------------- */
4269   int result;
4270   /* NSTRACE (fd_handler); */
4272   if (select_nfds == 0)
4273     return;
4275   memcpy (&t_readfds, &select_readfds, sizeof (fd_set));
4277   select_timeout.tv_sec = select_timeout.tv_usec = 0;
4278   result = select (select_nfds, &t_readfds, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
4279                   &select_timeout);
4280   if (result)
4281     {
4282       memcpy (&select_readfds, &t_readfds, sizeof (fd_set));
4283       ns_send_appdefined (result);
4284     }
4289 /* ==========================================================================
4291     Service provision
4293    ========================================================================== */
4295 /* called from system: queue for next pass through event loop */
4296 - (void)requestService: (NSPasteboard *)pboard
4297               userData: (NSString *)userData
4298                  error: (NSString **)error
4300   [ns_pending_service_names addObject: userData];
4301   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4302       SDATA (ns_string_from_pasteboard (pboard))]];
4306 /* called from ns_read_socket to clear queue */
4307 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4309   struct frame *emacsframe = SELECTED_FRAME ();
4310   NSEvent *theEvent = [NSApp currentEvent];
4312   if (!emacs_event)
4313     return NO;
4315   emacs_event->kind = NS_NONKEY_EVENT;
4316   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4317   ns_input_spi_name = build_string ([name UTF8String]);
4318   ns_input_spi_arg = build_string ([arg UTF8String]);
4319   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4320   EV_TRAILER (theEvent);
4322   return YES;
4326 @end  /* EmacsApp */
4330 /* ==========================================================================
4332     EmacsView implementation
4334    ========================================================================== */
4337 @implementation EmacsView
4339 /* needed to inform when window closed from LISP */
4340 - (void) setWindowClosing: (BOOL)closing
4342   windowClosing = closing;
4346 - (void)dealloc
4348   NSTRACE (EmacsView_dealloc);
4349   [toolbar release];
4350   [super dealloc];
4354 /* called on font panel selection */
4355 - (void)changeFont: (id)sender
4357   NSEvent *e =[[self window] currentEvent];
4358   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4359   id newFont;
4360   float size;
4362   NSTRACE (changeFont);
4363   if (!emacs_event)
4364     return;
4366   if (newFont = [sender convertFont:
4367                            ((struct nsfont_info *)face->font)->nsfont])
4368     {
4369       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4371       emacs_event->kind = NS_NONKEY_EVENT;
4372       emacs_event->modifiers = 0;
4373       emacs_event->code = KEY_NS_CHANGE_FONT;
4375       size = [newFont pointSize];
4376       ns_input_fontsize = make_number (lrint (size));
4377       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4378       EV_TRAILER (e);
4379     }
4383 - (BOOL)acceptsFirstResponder
4385   NSTRACE (acceptsFirstResponder);
4386   return YES;
4390 - (void)resetCursorRects
4392   NSRect visible = [self visibleRect];
4393   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4394   NSTRACE (resetCursorRects);
4396   if (currentCursor == nil)
4397     currentCursor = [NSCursor arrowCursor];
4399   if (!NSIsEmptyRect (visible))
4400     [self addCursorRect: visible cursor: currentCursor];
4401   [currentCursor setOnMouseEntered: YES];
4406 /*****************************************************************************/
4407 /* Keyboard handling. */
4408 #define NS_KEYLOG 0
4410 - (void)keyDown: (NSEvent *)theEvent
4412   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
4413   int code;
4414   unsigned fnKeysym = 0;
4415   int flags;
4416   static NSMutableArray *nsEvArray;
4417   static BOOL firstTime = YES;
4419   NSTRACE (keyDown);
4421   /* Rhapsody and OS X give up and down events for the arrow keys */
4422   if (ns_fake_keydown == YES)
4423     ns_fake_keydown = NO;
4424   else if ([theEvent type] != NSKeyDown)
4425     return;
4427   if (!emacs_event)
4428     return;
4430  if (![[self window] isKeyWindow])
4431    {
4432      /* XXX: There is an occasional condition in which, when Emacs display
4433          updates a different frame from the current one, and temporarily
4434          selects it, then processes some interrupt-driven input
4435          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4436          for some reason that window has its first responder set to the NSView
4437          most recently updated (I guess), which is not the correct one. */
4438      if ([[theEvent window] isKindOfClass: [EmacsWindow class]])
4439          [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4440      return;
4441    }
4443   if (nsEvArray == nil)
4444     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4446   [NSCursor setHiddenUntilMouseMoves: YES];
4448   if (dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4449     {
4450       clear_mouse_face (dpyinfo);
4451       dpyinfo->mouse_face_hidden = 1;
4452     }
4454   if (!processingCompose)
4455     {
4456       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4457         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4458       /* (Carbon way: [theEvent keyCode]) */
4460       /* is it a "function key"? */
4461       fnKeysym = ns_convert_key (code);
4462       if (fnKeysym)
4463         {
4464           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4465              because Emacs treats Delete and KP-Delete same (in simple.el). */
4466           if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4467             code = 0xFF08; /* backspace */
4468           else
4469             code = fnKeysym;
4470         }
4472       /* are there modifiers? */
4473       emacs_event->modifiers = 0;
4474       flags = [theEvent modifierFlags];
4476       if (flags & NSHelpKeyMask)
4477           emacs_event->modifiers |= hyper_modifier;
4479       if (flags & NSShiftKeyMask)
4480         emacs_event->modifiers |= shift_modifier;
4482       if (flags & NSCommandKeyMask)
4483         {
4484           emacs_event->modifiers |= parse_solitary_modifier (ns_command_modifier);
4485           /* if super (default), take input manager's word so things like
4486              dvorak / qwerty layout work */
4487           if (EQ (ns_command_modifier, Qsuper)
4488               && !fnKeysym
4489               && [[theEvent characters] length] != 0)
4490             {
4491               /* XXX: the code we get will be unshifted, so if we have
4492                  a shift modifier, must convert ourselves */
4493               if (!(flags & NSShiftKeyMask))
4494                 code = [[theEvent characters] characterAtIndex: 0];
4495 #if 0
4496               /* this is ugly and also requires linking w/Carbon framework
4497                  (for LMGetKbdType) so for now leave this rare (?) case
4498                  undealt with.. in future look into CGEvent methods */
4499               else
4500                 {
4501                   long smv = GetScriptManagerVariable (smKeyScript);
4502                   Handle uchrHandle = GetResource
4503                     ('uchr', GetScriptVariable (smv, smScriptKeys));
4504                   UInt32 dummy = 0;
4505                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
4506                                  [[theEvent characters] characterAtIndex: 0],
4507                                  kUCKeyActionDisplay,
4508                                  (flags & ~NSCommandKeyMask) >> 8,
4509                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
4510                                  &dummy, 1, &dummy, &code);
4511                   code &= 0xFF;
4512                 }
4513 #endif
4514             }
4515         }
4517       if (flags & NSControlKeyMask)
4518           emacs_event->modifiers |=
4519             parse_solitary_modifier (ns_control_modifier);
4521       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
4522           emacs_event->modifiers |=
4523             parse_solitary_modifier (ns_function_modifier);
4525       if (flags & NSAlternateKeyMask) /* default = meta */
4526         {
4527           if ((NILP (ns_alternate_modifier) || EQ (ns_alternate_modifier, Qnone))
4528               && !fnKeysym)
4529             {   /* accept pre-interp alt comb */
4530               if ([[theEvent characters] length] > 0)
4531                 code = [[theEvent characters] characterAtIndex: 0];
4532               /*HACK: clear lone shift modifier to stop next if from firing */
4533               if (emacs_event->modifiers == shift_modifier)
4534                 emacs_event->modifiers = 0;
4535             }
4536           else
4537               emacs_event->modifiers |=
4538                 parse_solitary_modifier (ns_alternate_modifier);
4539         }
4541   if (NS_KEYLOG)
4542     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
4543              code, fnKeysym, flags, emacs_event->modifiers);
4545       /* if it was a function key or had modifiers, pass it directly to emacs */
4546       if (fnKeysym || (emacs_event->modifiers
4547                        && [[theEvent charactersIgnoringModifiers] length] > 0))
4548 /*[[theEvent characters] length] */
4549         {
4550           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4551           if (code < 0x20)
4552             code |= (1<<28)|(3<<16);
4553           else if (code == 0x7f)
4554             code |= (1<<28)|(3<<16);
4555           else if (!fnKeysym)
4556             emacs_event->kind = code > 0xFF
4557               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4559           emacs_event->code = code;
4560           EV_TRAILER (theEvent);
4561           return;
4562         }
4563     }
4565   /* if we get here we should send the key for input manager processing */
4566   if (firstTime && [[NSInputManager currentInputManager]
4567                      wantsToDelayTextChangeNotifications] == NO)
4568     fprintf (stderr,
4569           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
4570   firstTime = NO;
4572   if (NS_KEYLOG && !processingCompose)
4573     fprintf (stderr, "keyDown: Begin compose sequence.\n");
4575   processingCompose = YES;
4576   [nsEvArray addObject: theEvent];
4577   [self interpretKeyEvents: nsEvArray];
4578   [nsEvArray removeObject: theEvent];
4582 #ifdef NS_IMPL_COCOA
4583 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
4584    decided not to send key-down for.
4585    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
4586    If it matches one of these, send it on to keyDown. */
4587 -(void)keyUp: (NSEvent *)theEvent
4589   int flags = [theEvent modifierFlags];
4590   int code = [theEvent keyCode];
4591   if (code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
4592     {
4593       if (NS_KEYLOG)
4594         fprintf (stderr, "keyUp: passed test");
4595       ns_fake_keydown = YES;
4596       [self keyDown: theEvent];
4597     }
4599 #endif
4602 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
4605 /* <NSTextInput>: called when done composing;
4606    NOTE: also called when we delete over working text, followed immed.
4607          by doCommandBySelector: deleteBackward: */
4608 - (void)insertText: (id)aString
4610   int code;
4611   int len = [(NSString *)aString length];
4612   int i;
4614   if (NS_KEYLOG)
4615     NSLog (@"insertText '%@'\tlen = %d", aString, len);
4616   processingCompose = NO;
4618   if (!emacs_event)
4619     return;
4621   /* first, clear any working text */
4622   if (workingText != nil)
4623     [self deleteWorkingText];
4625   /* now insert the string as keystrokes */
4626   for (i =0; i<len; i++)
4627     {
4628       code = [aString characterAtIndex: i];
4629       /* TODO: still need this? */
4630       if (code == 0x2DC)
4631         code = '~'; /* 0x7E */
4632       emacs_event->modifiers = 0;
4633       emacs_event->kind
4634         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4635       emacs_event->code = code;
4636       EV_TRAILER ((id)nil);
4637     }
4641 /* <NSTextInput>: inserts display of composing characters */
4642 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
4644   NSString *str = [aString respondsToSelector: @selector (string)] ?
4645     [aString string] : aString;
4646   if (NS_KEYLOG)
4647     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
4648            selRange.length, selRange.location);
4650   if (workingText != nil)
4651     [self deleteWorkingText];
4652   if ([str length] == 0)
4653     return;
4655   if (!emacs_event)
4656     return;
4658   processingCompose = YES;
4659   workingText = [str copy];
4660   ns_working_text = build_string ([workingText UTF8String]);
4662   emacs_event->kind = NS_TEXT_EVENT;
4663   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
4664   EV_TRAILER ((id)nil);
4668 /* delete display of composing characters [not in <NSTextInput>] */
4669 - (void)deleteWorkingText
4671   if (workingText == nil)
4672     return;
4673   if (NS_KEYLOG)
4674     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
4675   [workingText release];
4676   workingText = nil;
4677   processingCompose = NO;
4679   if (!emacs_event)
4680     return;
4682   emacs_event->kind = NS_TEXT_EVENT;
4683   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
4684   EV_TRAILER ((id)nil);
4688 - (BOOL)hasMarkedText
4690   return workingText != nil;
4694 - (NSRange)markedRange
4696   NSRange rng = workingText != nil
4697     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
4698   if (NS_KEYLOG)
4699     NSLog (@"markedRange request");
4700   return rng;
4704 - (void)unmarkText
4706   if (NS_KEYLOG)
4707     NSLog (@"unmark (accept) text");
4708   [self deleteWorkingText];
4709   processingCompose = NO;
4713 /* used to position char selection windows, etc. */
4714 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
4716   NSRect rect;
4717   NSPoint pt;
4718   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
4719   if (NS_KEYLOG)
4720     NSLog (@"firstRectForCharRange request");
4722   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
4723   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
4724   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
4725   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
4726                                        +FRAME_LINE_HEIGHT (emacsframe));
4728   pt = [self convertPoint: pt toView: nil];
4729   pt = [[self window] convertBaseToScreen: pt];
4730   rect.origin = pt;
4731   return rect;
4735 - (NSInteger)conversationIdentifier
4737   return (NSInteger)self;
4741 - (void)doCommandBySelector: (SEL)aSelector
4743   if (NS_KEYLOG)
4744     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
4746   if (aSelector == @selector (deleteBackward:))
4747     {
4748       /* happens when user backspaces over an ongoing composition:
4749          throw a 'delete' into the event queue */
4750       if (!emacs_event)
4751         return;
4752       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4753       emacs_event->code = 0xFF08;
4754       EV_TRAILER ((id)nil);
4755     }
4758 - (NSArray *)validAttributesForMarkedText
4760   static NSArray *arr = nil;
4761   if (arr == nil) arr = [NSArray new];
4762  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
4763   return arr;
4766 - (NSRange)selectedRange
4768   if (NS_KEYLOG)
4769     NSLog (@"selectedRange request");
4770   return NSMakeRange (NSNotFound, 0);
4773 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
4775   if (NS_KEYLOG)
4776     NSLog (@"characterIndexForPoint request");
4777   return 0;
4780 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
4782   static NSAttributedString *str = nil;
4783   if (str == nil) str = [NSAttributedString new];
4784   if (NS_KEYLOG)
4785     NSLog (@"attributedSubstringFromRange request");
4786   return str;
4789 /* End <NSTextInput> impl. */
4790 /*****************************************************************************/
4793 /* This is what happens when the user presses a mouse button.  */
4794 - (void)mouseDown: (NSEvent *)theEvent
4796   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
4797   Lisp_Object window;
4799   NSTRACE (mouseDown);
4801   [self deleteWorkingText];
4803   if (!emacs_event)
4804     return;
4806   last_mouse_frame = emacsframe;
4807   /* appears to be needed to prevent spurious movement events generated on
4808      button clicks */
4809   last_mouse_frame->mouse_moved = 0;
4811   if ([theEvent type] == NSScrollWheel)
4812     {
4813       float delta = [theEvent deltaY];
4814       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
4815       if (delta == 0)
4816         return;
4817       emacs_event->kind = WHEEL_EVENT;
4818       emacs_event->code = 0;
4819       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
4820         ((delta > 0) ? up_modifier : down_modifier);
4821     }
4822   else
4823     {
4824       emacs_event->kind = MOUSE_CLICK_EVENT;
4825       emacs_event->code = EV_BUTTON (theEvent);
4826       emacs_event->modifiers = EV_MODIFIERS (theEvent)
4827                              | EV_UDMODIFIERS (theEvent);
4828     }
4829   XSETINT (emacs_event->x, lrint (p.x));
4830   XSETINT (emacs_event->y, lrint (p.y));
4831   EV_TRAILER (theEvent);
4835 - (void)rightMouseDown: (NSEvent *)theEvent
4837   NSTRACE (rightMouseDown);
4838   [self mouseDown: theEvent];
4842 - (void)otherMouseDown: (NSEvent *)theEvent
4844   NSTRACE (otherMouseDown);
4845   [self mouseDown: theEvent];
4849 - (void)mouseUp: (NSEvent *)theEvent
4851   NSTRACE (mouseUp);
4852   [self mouseDown: theEvent];
4856 - (void)rightMouseUp: (NSEvent *)theEvent
4858   NSTRACE (rightMouseUp);
4859   [self mouseDown: theEvent];
4863 - (void)otherMouseUp: (NSEvent *)theEvent
4865   NSTRACE (otherMouseUp);
4866   [self mouseDown: theEvent];
4870 - (void) scrollWheel: (NSEvent *)theEvent
4872   NSTRACE (scrollWheel);
4873   [self mouseDown: theEvent];
4877 /* Tell emacs the mouse has moved. */
4878 - (void)mouseMoved: (NSEvent *)e
4880   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
4881   Lisp_Object frame;
4883 //  NSTRACE (mouseMoved);
4885   last_mouse_movement_time = EV_TIMESTAMP (e);
4886   last_mouse_motion_position
4887     = [self convertPoint: [e locationInWindow] fromView: nil];
4889   /* update any mouse face */
4890   if (dpyinfo->mouse_face_hidden)
4891     {
4892       dpyinfo->mouse_face_hidden = 0;
4893       clear_mouse_face (dpyinfo);
4894     }
4896   /* tooltip handling */
4897   previous_help_echo_string = help_echo_string;
4898   help_echo_string = Qnil;
4900   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
4901                             last_mouse_motion_position.y))
4902     help_echo_string = previous_help_echo_string;
4904   XSETFRAME (frame, emacsframe);
4905   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
4906     {
4907       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
4908          (note_mouse_highlight), which is called through the
4909          note_mouse_movement () call above */
4910       gen_help_event (help_echo_string, frame, help_echo_window,
4911                       help_echo_object, help_echo_pos);
4912     }
4913   else
4914     {
4915       help_echo_string = Qnil;
4916       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
4917     }
4919   if (emacsframe->mouse_moved && send_appdefined)
4920     ns_send_appdefined (-1);
4924 - (void)mouseDragged: (NSEvent *)e
4926   NSTRACE (mouseDragged);
4927   [self mouseMoved: e];
4931 - (void)rightMouseDragged: (NSEvent *)e
4933   NSTRACE (rightMouseDragged);
4934   [self mouseMoved: e];
4938 - (void)otherMouseDragged: (NSEvent *)e
4940   NSTRACE (otherMouseDragged);
4941   [self mouseMoved: e];
4945 - (BOOL)windowShouldClose: (id)sender
4947   NSEvent *e =[[self window] currentEvent];
4949   NSTRACE (windowShouldClose);
4950   windowClosing = YES;
4951   if (!emacs_event)
4952     return NO;
4953   emacs_event->kind = DELETE_WINDOW_EVENT;
4954   emacs_event->modifiers = 0;
4955   emacs_event->code = 0;
4956   EV_TRAILER (e);
4957   /* Don't close this window, let this be done from lisp code.  */
4958   return NO;
4962 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
4963 /* normalize frame to gridded text size */
4965   NSTRACE (windowWillResize);
4966 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
4968   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
4969 #ifdef NS_IMPL_GNUSTEP
4970                                         frameSize.width + 3);
4971 #else
4972                                         frameSize.width);
4973 #endif
4974   if (cols < MINWIDTH)
4975     cols = MINWIDTH;
4976   frameSize.width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (emacsframe, cols);
4978   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, frameSize.height
4979 #ifdef NS_IMPL_GNUSTEP
4980       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + 3
4981         - FRAME_NS_TOOLBAR_HEIGHT (emacsframe));
4982 #else
4983       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
4984         - FRAME_NS_TOOLBAR_HEIGHT (emacsframe));
4985 #endif
4986   if (rows < MINHEIGHT)
4987     rows = MINHEIGHT;
4988   frameSize.height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows)
4989                        + FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
4990                        + FRAME_NS_TOOLBAR_HEIGHT (emacsframe);
4991 #ifdef NS_IMPL_COCOA
4992   {
4993     /* this sets window title to have size in it; the wm does this under GS */
4994     NSRect r = [[self window] frame];
4995     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
4996       {
4997         if (old_title != 0)
4998           {
4999             xfree (old_title);
5000             old_title = 0;
5001           }
5002       }
5003     else
5004       {
5005         char *size_title;
5006         NSWindow *window = [self window];
5007         if (old_title == 0)
5008           {
5009             const char *t = [[[self window] title] UTF8String];
5010             char *pos = strstr (t, "  â€”  ");
5011             if (pos)
5012               *pos = '\0';
5013             old_title = (char *) xmalloc (strlen (t) + 1);
5014             strcpy (old_title, t);
5015           }
5016         size_title = xmalloc (strlen (old_title) + 40);
5017         sprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5018         [window setTitle: [NSString stringWithUTF8String: size_title]];
5019         [window display];
5020         xfree (size_title);
5021       }
5022   }
5023 #endif /* NS_IMPL_COCOA */
5024 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5026   return frameSize;
5030 - (void)windowDidResize: (NSNotification *)notification
5032   NSWindow *theWindow = [notification object];
5034 #ifdef NS_IMPL_GNUSTEP
5035    /* in GNUstep, at least currently, it's possible to get a didResize
5036       without getting a willResize.. therefore we need to act as if we got
5037       the willResize now */
5038   NSSize sz = [theWindow frame].size;
5039   sz = [self windowWillResize: theWindow toSize: sz];
5040 #endif /* NS_IMPL_GNUSTEP */
5042   NSTRACE (windowDidResize);
5043 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5045 #ifdef NS_IMPL_COCOA
5046   if (old_title != 0)
5047     {
5048       xfree (old_title);
5049       old_title = 0;
5050     }
5051 #endif /* NS_IMPL_COCOA */
5053   if (cols > 0 && rows > 0)
5054     x_set_window_size (emacsframe, 0, cols, rows);
5056   ns_send_appdefined (-1);
5060 - (void)windowDidBecomeKey: (NSNotification *)notification
5061 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5063   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5064   struct frame *old_focus = dpyinfo->x_focus_frame;
5066   NSTRACE (windowDidBecomeKey);
5068   if (emacsframe != old_focus)
5069     dpyinfo->x_focus_frame = emacsframe;
5071   ns_frame_rehighlight (emacsframe);
5073   if (emacs_event)
5074     {
5075       emacs_event->kind = FOCUS_IN_EVENT;
5076       EV_TRAILER ((id)nil);
5077     }
5081 - (void)windowDidResignKey: (NSNotification *)notification
5082 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5084   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5085   NSTRACE (windowDidResignKey);
5087   if (dpyinfo->x_focus_frame == emacsframe)
5088     dpyinfo->x_focus_frame = 0;
5090   ns_frame_rehighlight (emacsframe);
5092   /* FIXME: for some reason needed on second and subsequent clicks away
5093             from sole-frame Emacs to get hollow box to show */
5094   if (!windowClosing && [[self window] isVisible] == YES)
5095     {
5096       x_update_cursor (emacsframe, 1);
5097       x_set_frame_alpha (emacsframe);
5098     }
5100   if (emacs_event)
5101     {
5102       [self deleteWorkingText];
5103       emacs_event->kind = FOCUS_IN_EVENT;
5104       EV_TRAILER ((id)nil);
5105     }
5109 - (void)windowWillMiniaturize: sender
5111   NSTRACE (windowWillMiniaturize);
5115 - (BOOL)isFlipped
5117   return YES;
5121 - (BOOL)isOpaque
5123   return NO;
5127 - initFrameFromEmacs: (struct frame *)f
5129   NSRect r, wr;
5130   Lisp_Object tem;
5131   NSWindow *win;
5132   NSButton *toggleButton;
5133   int vbextra = NS_SCROLL_BAR_WIDTH (f);
5134   NSSize sz;
5135   NSColor *col;
5136   NSString *name;
5138   NSTRACE (initFrameFromEmacs);
5140   windowClosing = NO;
5141   processingCompose = NO;
5142   scrollbarsNeedingUpdate = 0;
5144 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5146   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5147                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5148   [self initWithFrame: r];
5150   FRAME_NS_VIEW (f) = self;
5151   emacsframe = f;
5152   old_title = 0;
5154   win = [[EmacsWindow alloc]
5155             initWithContentRect: r
5156                       styleMask: (NSResizableWindowMask |
5157                                   NSMiniaturizableWindowMask |
5158                                   NSClosableWindowMask)
5159                         backing: NSBackingStoreBuffered
5160                           defer: YES];
5162   wr = [win frame];
5163   f->border_width = wr.size.width - r.size.width;
5164   FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5166   [win setAcceptsMouseMovedEvents: YES];
5167   [win setDelegate: self];
5168   [win useOptimizedDrawing: YES];
5170   sz.width = FRAME_COLUMN_WIDTH (f);
5171   sz.height = FRAME_LINE_HEIGHT (f);
5172   [win setResizeIncrements: sz];
5174   [[win contentView] addSubview: self];
5176   if (ns_drag_types)
5177     [self registerForDraggedTypes: ns_drag_types];
5179   tem = f->name;
5180   name = [NSString stringWithUTF8String:
5181                    NILP (tem) ? (unsigned char *)"Emacs" : SDATA (tem)];
5182   [win setTitle: name];
5184   /* toolbar support */
5185   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5186                          [NSString stringWithFormat: @"Emacs Frame %d",
5187                                    ns_window_num]];
5188   [win setToolbar: toolbar];
5189   [toolbar setVisible: NO];
5190 #ifdef NS_IMPL_COCOA
5191   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5192   [toggleButton setTarget: self];
5193   [toggleButton setAction: @selector (toggleToolbar: )];
5194 #endif
5195   FRAME_NS_TOOLBAR_HEIGHT (f) = 0;
5197   tem = f->icon_name;
5198   if (!NILP (tem))
5199     [win setMiniwindowTitle:
5200            [NSString stringWithUTF8String: SDATA (tem)]];
5202   {
5203     NSScreen *screen = [win screen];
5205     if (screen != 0)
5206       [win setFrameTopLeftPoint: NSMakePoint
5207            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5208             IN_BOUND (-SCREENMAX,
5209                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5210   }
5212   [win makeFirstResponder: self];
5214   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5215                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5216   [win setBackgroundColor: col];
5217   if ([col alphaComponent] != 1.0)
5218     [win setOpaque: NO];
5220   [self allocateGState];
5222   ns_window_num++;
5223   return self;
5227 - (void)windowDidMove: sender
5229   NSWindow *win = [self window];
5230   NSRect r = [win frame];
5231   NSScreen *screen = [win screen];
5232   NSRect sr = [screen frame];
5234   NSTRACE (windowDidMove);
5236   if (!emacsframe->output_data.ns)
5237     return;
5238   if (screen != nil)
5239     {
5240       emacsframe->left_pos = r.origin.x; /* - sr.origin.x; */
5241       emacsframe->top_pos = sr.size.height -
5242         (r.origin.y + r.size.height); /* + sr.origin.y; */
5243     }
5246 #ifdef NS_IMPL_COCOA
5247 /* if we don't do this manually, the window will resize but not move */
5248 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5250   NSTRACE (windowShouldZoom);
5251   [[self window] setFrame: newFrame display: NO];
5252   return YES;
5254 #endif
5257 /* Override to do something slightly nonstandard, but nice.  First click on
5258    zoom button will zoom vertically.  Second will zoom completely.  Third
5259    returns to original. */
5260 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5261                         defaultFrame:(NSRect)defaultFrame
5263   NSRect result = [sender frame];
5264   NSTRACE (windowWillUseStandardFrame);
5266   if (result.size.height == defaultFrame.size.height) {
5267     result = defaultFrame;
5268   } else {
5269     result.size.height = defaultFrame.size.height;
5270     result.origin.y = defaultFrame.origin.y;
5271   }
5273   /* A windowWillResize does not get generated at least on Tiger. */
5274   [self windowWillResize: sender toSize: result.size];
5275   return result;
5279 - (void)windowDidDeminiaturize: sender
5281   NSTRACE (windowDidDeminiaturize);
5282   if (!emacsframe->output_data.ns)
5283     return;
5284   emacsframe->async_iconified = 0;
5285   emacsframe->async_visible   = 1;
5286   windows_or_buffers_changed++;
5288   if (emacs_event)
5289     {
5290       emacs_event->kind = ICONIFY_EVENT;
5291       EV_TRAILER ((id)nil);
5292     }
5296 - (void)windowDidExpose: sender
5298   NSTRACE (windowDidExpose);
5299   if (!emacsframe->output_data.ns)
5300     return;
5301   emacsframe->async_visible = 1;
5302   SET_FRAME_GARBAGED (emacsframe);
5304   if (send_appdefined)
5305     ns_send_appdefined (-1);
5309 - (void)windowDidMiniaturize: sender
5311   NSTRACE (windowDidMiniaturize);
5312   if (!emacsframe->output_data.ns)
5313     return;
5315   emacsframe->async_iconified = 1;
5316   emacsframe->async_visible = 0;
5318   if (emacs_event)
5319     {
5320       emacs_event->kind = ICONIFY_EVENT;
5321       EV_TRAILER ((id)nil);
5322     }
5326 - (void)mouseEntered: (NSEvent *)theEvent
5328   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5329   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5330   NSTRACE (mouseEntered);
5332   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5336 - (void)mouseExited: (NSEvent *)theEvent
5338   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5339   NSRect r;
5340   struct ns_display_info *dpyinfo
5341     = emacsframe ? FRAME_NS_DISPLAY_INFO (emacsframe) : NULL;
5343   NSTRACE (mouseExited);
5345   if (dpyinfo || !emacsframe)
5346     return;
5348   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5350   if (emacsframe == dpyinfo->mouse_face_mouse_frame)
5351     {
5352       clear_mouse_face (dpyinfo);
5353       dpyinfo->mouse_face_mouse_frame = 0;
5354     }
5358 - menuDown: sender
5360   NSTRACE (menuDown);
5361   if (context_menu_value == -1)
5362     context_menu_value = [sender tag];
5363   else
5364     find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
5365                                   emacsframe->menu_bar_vector,
5366                                   (void *)[sender tag]);
5367   ns_send_appdefined (-1);
5368   return self;
5372 - (EmacsToolbar *)toolbar
5374   return toolbar;
5378 /* this gets called on toolbar button click */
5379 - toolbarClicked: (id)item
5381   NSEvent *theEvent;
5382   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
5384   NSTRACE (toolbarClicked);
5386   if (!emacs_event)
5387     return self;
5389   /* send first event (for some reason two needed) */
5390   theEvent = [[self window] currentEvent];
5391   emacs_event->kind = TOOL_BAR_EVENT;
5392   XSETFRAME (emacs_event->arg, emacsframe);
5393   EV_TRAILER (theEvent);
5395   emacs_event->kind = TOOL_BAR_EVENT;
5396 /*   XSETINT (emacs_event->code, 0); */
5397   emacs_event->arg = AREF (emacsframe->tool_bar_items,
5398                           idx + TOOL_BAR_ITEM_KEY);
5399   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5400   EV_TRAILER (theEvent);
5401   return self;
5405 - toggleToolbar: (id)sender
5407   if (!emacs_event)
5408     return self;
5410   emacs_event->kind = NS_NONKEY_EVENT;
5411   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
5412   EV_TRAILER ((id)nil);
5413   return self;
5417 - (void)drawRect: (NSRect)rect
5419   int x = NSMinX (rect), y = NSMinY (rect);
5420   int width = NSWidth (rect), height = NSHeight (rect);
5422   NSTRACE (drawRect);
5424   if (!emacsframe || !emacsframe->output_data.ns || ns_in_resize)
5425     return;
5427   ns_clear_frame_area (emacsframe, x, y, width, height);
5428   expose_frame (emacsframe, x, y, width, height);
5429   emacsframe->async_visible = 1;
5430   emacsframe->async_iconified = 0;
5434 /* NSDraggingDestination protocol methods.  Actually this is not really a
5435    protocol, but a category of Object.  O well...  */
5437 -(unsigned int) draggingEntered: (id <NSDraggingInfo>) sender
5439   NSTRACE (draggingEntered);
5440   return NSDragOperationGeneric;
5444 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
5446   return YES;
5450 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
5452   id pb;
5453   int x, y;
5454   NSString *type;
5455   NSEvent *theEvent = [[self window] currentEvent];
5456   NSPoint position;
5458   NSTRACE (performDragOperation);
5460   if (!emacs_event)
5461     return;
5463   position = [self convertPoint: [sender draggingLocation] fromView: nil];
5464   x = lrint (position.x);  y = lrint (position.y);
5466   pb = [sender draggingPasteboard];
5467   type = [pb availableTypeFromArray: ns_drag_types];
5468   if (type == 0)
5469     {
5470       return NO;
5471     }
5472   else if ([type isEqualToString: NSFilenamesPboardType])
5473     {
5474       NSArray *files;
5475       NSEnumerator *fenum;
5476       NSString *file;
5478       if (!(files = [pb propertyListForType: type]))
5479         return NO;
5481       fenum = [files objectEnumerator];
5482       while ( (file = [fenum nextObject]) )
5483         {
5484           emacs_event->kind = NS_NONKEY_EVENT;
5485           emacs_event->code = KEY_NS_DRAG_FILE;
5486           XSETINT (emacs_event->x, x);
5487           XSETINT (emacs_event->y, y);
5488           ns_input_file = append2 (ns_input_file,
5489                                    build_string ([file UTF8String]));
5490           emacs_event->modifiers = EV_MODIFIERS (theEvent);
5491           EV_TRAILER (theEvent);
5492         }
5493       return YES;
5494     }
5495   else if ([type isEqualToString: NSURLPboardType])
5496     {
5497       NSString *file;
5498       NSURL *fileURL;
5500       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
5501           [fileURL isFileURL] == NO)
5502         return NO;
5504       file = [fileURL path];
5505       emacs_event->kind = NS_NONKEY_EVENT;
5506       emacs_event->code = KEY_NS_DRAG_FILE;
5507       XSETINT (emacs_event->x, x);
5508       XSETINT (emacs_event->y, y);
5509       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
5510       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5511       EV_TRAILER (theEvent);
5512       return YES;
5513     }
5514   else if ([type isEqualToString: NSStringPboardType]
5515            || [type isEqualToString: NSTabularTextPboardType])
5516     {
5517       NSString *data;
5519       if (! (data = [pb stringForType: type]))
5520         return NO;
5522       emacs_event->kind = NS_NONKEY_EVENT;
5523       emacs_event->code = KEY_NS_DRAG_TEXT;
5524       XSETINT (emacs_event->x, x);
5525       XSETINT (emacs_event->y, y);
5526       ns_input_text = build_string ([data UTF8String]);
5527       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5528       EV_TRAILER (theEvent);
5529       return YES;
5530     }
5531   else if ([type isEqualToString: NSColorPboardType])
5532     {
5533       NSColor *c = [NSColor colorFromPasteboard: pb];
5534       emacs_event->kind = NS_NONKEY_EVENT;
5535       emacs_event->code = KEY_NS_DRAG_COLOR;
5536       XSETINT (emacs_event->x, x);
5537       XSETINT (emacs_event->y, y);
5538       ns_input_color = ns_color_to_lisp (c);
5539       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5540       EV_TRAILER (theEvent);
5541       return YES;
5542     }
5543   else if ([type isEqualToString: NSFontPboardType])
5544     {
5545       /* impl based on GNUstep NSTextView.m */
5546       NSData *data = [pb dataForType: NSFontPboardType];
5547       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
5548       NSFont *font = [dict objectForKey: NSFontAttributeName];
5549       char fontSize[10];
5551       if (font == nil)
5552         return NO;
5554       emacs_event->kind = NS_NONKEY_EVENT;
5555       emacs_event->code = KEY_NS_CHANGE_FONT;
5556       XSETINT (emacs_event->x, x);
5557       XSETINT (emacs_event->y, y);
5558       ns_input_font = build_string ([[font fontName] UTF8String]);
5559       snprintf (fontSize, 10, "%f", [font pointSize]);
5560       ns_input_fontsize = build_string (fontSize);
5561       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5562       EV_TRAILER (theEvent);
5563       return YES;
5564     }
5565   else
5566     {
5567       error ("Invalid data type in dragging pasteboard.");
5568       return NO;
5569     }
5573 - validRequestorForSendType: (NSString *)typeSent
5574                  returnType: (NSString *)typeReturned
5576   NSTRACE (validRequestorForSendType);
5577   if ([ns_send_types indexOfObjectIdenticalTo: typeSent] != NSNotFound &&
5578       [ns_return_types indexOfObjectIdenticalTo: typeSent] != NSNotFound)
5579     return self;
5581   return [super validRequestorForSendType: typeSent
5582                                returnType: typeReturned];
5586 /* The next two methods are part of NSServicesRequests informal protocol,
5587    supposedly called when a services menu item is chosen from this app.
5588    But this should not happen because we override the services menu with our
5589    own entries which call ns-perform-service.
5590    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
5591    So let's at least stub them out until further investigation can be done. */
5593 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
5595   /* we could call ns_string_from_pasteboard(pboard) here but then it should
5596      be written into the buffer in place of the existing selection..
5597      ordinary service calls go through functions defined in ns-win.el */
5598   return NO;
5601 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
5603   /* supposed to write for as many of types as we are able */
5604   return NO;
5608 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
5609    (gives a miniaturized version of the window); currently we use the latter for
5610    frames whose active buffer doesn't correspond to any file
5611    (e.g., '*scratch*') */
5612 - setMiniwindowImage: (BOOL) setMini
5614   id image = [[self window] miniwindowImage];
5615   NSTRACE (setMiniwindowImage);
5617   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
5618      about "AppleDockIconEnabled" notwithstanding, however the set message
5619      below has its effect nonetheless. */
5620   if (image != emacsframe->output_data.ns->miniimage)
5621     {
5622       if (image && [image isKindOfClass: [EmacsImage class]])
5623         [image release];
5624       [[self window] setMiniwindowImage:
5625                        setMini ? emacsframe->output_data.ns->miniimage : nil];
5626     }
5628   return self;
5632 - (void) setRows: (int) r andColumns: (int) c
5634   rows = r;
5635   cols = c;
5638 @end  /* EmacsView */
5642 /* ==========================================================================
5644     EmacsWindow implementation
5646    ========================================================================== */
5648 @implementation EmacsWindow
5650 /* called only on resize clicks by special case in EmacsApp-sendEvent */
5651 - (void)mouseDown: (NSEvent *)theEvent
5653   if (ns_in_resize)
5654     {
5655       NSSize size = [[theEvent window] frame].size;
5656       grabOffset = [theEvent locationInWindow];
5657       grabOffset.x = size.width - grabOffset.x;
5658     }
5659   else
5660     [super mouseDown: theEvent];
5664 /* stop resizing */
5665 - (void)mouseUp: (NSEvent *)theEvent
5667   if (ns_in_resize)
5668     {
5669       struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
5670       ns_in_resize = NO;
5671       ns_set_name_as_filename (f);
5672       [self display];
5673       ns_send_appdefined (-1);
5674     }
5675   else
5676     [super mouseUp: theEvent];
5680 /* send resize events */
5681 - (void)mouseDragged: (NSEvent *)theEvent
5683   if (ns_in_resize)
5684     {
5685       NSPoint p = [theEvent locationInWindow];
5686       NSSize size, vettedSize, origSize = [self frame].size;
5688       size.width = p.x + grabOffset.x;
5689       size.height = origSize.height - p.y + grabOffset.y;
5691       if (size.width == origSize.width && size.height == origSize.height)
5692         return;
5694       vettedSize = [[self delegate] windowWillResize: self toSize: size];
5695       if (vettedSize.width != size.width || vettedSize.height != size.height)
5696         {
5697           [[NSNotificationCenter defaultCenter]
5698             postNotificationName: NSWindowDidResizeNotification
5699                           object: self];
5700         }
5701     }
5702   else
5703     [super mouseDragged: theEvent];
5706 @end /* EmacsWindow */
5709 /* ==========================================================================
5711     EmacsScroller implementation
5713    ========================================================================== */
5716 @implementation EmacsScroller
5718 /* for repeat button push */
5719 #define SCROLL_BAR_FIRST_DELAY 0.5
5720 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
5722 + (float) scrollerWidth
5724   /* TODO: if we want to allow variable widths, this is the place to do it,
5725            however neither GNUstep nor Cocoa support it very well */
5726   return [NSScroller scrollerWidth];
5730 - initFrame: (NSRect )r window: (Lisp_Object)nwin
5732   NSTRACE (EmacsScroller_initFrame);
5734   r.size.width = [EmacsScroller scrollerWidth];
5735   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
5736   [self setContinuous: YES];
5737   [self setEnabled: YES];
5739   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
5740      locked against the right, top and bottom edges. */
5741   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
5743   win = nwin;
5744   condemned = NO;
5745   pixel_height = NSHeight (r);
5746   min_portion = 20 / pixel_height;
5748   frame = XFRAME (XWINDOW (win)->frame);
5749   if (FRAME_LIVE_P (frame))
5750     {
5751       int i;
5752       EmacsView *view = FRAME_NS_VIEW (frame);
5753       NSView *sview = [[view window] contentView];
5754       NSArray *subs = [sview subviews];
5756       /* disable optimization stopping redraw of other scrollbars */
5757       view->scrollbarsNeedingUpdate = 0;
5758       for (i =[subs count]-1; i >= 0; i--)
5759         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
5760           view->scrollbarsNeedingUpdate++;
5761       [sview addSubview: self];
5762     }
5764 /*  [self setFrame: r]; */
5766   return self;
5770 - (void)setFrame: (NSRect)newRect
5772   NSTRACE (EmacsScroller_setFrame);
5773 /*  BLOCK_INPUT; */
5774   pixel_height = NSHeight (newRect);
5775   min_portion = 20 / pixel_height;
5776   [super setFrame: newRect];
5777   [self display];
5778 /*  UNBLOCK_INPUT; */
5782 - (void)dealloc
5784   NSTRACE (EmacsScroller_dealloc);
5785   if (!NILP (win))
5786     XWINDOW (win)->vertical_scroll_bar = Qnil;
5787   [super dealloc];
5791 - condemn
5793   NSTRACE (condemn);
5794   condemned =YES;
5795   return self;
5799 - reprieve
5801   NSTRACE (reprieve);
5802   condemned =NO;
5803   return self;
5807 - judge
5809   NSTRACE (judge);
5810   if (condemned)
5811     {
5812       BLOCK_INPUT;
5813       /* ensure other scrollbar updates after deletion */
5814       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
5815       if (view != nil)
5816         view->scrollbarsNeedingUpdate++;
5817       [self removeFromSuperview];
5818       [self release];
5819       UNBLOCK_INPUT;
5820     }
5821   return self;
5825 - (void)resetCursorRects
5827   NSRect visible = [self visibleRect];
5828   NSTRACE (resetCursorRects);
5830   if (!NSIsEmptyRect (visible))
5831     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
5832   [[NSCursor arrowCursor] setOnMouseEntered: YES];
5836 - (int) checkSamePosition: (int) position portion: (int) portion
5837                     whole: (int) whole
5839   return em_position ==position && em_portion ==portion && em_whole ==whole
5840     && portion != whole; /* needed for resize empty buf */
5844 - setPosition: (int)position portion: (int)portion whole: (int)whole
5846   NSTRACE (setPosition);
5848   em_position = position;
5849   em_portion = portion;
5850   em_whole = whole;
5852   if (portion >= whole)
5853     [self setFloatValue: 0.0 knobProportion: 1.0];
5854   else
5855     {
5856       float pos, por;
5857       portion = max ((float)whole*min_portion/pixel_height, portion);
5858       pos = (float)position / (whole - portion);
5859       por = (float)portion/whole;
5860       [self setFloatValue: pos knobProportion: por];
5861     }
5862 #ifdef NS_IMPL_GNUSTEP
5863   [self display];
5864 #endif
5865   return self;
5868 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
5869      drag events will go directly to the EmacsScroller.  Leaving in for now. */
5870 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
5871                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
5873   *part = last_hit_part;
5874   *window = win;
5875   XSETINT (*y, pixel_height);
5876   if ([self floatValue] > 0.999)
5877     XSETINT (*x, pixel_height);
5878   else
5879     XSETINT (*x, pixel_height * [self floatValue]);
5883 /* set up emacs_event */
5884 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
5886   if (!emacs_event)
5887     return;
5889   emacs_event->part = last_hit_part;
5890   emacs_event->code = 0;
5891   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
5892   emacs_event->frame_or_window = win;
5893   emacs_event->timestamp = EV_TIMESTAMP (e);
5894   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
5895   emacs_event->arg = Qnil;
5896   XSETINT (emacs_event->x, loc * pixel_height);
5897   XSETINT (emacs_event->y, pixel_height-20);
5899   n_emacs_events_pending++;
5900   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
5901   EVENT_INIT (*emacs_event);
5902   ns_send_appdefined (-1);
5906 /* called manually thru timer to implement repeated button action w/hold-down */
5907 - repeatScroll: (NSTimer *)scrollEntry
5909   NSEvent *e = [[self window] currentEvent];
5910   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
5911   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
5913   /* clear timer if need be */
5914   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
5915     {
5916         [scroll_repeat_entry invalidate];
5917         [scroll_repeat_entry release];
5918         scroll_repeat_entry = nil;
5920         if (inKnob)
5921           return self;
5923         scroll_repeat_entry
5924           = [[NSTimer scheduledTimerWithTimeInterval:
5925                         SCROLL_BAR_CONTINUOUS_DELAY
5926                                             target: self
5927                                           selector: @selector (repeatScroll:)
5928                                           userInfo: 0
5929                                            repeats: YES]
5930               retain];
5931     }
5933   [self sendScrollEventAtLoc: 0 fromEvent: e];
5934   return self;
5938 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
5939    mouseDragged events without going into a modal loop. */
5940 - (void)mouseDown: (NSEvent *)e
5942   NSRect sr, kr;
5943   /* hitPart is only updated AFTER event is passed on */
5944   NSScrollerPart part = [self testPart: [e locationInWindow]];
5945   double inc = 0.0, loc, kloc, pos;
5946   int edge = 0;
5948   NSTRACE (EmacsScroller_mouseDown);
5950   switch (part)
5951     {
5952     case NSScrollerDecrementPage:
5953         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
5954     case NSScrollerIncrementPage:
5955         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
5956     case NSScrollerDecrementLine:
5957       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
5958     case NSScrollerIncrementLine:
5959       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
5960     case NSScrollerKnob:
5961       last_hit_part = scroll_bar_handle; break;
5962     case NSScrollerKnobSlot:  /* GNUstep-only */
5963       last_hit_part = scroll_bar_move_ratio; break;
5964     default:  /* NSScrollerNoPart? */
5965       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %d\n", part);
5966       return;
5967     }
5969   if (inc != 0.0)
5970     {
5971       pos = 0;      /* ignored */
5973       /* set a timer to repeat, as we can't let superclass do this modally */
5974       scroll_repeat_entry
5975         = [[NSTimer scheduledTimerWithTimeInterval: 0.5
5976                                             target: self
5977                                           selector: @selector (repeatScroll:)
5978                                           userInfo: 0
5979                                            repeats: YES]
5980             retain];
5981     }
5982   else
5983     {
5984       /* handle, or on GNUstep possibly slot */
5985       NSEvent *fake_event;
5987       /* compute float loc in slot and mouse offset on knob */
5988       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
5989                       toView: nil];
5990       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
5991       if (loc <= 0.0)
5992         {
5993           loc = 0.0;
5994           edge = -1;
5995         }
5996       else if (loc >= NSHeight (sr))
5997         {
5998           loc = NSHeight (sr);
5999           edge = 1;
6000         }
6002       if (edge)
6003         kloc = 0.5 * edge;
6004       else
6005         {
6006           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
6007                           toView: nil];
6008           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
6009         }
6010       last_mouse_offset = kloc;
6012       /* if knob, tell emacs a location offset by knob pos
6013          (to indicate top of handle) */
6014       if (part == NSScrollerKnob)
6015           pos = (loc - last_mouse_offset) / NSHeight (sr);
6016       else
6017         /* else this is a slot click on GNUstep: go straight there */
6018         pos = loc / NSHeight (sr);
6020       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
6021       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
6022                                       location: [e locationInWindow]
6023                                  modifierFlags: [e modifierFlags]
6024                                      timestamp: [e timestamp]
6025                                   windowNumber: [e windowNumber]
6026                                        context: [e context]
6027                                    eventNumber: [e eventNumber]
6028                                     clickCount: [e clickCount]
6029                                       pressure: [e pressure]];
6030       [super mouseUp: fake_event];
6031     }
6033   if (part != NSScrollerKnob)
6034     [self sendScrollEventAtLoc: pos fromEvent: e];
6038 /* Called as we manually track scroller drags, rather than superclass. */
6039 - (void)mouseDragged: (NSEvent *)e
6041     NSRect sr;
6042     double loc, pos;
6043     int edge = 0;
6045     NSTRACE (EmacsScroller_mouseDragged);
6047       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6048                       toView: nil];
6049       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6051       if (loc <= 0.0)
6052         {
6053           loc = 0.0;
6054           edge = -1;
6055         }
6056       else if (loc >= NSHeight (sr) + last_mouse_offset)
6057         {
6058           loc = NSHeight (sr) + last_mouse_offset;
6059           edge = 1;
6060         }
6062       pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
6063       [self sendScrollEventAtLoc: pos fromEvent: e];
6067 - (void)mouseUp: (NSEvent *)e
6069   if (scroll_repeat_entry)
6070     {
6071       [scroll_repeat_entry invalidate];
6072       [scroll_repeat_entry release];
6073       scroll_repeat_entry = nil;
6074     }
6075   last_hit_part = 0;
6079 /* treat scrollwheel events in the bar as though they were in the main window */
6080 - (void) scrollWheel: (NSEvent *)theEvent
6082   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
6083   [view mouseDown: theEvent];
6086 @end  /* EmacsScroller */
6091 /* ==========================================================================
6093    Font-related functions; these used to be in nsfaces.m
6095    ========================================================================== */
6098 Lisp_Object
6099 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
6101   struct font *font = XFONT_OBJECT (font_object);
6103   if (fontset < 0)
6104     fontset = fontset_from_font (font_object);
6105   FRAME_FONTSET (f) = fontset;
6107   if (FRAME_FONT (f) == font)
6108     /* This font is already set in frame F.  There's nothing more to
6109        do.  */
6110     return font_object;
6112   FRAME_FONT (f) = font;
6114   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
6115   FRAME_COLUMN_WIDTH (f) = font->average_width;
6116   FRAME_SPACE_WIDTH (f) = font->space_width;
6117   FRAME_LINE_HEIGHT (f) = font->height;
6119   compute_fringe_widths (f, 1);
6121   /* Compute the scroll bar width in character columns.  */
6122   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6123     {
6124       int wid = FRAME_COLUMN_WIDTH (f);
6125       FRAME_CONFIG_SCROLL_BAR_COLS (f)
6126         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
6127     }
6128   else
6129     {
6130       int wid = FRAME_COLUMN_WIDTH (f);
6131       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6132     }
6134   /* Now make the frame display the given font.  */
6135   if (FRAME_NS_WINDOW (f) != 0)
6136         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6138   return font_object;
6142 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
6143 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
6144          in 1.43. */
6146 const char *
6147 ns_xlfd_to_fontname (const char *xlfd)
6148 /* --------------------------------------------------------------------------
6149     Convert an X font name (XLFD) to an NS font name.
6150     Only family is used.
6151     The string returned is temporarily allocated.
6152    -------------------------------------------------------------------------- */
6154   char *name = xmalloc (180);
6155   int i, len;
6156   const char *ret;
6158   if (!strncmp (xlfd, "--", 2))
6159     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
6160   else
6161     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
6163   /* stopgap for malformed XLFD input */
6164   if (strlen (name) == 0)
6165     strcpy (name, "Monaco");
6167   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
6168      also uppercase after '-' or ' ' */
6169   name[0] = toupper (name[0]);
6170   for (len =strlen (name), i =0; i<len; i++)
6171     {
6172       if (name[i] == '$')
6173         {
6174           name[i] = '-';
6175           if (i+1<len)
6176             name[i+1] = toupper (name[i+1]);
6177         }
6178       else if (name[i] == '_')
6179         {
6180           name[i] = ' ';
6181           if (i+1<len)
6182             name[i+1] = toupper (name[i+1]);
6183         }
6184     }
6185 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
6186   ret = [[NSString stringWithUTF8String: name] UTF8String];
6187   xfree (name);
6188   return ret;
6192 void
6193 syms_of_nsterm ()
6195   NSTRACE (syms_of_nsterm);
6196   DEFVAR_LISP ("ns-input-file", &ns_input_file,
6197               "The file specified in the last NS event.");
6198   ns_input_file =Qnil;
6200   DEFVAR_LISP ("ns-input-text", &ns_input_text,
6201               "The data received in the last NS text drag event.");
6202   ns_input_text =Qnil;
6204   DEFVAR_LISP ("ns-working-text", &ns_working_text,
6205               "String for visualizing working composition sequence.");
6206   ns_working_text =Qnil;
6208   DEFVAR_LISP ("ns-input-font", &ns_input_font,
6209               "The font specified in the last NS event.");
6210   ns_input_font =Qnil;
6212   DEFVAR_LISP ("ns-input-fontsize", &ns_input_fontsize,
6213               "The fontsize specified in the last NS event.");
6214   ns_input_fontsize =Qnil;
6216   DEFVAR_LISP ("ns-input-line", &ns_input_line,
6217                "The line specified in the last NS event.");
6218   ns_input_line =Qnil;
6220   DEFVAR_LISP ("ns-input-color", &ns_input_color,
6221                "The color specified in the last NS event.");
6222   ns_input_color =Qnil;
6224   DEFVAR_LISP ("ns-input-spi-name", &ns_input_spi_name,
6225                "The service name specified in the last NS event.");
6226   ns_input_spi_name =Qnil;
6228   DEFVAR_LISP ("ns-input-spi-arg", &ns_input_spi_arg,
6229                "The service argument specified in the last NS event.");
6230   ns_input_spi_arg =Qnil;
6232   DEFVAR_LISP ("ns-alternate-modifier", &ns_alternate_modifier,
6233                "This variable describes the behavior of the alternate or option key.\n\
6234 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6235 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6236 at all, allowing it to be used at a lower level for accented character entry.");
6238   DEFVAR_LISP ("ns-command-modifier", &ns_command_modifier,
6239                "This variable describes the behavior of the command key.\n\
6240 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6242   DEFVAR_LISP ("ns-control-modifier", &ns_control_modifier,
6243                "This variable describes the behavior of the control key.\n\
6244 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6246   DEFVAR_LISP ("ns-function-modifier", &ns_function_modifier,
6247                "This variable describes the behavior of the function key (on laptops).\n\
6248 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6249 Set to none means that the function key is not interpreted by Emacs at all,\n\
6250 allowing it to be used at a lower level for accented character entry.");
6252   DEFVAR_LISP ("ns-antialias-text", &ns_antialias_text,
6253                "Non-nil (the default) means to render text antialiased. Only has an effect on OS X Panther and above.");
6255   DEFVAR_LISP ("ns-use-qd-smoothing", &ns_use_qd_smoothing,
6256                "Whether to render text using QuickDraw (less heavy) antialiasing. Only has an effect on OS X Panther and above.  Default is nil (use Quartz smoothing).");
6258   DEFVAR_LISP ("ns-use-system-highlight-color",
6259                &ns_use_system_highlight_color,
6260                "Whether to use the system default (on OS X only) for the highlight color.  Nil means to use standard emacs (prior to version 21) 'grey'.");
6262   DEFVAR_LISP ("ns-confirm-quit", &ns_confirm_quit,
6263                "Whether to confirm application quit using dialog.");
6265   staticpro (&ns_display_name_list);
6266   ns_display_name_list = Qnil;
6268   staticpro (&last_mouse_motion_frame);
6269   last_mouse_motion_frame = Qnil;
6271   /* from 23+ we need to tell emacs what modifiers there are.. */
6272   Qmodifier_value = intern ("modifier-value");
6273   Qalt = intern ("alt");
6274   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
6275   Qhyper = intern ("hyper");
6276   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
6277   Qmeta = intern ("meta");
6278   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
6279   Qsuper = intern ("super");
6280   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
6281   Qcontrol = intern ("control");
6282   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
6284   /* TODO: move to common code */
6285   DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
6286                doc: /* If not nil, Emacs uses toolkit scroll bars.  */);
6287 #ifdef USE_TOOLKIT_SCROLL_BARS
6288   Vx_toolkit_scroll_bars = Qt;
6289 #else
6290   Vx_toolkit_scroll_bars = Qnil;
6291 #endif
6293   /* these are unsupported but we need the declarations to avoid whining
6294      messages from cus-start.el */
6295   DEFVAR_BOOL ("x-use-underline-position-properties",
6296                &x_use_underline_position_properties,
6297      doc: /* NOT SUPPORTED UNDER NS.
6298 *Non-nil means make use of UNDERLINE_POSITION font properties.
6299 A value of nil means ignore them.  If you encounter fonts with bogus
6300 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
6301 to 4.1, set this to nil.
6303 NOTE: Not supported on Mac yet.  */);
6304   x_use_underline_position_properties = 0;
6306   DEFVAR_BOOL ("x-underline-at-descent-line",
6307                &x_underline_at_descent_line,
6308      doc: /* NOT SUPPORTED UNDER NS.
6309 *Non-nil means to draw the underline at the same place as the descent line.
6310 A value of nil means to draw the underline according to the value of the
6311 variable `x-use-underline-position-properties', which is usually at the
6312 baseline level.  The default value is nil.  */);
6313   x_underline_at_descent_line = 0;
6315   /* Tell emacs about this window system. */
6316   Fprovide (intern ("ns"), Qnil);
6320 // arch-tag: 6eaa8f7d-a69b-4e1c-b43d-ab31defbe0d2