Add arch tagline
[emacs.git] / src / nsterm.m
blob1e112ea8e4ffc53476dbdddbd45cbe983f04890c
1 /* NeXT/Open/GNUstep / MacOSX communication module.
2    Copyright (C) 1989, 1993, 1994, 2005, 2006, 2008,
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, or (at your option)
10 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; see the file COPYING.  If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
22 Originally by Carl Edman
23 Updated by Christian Limpach (chris@nice.ch)
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25 MacOSX/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
26 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
29 #include <math.h>
30 #include <sys/types.h>
31 #include <time.h>
32 #include <unistd.h>
34 #include "config.h"
35 #include "lisp.h"
36 #include "blockinput.h"
37 #include "sysselect.h"
38 #include "nsterm.h"
39 #include "systime.h"
40 #include "character.h"
41 #include "fontset.h"
42 #include "composite.h"
43 #include "ccl.h"
45 #include "termhooks.h"
46 #include "termopts.h"
47 #include "termchar.h"
49 #include "window.h"
50 #include "keyboard.h"
52 #include "font.h"
54 /* call tracing */
55 #if 0
56 int term_trace_num = 0;
57 #define NSTRACE(x)        fprintf (stderr, "%s:%d: [%d] " #x "\n",         \
58                                 __FILE__, __LINE__, ++term_trace_num)
59 #else
60 #define NSTRACE(x)
61 #endif
64 /* ==========================================================================
66     Local declarations
68    ========================================================================== */
70 /* Special keycodes that we pass down the event chain */
71 #define KEY_NS_POWER_OFF               ((1<<28)|(0<<16)|1)
72 #define KEY_NS_OPEN_FILE               ((1<<28)|(0<<16)|2)
73 #define KEY_NS_OPEN_TEMP_FILE          ((1<<28)|(0<<16)|3)
74 #define KEY_NS_DRAG_FILE               ((1<<28)|(0<<16)|4)
75 #define KEY_NS_DRAG_COLOR              ((1<<28)|(0<<16)|5)
76 #define KEY_NS_DRAG_TEXT               ((1<<28)|(0<<16)|6)
77 #define KEY_NS_CHANGE_FONT             ((1<<28)|(0<<16)|7)
78 #define KEY_NS_OPEN_FILE_LINE          ((1<<28)|(0<<16)|8)
79 #define KEY_NS_INSERT_WORKING_TEXT     ((1<<28)|(0<<16)|9)
80 #define KEY_NS_DELETE_WORKING_TEXT     ((1<<28)|(0<<16)|10)
81 #define KEY_NS_SPI_SERVICE_CALL        ((1<<28)|(0<<16)|11)
83 /* Convert a symbol indexed with an NSxxx value to a value as defined
84    in keyboard.c (lispy_function_key). I hope this is a correct way
85    of doing things... */
86 static unsigned convert_ns_to_X_keysym[] =
88   NSHomeFunctionKey,            0x50,
89   NSLeftArrowFunctionKey,       0x51,
90   NSUpArrowFunctionKey,         0x52,
91   NSRightArrowFunctionKey,      0x53,
92   NSDownArrowFunctionKey,       0x54,
93   NSPageUpFunctionKey,          0x55,
94   NSPageDownFunctionKey,        0x56,
95   NSEndFunctionKey,             0x57,
96   NSBeginFunctionKey,           0x58,
97   NSSelectFunctionKey,          0x60,
98   NSPrintFunctionKey,           0x61,
99   NSExecuteFunctionKey,         0x62,
100   NSInsertFunctionKey,          0x63,
101   NSUndoFunctionKey,            0x65,
102   NSRedoFunctionKey,            0x66,
103   NSMenuFunctionKey,            0x67,
104   NSFindFunctionKey,            0x68,
105   NSHelpFunctionKey,            0x6A,
106   NSBreakFunctionKey,           0x6B,
108   NSF1FunctionKey,              0xBE,
109   NSF2FunctionKey,              0xBF,
110   NSF3FunctionKey,              0xC0,
111   NSF4FunctionKey,              0xC1,
112   NSF5FunctionKey,              0xC2,
113   NSF6FunctionKey,              0xC3,
114   NSF7FunctionKey,              0xC4,
115   NSF8FunctionKey,              0xC5,
116   NSF9FunctionKey,              0xC6,
117   NSF10FunctionKey,             0xC7,
118   NSF11FunctionKey,             0xC8,
119   NSF12FunctionKey,             0xC9,
120   NSF13FunctionKey,             0xCA,
121   NSF14FunctionKey,             0xCB,
122   NSF15FunctionKey,             0xCC,
124   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
125   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
126   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
128   NSTabCharacter,               0x09,
129   0x19,                         0x09,  /* left tab->regular since pass shift */
130   NSCarriageReturnCharacter,    0x0D,
131   NSNewlineCharacter,           0x0D,
132   NSEnterCharacter,             0x8D,
134   0x1B,                         0x1B   /* escape */
138 /* Lisp communications */
139 Lisp_Object ns_input_file, ns_input_font, ns_input_fontsize, ns_input_line;
140 Lisp_Object ns_input_color, ns_input_text, ns_working_text;
141 Lisp_Object ns_input_spi_name, ns_input_spi_arg;
142 Lisp_Object Vx_toolkit_scroll_bars;
143 static Lisp_Object Qmodifier_value;
144 /*PENDING: unsure why these defined in term files, anyway we need in keymap.c */
145 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper;
146 extern Lisp_Object Qcursor_color, Qcursor_type, Qns;
147 extern int lisp_to_mod (Lisp_Object lmod);
150 EmacsPrefsController *prefsController;
152 /* Defaults managed through the OpenStep defaults system.  These pertain to
153    the NS interface specifically.  Although a customization group could be
154    created, it's more natural to manage them via defaults. */
156 /* Specifies which emacs modifier should be generated when NS receives
157    the Alternate modifer.  May be Qnone or any of the modifier lisp symbols. */
158 Lisp_Object ns_alternate_modifier;
160 /* Specifies which emacs modifier should be generated when NS receives
161    the Command modifer.  May be any of the modifier lisp symbols. */
162 Lisp_Object ns_command_modifier;
164 /* Specifies which emacs modifier should be generated when NS receives
165    the Control modifer.  May be any of the modifier lisp symbols. */
166 Lisp_Object ns_control_modifier;
168 /* Specifies which emacs modifier should be generated when NS receives
169    the Function modifer (laptops).  May be any of the modifier lisp symbols. */
170 Lisp_Object ns_function_modifier;
172 /* A floating point value specifying the rate at which to blink the cursor.
173    YES indicates 0.5, NO indicates no blinking. */
174 Lisp_Object ns_cursor_blink_rate;
176 /* Used for liason with core emacs cursor-blink-mode. */
177 Lisp_Object ns_cursor_blink_mode;
179 /* A floating point value specifying vertical stretch (positive) or shrink
180   (negative) of text line spacing.  Zero means default spacing.
181   YES indicates 0.5, NO indicates 0.0. */
182 Lisp_Object ns_expand_space;
184 /* Control via default 'GSFontAntiAlias' on OS X and GNUstep. */
185 int ns_antialias_text;
187 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
188    the maximum font size to NOT antialias.  On GNUstep there is currently
189    no way to control this behavior. */
190 float ns_antialias_threshold;
192 /* Controls use of an undocumented CG function to do Quickdraw-style font
193    smoothing (less heavy) instead of regular Quartz smoothing. */
194 int ns_use_qd_smoothing;
196 /* Used to pick up AppleHighlightColor on OS X */
197 int ns_use_system_highlight_color;
198 NSString *ns_selection_color;
201 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
203 /* Display variables */
204 struct ns_display_info *ns_display_list; /* Chain of existing displays */
205 Lisp_Object ns_display_name_list;
206 long context_menu_value = 0;
208 /* display update */
209 NSPoint last_mouse_motion_position;
210 static NSRect last_mouse_glyph;
211 static unsigned long last_mouse_movement_time = 0;
212 static Lisp_Object last_mouse_motion_frame;
213 static EmacsScroller *last_mouse_scroll_bar = nil;
214 static struct frame *ns_updating_frame;
215 static NSView *focus_view = NULL;
216 static int ns_window_num =0;
217 static NSRect uRect;
218 static BOOL gsaved = NO;
219 BOOL ns_in_resize = NO;
220 int ns_tmp_flags; /*PENDING */
221 struct nsfont_info *ns_tmp_font; /*PENDING */
222 /*static int debug_lock = 0; */
224 #ifdef NS_IMPL_COCOA
225 /* This undocumented Quartz function controls how fonts are anti-aliased.
226    (Found from code in Mac wxWindows impl, discovered by running `nm' on
227    the "QD" framework.)
228    Mode 0 is normal anti-aliasing, mode 1 is no anti-aliasing, and mode 2 is
229    4-bit pixel-aligned anti-aliasing (the old QuickDraw standard). */
230 extern void CGContextSetFontRenderingMode (CGContextRef cg, int v);
231 #endif
234 /* event loop */
235 static BOOL send_appdefined = YES;
236 static NSEvent *last_appdefined_event = 0;
237 static NSTimer *timed_entry = 0;
238 static NSTimer *fd_entry = nil;
239 static NSTimer *cursor_blink_entry = nil;
240 static NSTimer *scroll_repeat_entry = nil;
241 static fd_set select_readfds, t_readfds;
242 static struct timeval select_timeout;
243 static int select_nfds;
244 static NSAutoreleasePool *outerpool;
245 static BOOL ns_shutdown_properly = NO;
246 static struct input_event *emacs_event = NULL;
247 static struct input_event *q_event_ptr = NULL;
248 static int n_emacs_events_pending = 0;
249 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
250   *ns_pending_service_args;
251 static BOOL inNsSelect = 0;
253 /* Convert modifiers in a NeXTSTEP event to emacs style modifiers.  */
254 #define NS_FUNCTION_KEY_MASK 0x800000
255 #define EV_MODIFIERS(e)                               \
256     ((([e modifierFlags] & NSHelpKeyMask) ?           \
257            hyper_modifier : 0)                        \
258      | (([e modifierFlags] & NSAlternateKeyMask) ?    \
259            lisp_to_mod (ns_alternate_modifier) : 0)   \
260      | (([e modifierFlags] & NSShiftKeyMask) ?        \
261            shift_modifier : 0)                        \
262      | (([e modifierFlags] & NSControlKeyMask) ?      \
263            lisp_to_mod (ns_control_modifier) : 0)     \
264      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
265            lisp_to_mod (ns_function_modifier) : 0)    \
266      | (([e modifierFlags] & NSCommandKeyMask) ?      \
267            lisp_to_mod (ns_command_modifier):0))
269 #define EV_UDMODIFIERS(e)                                      \
270     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
271      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
272      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
273      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
274      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
275      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0))
277 #define EV_BUTTON(e)                                                         \
278     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
279       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : 1)
281 /* Convert the time field to a timestamp in milliseconds. */
282 #ifdef NS_IMPL_GNUSTEP
283 /* Apple says timestamp is in seconds, but GNUstep seems to be returning msec */
284 #define EV_TIMESTAMP(e) ([e timestamp])
285 #else
286 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
287 #endif /* not gnustep */
289 /* This is a piece of code which is common to all the event handling
290    methods.  Maybe it should even be a function.  */
291 #define EV_TRAILER(e)                                         \
292   {                                                           \
293   XSETFRAME (emacs_event->frame_or_window, [NSApp isActive] ? \
294              emacsframe : SELECTED_FRAME ());                 \
295   if (e) emacs_event->timestamp = EV_TIMESTAMP (e);           \
296   n_emacs_events_pending++;                                   \
297   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);     \
298   EVENT_INIT (*emacs_event);                                  \
299   ns_send_appdefined (-1);                                    \
300   }
302 /*PENDING: get rid of need for these forward declarations */
303 static void ns_condemn_scroll_bars (struct frame *f),
304             ns_judge_scroll_bars (struct frame *f);
306 /* unused variables needed for compatibility reasons */
307 int x_use_underline_position_properties, x_underline_at_descent_line;
308 /* PENDING: figure out what to do with underline_minimum_offset. */
311 /* ==========================================================================
313     Utilities
315    ========================================================================== */
318 static Lisp_Object
319 append2 (Lisp_Object list, Lisp_Object item)
320 /* --------------------------------------------------------------------------
321    Utility to append to a list
322    -------------------------------------------------------------------------- */
324   Lisp_Object array[2];
325   array[0] = list;
326   array[1] = Fcons (item, Qnil);
327   return Fnconc (2, &array[0]);
331 void
332 ns_init_paths ()
333 /* --------------------------------------------------------------------------
334    Used to allow emacs to find its resources under Emacs.app
335    Called from emacs.c at startup.
336    -------------------------------------------------------------------------- */
338   NSBundle *bundle = [NSBundle mainBundle];
339   NSString *binDir = [bundle bundlePath], *resourceDir = [bundle resourcePath];
340   NSString *resourcePath, *resourcePaths;
341   NSRange range;
342   BOOL onWindows = NO; /* how do I determine this? */
343   NSString *pathSeparator = onWindows ? @";" : @":";
344   NSFileManager *fileManager = [NSFileManager defaultManager];
345   BOOL isDir;
346 /*NSLog (@"ns_init_paths: '%@'\n%@\n", [[NSBundle mainBundle] bundlePath], [[NSBundle mainBundle] resourcePath]); */
348   /* get bindir from base */
349   range = [resourceDir rangeOfString: @"Contents"];
350   if (range.location != NSNotFound)
351     {
352       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
353 #ifdef NS_IMPL_COCOA
354       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
355 #endif
356     }
358   /* the following based on Andrew Choi's init_mac_osx_environment () */
359   if (!getenv ("EMACSLOADPATH"))
360     {
361       NSArray *paths = [resourceDir stringsByAppendingPaths:
362                                   [NSArray arrayWithObjects:
363                                          @"site-lisp", @"lisp", @"leim", nil]];
364       NSEnumerator *pathEnum = [paths objectEnumerator];
365       resourcePaths = @"";
366       while (resourcePath = [pathEnum nextObject])
367         {
368           if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
369             if (isDir)
370               {
371                 if ([resourcePaths length] > 0)
372                   resourcePaths =
373                     [resourcePaths stringByAppendingString: pathSeparator];
374                 resourcePaths =
375                   [resourcePaths stringByAppendingString: resourcePath];
376               }
377         }
378       if ([resourcePaths length] > 0)
379         setenv ("EMACSLOADPATH", [resourcePaths UTF8String], 1);
380 /*NSLog (@"loadPath: '%s'\n", resourcePaths); */
381     }
383   if (!getenv ("EMACSPATH"))
384     {
385       NSArray *paths = [binDir stringsByAppendingPaths:
386                                   [NSArray arrayWithObjects: @"bin",
387                                                              @"lib-exec", nil]];
388       NSEnumerator *pathEnum = [paths objectEnumerator];
389       resourcePaths = @"";
390       while (resourcePath = [pathEnum nextObject])
391         {
392           if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
393             if (isDir)
394               {
395                 if ([resourcePaths length] > 0)
396                   resourcePaths =
397                     [resourcePaths stringByAppendingString: pathSeparator];
398                 resourcePaths =
399                   [resourcePaths stringByAppendingString: resourcePath];
400               }
401         }
402       if ([resourcePaths length] > 0)
403         setenv ("EMACSPATH", [resourcePaths UTF8String], 1);
404     }
406   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
407   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
408     {
409       if (isDir)
410         {
411           if (!getenv ("EMACSDATA"))
412             setenv ("EMACSDATA", [resourcePath UTF8String], 1);
413           if (!getenv ("EMACSDOC"))
414             setenv ("EMACSDOC", [resourcePath UTF8String], 1);
415         }
416     }
418   /*PENDING: append to INFOPATH... */
419   if (!getenv ("INFOPATH"))
420     {
421       resourcePath = [resourceDir stringByAppendingPathComponent: @"info"];
422       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
423         if (isDir)
424           setenv ("INFOPATH", [resourcePath UTF8String], 1);
425     }
429 static int
430 timeval_subtract (struct timeval *result, struct timeval x, struct timeval y)
431 /* --------------------------------------------------------------------------
432    Subtract the `struct timeval' values X and Y, storing the result in RESULT.
433    Return 1 if the difference is negative, otherwise 0.
434    -------------------------------------------------------------------------- */
436   /* Perform the carry for the later subtraction by updating y.
437      This is safer because on some systems
438      the tv_sec member is unsigned.  */
439   if (x.tv_usec < y.tv_usec)
440     {
441       int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
442       y.tv_usec -= 1000000 * nsec;
443       y.tv_sec += nsec;
444     }
445   if (x.tv_usec - y.tv_usec > 1000000)
446     {
447       int nsec = (y.tv_usec - x.tv_usec) / 1000000;
448       y.tv_usec += 1000000 * nsec;
449       y.tv_sec -= nsec;
450     }
452   /* Compute the time remaining to wait.  tv_usec is certainly positive.  */
453   result->tv_sec = x.tv_sec - y.tv_sec;
454   result->tv_usec = x.tv_usec - y.tv_usec;
456   /* Return indication of whether the result should be considered negative.  */
457   return x.tv_sec < y.tv_sec;
460 static void
461 ns_timeout (int usecs)
462 /* --------------------------------------------------------------------------
463      Blocking timer utility used by ns_ring_bell
464    -------------------------------------------------------------------------- */
466   struct timeval wakeup;
468   EMACS_GET_TIME (wakeup);
470   /* Compute time to wait until, propagating carry from usecs.  */
471   wakeup.tv_usec += usecs;
472   wakeup.tv_sec += (wakeup.tv_usec / 1000000);
473   wakeup.tv_usec %= 1000000;
475   /* Keep waiting until past the time wakeup.  */
476   while (1)
477     {
478       struct timeval timeout;
480       EMACS_GET_TIME (timeout);
482       /* In effect, timeout = wakeup - timeout.
483          Break if result would be negative.  */
484       if (timeval_subtract (&timeout, wakeup, timeout))
485         break;
487       /* Try to wait that long--but we might wake up sooner.  */
488       select (0, NULL, NULL, NULL, &timeout);
489     }
493 void
494 ns_release_object (void *obj)
495 /* --------------------------------------------------------------------------
496     Release an object (callable from C)
497    -------------------------------------------------------------------------- */
499     [(id)obj release];
503 void
504 ns_retain_object (void *obj)
505 /* --------------------------------------------------------------------------
506     Retain an object (callable from C)
507    -------------------------------------------------------------------------- */
509     [(id)obj retain];
513 void *
514 ns_alloc_autorelease_pool ()
515 /* --------------------------------------------------------------------------
516      Allocate a pool for temporary objects (callable from C)
517    -------------------------------------------------------------------------- */
519   return [[NSAutoreleasePool alloc] init];
523 void
524 ns_release_autorelease_pool (void *pool)
525 /* --------------------------------------------------------------------------
526      Free a pool and temporary objects it refers to (callable from C)
527    -------------------------------------------------------------------------- */
529   ns_release_object (pool);
534 /* ==========================================================================
536     Focus (clipping) and screen update
538    ========================================================================== */
540 static NSRect
541 ns_resize_handle_rect (NSWindow *window)
543   NSRect r = [window frame];
544   r.origin.x = r.size.width - RESIZE_HANDLE_SIZE;
545   r.origin.y = 0;
546   r.size.width = r.size.height = RESIZE_HANDLE_SIZE;
547   return r;
551 static void
552 ns_update_begin (struct frame *f)
553 /* --------------------------------------------------------------------------
554    Prepare for a grouped sequence of drawing calls
555    23: external (RIF) call; now split w/ and called before update_window_begin
556    -------------------------------------------------------------------------- */
558   NSView *view = FRAME_NS_VIEW (f);
559   NSTRACE (ns_update_begin);
560 /*fprintf (stderr, "\\%p\n", f); */
562   ns_updating_frame = f;
563   [view lockFocus];
565 #ifdef NS_IMPL_GNUSTEP
566   uRect = NSMakeRect (0, 0, 0, 0);
567 #endif
571 static void
572 ns_update_window_begin (struct window *w)
573 /* --------------------------------------------------------------------------
574    Prepare for a grouped sequence of drawing calls
575    23: external (RIF) call; now split with and called after update_begin
576    -------------------------------------------------------------------------- */
578   struct frame *f = XFRAME (WINDOW_FRAME (w));
579   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
580   NSTRACE (ns_update_window_begin);
582   updated_window = w;
583   set_output_cursor (&w->cursor);
585   BLOCK_INPUT;
587   if (f == dpyinfo->mouse_face_mouse_frame)
588     {
589       /* Don't do highlighting for mouse motion during the update.  */
590       dpyinfo->mouse_face_defer = 1;
592         /* If the frame needs to be redrawn,
593            simply forget about any prior mouse highlighting.  */
594       if (FRAME_GARBAGED_P (f))
595         dpyinfo->mouse_face_window = Qnil;
597       /* (further code for mouse faces ifdef'd out in other terms elided) */
598     }
600   UNBLOCK_INPUT;
604 static void
605 ns_update_window_end (struct window *w, int cursor_on_p,
606                       int mouse_face_overwritten_p)
607 /* --------------------------------------------------------------------------
608    Finished a grouped sequence of drawing calls
609    23: external (RIF) call; now split with and called before update_window_end
610    -------------------------------------------------------------------------- */
612   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (XFRAME (w->frame));
614   /* note: this fn is nearly identical in all terms */
615   if (!w->pseudo_window_p)
616     {
617       BLOCK_INPUT;
619       if (cursor_on_p)
620         display_and_set_cursor (w, 1,
621                                 output_cursor.hpos, output_cursor.vpos,
622                                 output_cursor.x, output_cursor.y);
624       if (draw_window_fringes (w, 1))
625         x_draw_vertical_border (w);
627       UNBLOCK_INPUT;
628     }
630   /* If a row with mouse-face was overwritten, arrange for
631      frame_up_to_date to redisplay the mouse highlight.  */
632   if (mouse_face_overwritten_p)
633     {
634       dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
635       dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
636       dpyinfo->mouse_face_window = Qnil;
637     }
639   updated_window = NULL;
640   NSTRACE (update_window_end);
644 static void
645 ns_update_end (struct frame *f)
646 /* --------------------------------------------------------------------------
647    Finished a grouped sequence of drawing calls
648    23: external (RIF) call; now split with and called after update_window_end
649    -------------------------------------------------------------------------- */
651   NSView *view = FRAME_NS_VIEW (f);
653 /*   if (f == FRAME_NS_DISPLAY_INFO (f)->mouse_face_mouse_frame) */
654     FRAME_NS_DISPLAY_INFO (f)->mouse_face_defer = 0;
656   BLOCK_INPUT;
658 #ifdef NS_IMPL_GNUSTEP
659   /* trigger flush only in the rectangle we tracked as being drawn */
660   [view unlockFocusNeedsFlush: NO];
661 /*fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", uRect.origin.x, uRect.origin.y, uRect.size.width, uRect.size.height); */
662   [view lockFocusInRect: uRect];
663 #endif
665   [view unlockFocus];
666   [[view window] flushWindow];
668   UNBLOCK_INPUT;
669   ns_updating_frame = NULL;
670   NSTRACE (ns_update_end);
674 static void
675 ns_flush (struct frame *f)
676 /* --------------------------------------------------------------------------
677    23: external (RIF) call
678    NS impl is no-op since currently we flush in ns_update_end and elsewhere
679    -------------------------------------------------------------------------- */
681     NSTRACE (ns_flush);
685 static void
686 ns_focus (struct frame *f, NSRect *r, int n)
687 /* --------------------------------------------------------------------------
688    Internal: Focus on given frame.  During small local updates this is used to
689      draw, however during large updates, ns_update_begin and ns_update_end are
690      called to wrap the whole thing, in which case these calls are stubbed out.
691      Except, on GNUstep, we accumulate the rectangle being drawn into, because
692      the back end won't do this automatically, and will just end up flushing
693      the entire window.
694    -------------------------------------------------------------------------- */
696   NSTRACE (ns_focus);
697 #ifdef NS_IMPL_GNUSTEP
698   NSRect u;
699     if (n == 2)
700       u = NSUnionRect (r[0], r[1]);
701     else if (r)
702       u = *r;
703 #endif
704 /* static int c =0;
705    fprintf (stderr, "focus: %d", c++);
706    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
707    fprintf (stderr, "\n"); */
709   if (f != ns_updating_frame)
710     {
711       NSView *view = FRAME_NS_VIEW (f);
712       if (view != focus_view)
713         {
714           if (focus_view != NULL)
715             {
716               [focus_view unlockFocus];
717               [[focus_view window] flushWindow];
718 /*debug_lock--; */
719             }
721           if (view)
722 #ifdef NS_IMPL_GNUSTEP
723             r ? [view lockFocusInRect: u] : [view lockFocus];
724 #else
725             [view lockFocus];
726 #endif
727           focus_view = view;
728 /*if (view) debug_lock++; */
729         }
730 #ifdef NS_IMPL_GNUSTEP
731       else
732         {
733           /* more than one rect being drawn into */
734           if (view && r)
735             {
736               [view unlockFocus]; /* add prev rect to redraw list */
737               [view lockFocusInRect: u]; /* focus for draw in new rect */
738             }
739         }
740 #endif
741     }
742 #ifdef NS_IMPL_GNUSTEP
743   else
744     {
745       /* in batch mode, but in GNUstep must still track rectangles explicitly */
746       uRect = (r ? NSUnionRect (uRect, u) : [FRAME_NS_VIEW (f) visibleRect]);
747     }
748 #endif
750   /*23: clipping */
751   if (r)
752     {
753       [[NSGraphicsContext currentContext] saveGraphicsState];
754       if (n == 2)
755         NSRectClipList (r, 2);
756       else
757         NSRectClip (*r);
758       gsaved = YES;
759     }
763 static void
764 ns_unfocus (struct frame *f)
765 /* --------------------------------------------------------------------------
766      Internal: Remove focus on given frame
767    -------------------------------------------------------------------------- */
769   NSTRACE (ns_unfocus);
771   if (gsaved)
772     {
773       [[NSGraphicsContext currentContext] restoreGraphicsState];
774       gsaved = NO;
775     }
777   if (f != ns_updating_frame)
778     {
779       if (focus_view != NULL)
780         {
781           [focus_view unlockFocus];
782           [[focus_view window] flushWindow];
783           focus_view = NULL;
784 /*debug_lock--; */
785         }
786     }
790 static void
791 ns_clip_to_row (struct window *w, struct glyph_row *row, int area, GC gc)
792 /* --------------------------------------------------------------------------
793      23: Internal (but parallels other terms): Focus drawing on given row
794    -------------------------------------------------------------------------- */
796   struct frame *f = XFRAME (WINDOW_FRAME (w));
797   NSRect clip_rect;
798   int window_x, window_y, window_width;
800   window_box (w, area, &window_x, &window_y, &window_width, 0);
802   clip_rect.origin.x = window_x - FRAME_INTERNAL_BORDER_WIDTH (f);
803   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
804   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
805   clip_rect.size.width = window_width + 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
806   clip_rect.size.height = row->visible_height;
808   /* allow a full-height row at the top when requested
809      (used to draw fringe all the way through internal border area) */
810   if (gc && clip_rect.origin.y < 5)
811     {
812       clip_rect.origin.y -= FRAME_INTERNAL_BORDER_WIDTH (f);
813       clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
814     }
816   /* likewise at bottom */
817   if (gc &&
818       FRAME_PIXEL_HEIGHT (f) - (clip_rect.origin.y + clip_rect.size.height) < 5)
819     clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
821   ns_focus (f, &clip_rect, 1);
825 static void
826 ns_ring_bell ()
827 /* --------------------------------------------------------------------------
828      "Beep" routine
829    -------------------------------------------------------------------------- */
831   NSTRACE (ns_ring_bell);
832   if (visible_bell)
833     {
834       NSAutoreleasePool *pool;
835       struct frame *frame = SELECTED_FRAME ();
836       NSView *view;
838       BLOCK_INPUT;
839       pool = [[NSAutoreleasePool alloc] init];
841       view = FRAME_NS_VIEW (frame);
842       if (view != nil)
843         {
844           NSRect r, surr;
845           NSPoint dim = NSMakePoint (128, 128);
847           r = [view bounds];
848           r.origin.x += (r.size.width - dim.x) / 2;
849           r.origin.y += (r.size.height - dim.y) / 2;
850           r.size.width = dim.x;
851           r.size.height = dim.y;
852           /* PENDING: cacheImageInRect under GNUSTEP does not account for
853              offset in x_set_window_size, so overestimate (4 fine on Cocoa) */
854           surr = NSInsetRect (r, -10, -10);
855           ns_focus (frame, &surr, 1);
856           [[view window] cacheImageInRect: surr];
857           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
858                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
859           NSRectFill (r);
860           [[view window] flushWindow];
861           ns_timeout (150000);
862           [[view window] restoreCachedImage];
863           [[view window] flushWindow];
864           ns_unfocus (frame);
865         }
866       [pool release];
867       UNBLOCK_INPUT;
868     }
869   else
870     {
871       NSBeep ();
872     }
876 static void
877 ns_reset_terminal_modes (struct terminal *terminal)
878 /*  Externally called as hook */
880   NSTRACE (ns_reset_terminal_modes);
883 static void
884 ns_set_terminal_modes (struct terminal *terminal)
885 /*  Externally called as hook */
887   NSTRACE (ns_set_terminal_modes);
892 /* ==========================================================================
894     Frame / window manager related functions
896    ========================================================================== */
899 static void
900 ns_raise_frame (struct frame *f)
901 /* --------------------------------------------------------------------------
902      Bring window to foreground and make it active
903    -------------------------------------------------------------------------- */
905   NSView *view = FRAME_NS_VIEW (f);
906   check_ns ();
907   BLOCK_INPUT;
908   [[view window] makeKeyAndOrderFront: NSApp];
909   UNBLOCK_INPUT;
913 static void
914 ns_lower_frame (struct frame *f)
915 /* --------------------------------------------------------------------------
916      Send window to back
917    -------------------------------------------------------------------------- */
919   NSView *view = FRAME_NS_VIEW (f);
920   check_ns ();
921   BLOCK_INPUT;
922   [[view window] orderBack: NSApp];
923   UNBLOCK_INPUT;
927 static void
928 ns_frame_raise_lower (struct frame *f, int raise)
929 /* --------------------------------------------------------------------------
930      External (hook)
931    -------------------------------------------------------------------------- */
933   NSTRACE (ns_frame_raise_lower);
935   if (raise)
936     ns_raise_frame (f);
937   else
938     ns_lower_frame (f);
942 static void
943 ns_frame_rehighlight (struct frame *frame)
944 /* --------------------------------------------------------------------------
945      External (hook): called on things like window switching within frame
946    -------------------------------------------------------------------------- */
948   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
949   struct frame *old_highlight = dpyinfo->ns_highlight_frame;
951   NSTRACE (ns_frame_rehighlight);
952   if (dpyinfo->ns_focus_frame)
953     {
954       dpyinfo->ns_highlight_frame =
955         (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->ns_focus_frame))
956            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->ns_focus_frame))
957            : dpyinfo->ns_focus_frame);
958       if (!FRAME_LIVE_P (dpyinfo->ns_highlight_frame))
959         {
960           FRAME_FOCUS_FRAME (dpyinfo->ns_focus_frame) = Qnil;
961           dpyinfo->ns_highlight_frame = dpyinfo->ns_focus_frame;
962         }
963     }
964   else
965       dpyinfo->ns_highlight_frame = 0;
967   if (dpyinfo->ns_highlight_frame &&
968          dpyinfo->ns_highlight_frame != old_highlight)
969     {
970       /* as of 20080602 the lower and raise are superfluous */
971       if (old_highlight)
972         {
973           /*ns_lower_frame (old_highlight); */
974           x_update_cursor (old_highlight, 1);
975         }
976       if (dpyinfo->ns_highlight_frame)
977         {
978           /*ns_raise_frame (dpyinfo->ns_highlight_frame); */
979           x_update_cursor (dpyinfo->ns_highlight_frame, 1);
980         }
981     }
985 void
986 x_make_frame_visible (struct frame *f)
987 /* --------------------------------------------------------------------------
988      External: Show the window (X11 semantics)
989    -------------------------------------------------------------------------- */
991   NSTRACE (x_make_frame_visible);
992   /* PENDING: at some points in past this was not needed, as the only place that
993      called this (frame.c:Fraise_frame ()) also called raise_lower;
994      if this ends up the case again, comment this out again. */
995   if (!FRAME_VISIBLE_P (f))
996     ns_raise_frame (f);
1000 void
1001 x_make_frame_invisible (struct frame *f)
1002 /* --------------------------------------------------------------------------
1003      External: Hide the window (X11 semantics)
1004    -------------------------------------------------------------------------- */
1006   NSView * view = FRAME_NS_VIEW (f);
1007   NSTRACE (x_make_frame_invisible);
1008   check_ns ();
1009   [[view window] orderOut: NSApp];
1013 void
1014 x_iconify_frame (struct frame *f)
1015 /* --------------------------------------------------------------------------
1016      External: Iconify window
1017    -------------------------------------------------------------------------- */
1019   NSView * view = FRAME_NS_VIEW (f);
1020   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1021   NSTRACE (x_iconify_frame);
1022   check_ns ();
1024   if (dpyinfo->ns_highlight_frame == f)
1025     dpyinfo->ns_highlight_frame = 0;
1027   if ([[view window] windowNumber] <= 0)
1028     {
1029       /* the window is still deferred.  Make it very small, bring it
1030          on screen and order it out. */
1031       NSRect s = { { 100, 100}, {0, 0} };
1032       NSRect t;
1033       t = [[view window] frame];
1034       [[view window] setFrame: s display: NO];
1035       [[view window] orderBack: NSApp];
1036       [[view window] orderOut: NSApp];
1037       [[view window] setFrame: t display: NO];
1038     }
1039   [[view window] miniaturize: NSApp];
1043 void
1044 x_destroy_window (struct frame *f)
1045 /* --------------------------------------------------------------------------
1046      External: Delete the window
1047    -------------------------------------------------------------------------- */
1049   NSView *view = FRAME_NS_VIEW (f);
1050   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1051   NSTRACE (x_destroy_window);
1052   check_ns ();
1054   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1056   BLOCK_INPUT;
1058   free_frame_menubar (f);
1060   if (FRAME_FACE_CACHE (f))
1061     free_frame_faces (f);
1063   if (f == dpyinfo->ns_focus_frame)
1064     dpyinfo->ns_focus_frame = 0;
1065   if (f == dpyinfo->ns_highlight_frame)
1066     dpyinfo->ns_highlight_frame = 0;
1067   if (f == dpyinfo->mouse_face_mouse_frame)
1068     {
1069       dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
1070       dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
1071       dpyinfo->mouse_face_window = Qnil;
1072       dpyinfo->mouse_face_deferred_gc = 0;
1073       dpyinfo->mouse_face_mouse_frame = 0;
1074     }
1076   xfree (f->output_data.ns);
1078   [[view window] close];
1079   [view release];
1081   ns_window_num--;
1082   UNBLOCK_INPUT;
1086 void
1087 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1088 /* --------------------------------------------------------------------------
1089      External: Position the window
1090    -------------------------------------------------------------------------- */
1092   NSScreen *screen;
1093   NSView *view = FRAME_NS_VIEW (f);
1095   NSTRACE (x_set_offset);
1097   BLOCK_INPUT;
1099   f->left_pos = xoff;
1100   f->top_pos = yoff;
1101 #ifdef NS_IMPL_GNUSTEP
1102   if (xoff < 100)
1103     f->left_pos = 100;  /* don't overlap menu */
1104 #endif
1105   if (view != nil && (screen = [[view window] screen]))
1106     [[view window] setFrameTopLeftPoint:
1107         NSMakePoint (SCREENMAXBOUND (f->left_pos),
1108                      SCREENMAXBOUND ([screen frame].size.height
1109                                      - NS_TOP_POS (f)))];
1110   UNBLOCK_INPUT;
1114 void
1115 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1116 /* --------------------------------------------------------------------------
1117      Adjust window pixel size based on given character grid size
1118      Impl is a bit more complex than other terms, need to do some
1119      internal clipping and also pay attention to screen constraints.
1120    -------------------------------------------------------------------------- */
1122   EmacsView *view = FRAME_NS_VIEW (f);
1123   EmacsToolbar *toolbar = [view toolbar];
1124   NSWindow *window = [view window];
1125   NSScreen *screen = [window screen];
1126   NSRect wr = [window frame];
1127   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1128   int pixelwidth, pixelheight;
1129   static int oldRows, oldCols, oldFontWidth, oldFontHeight;
1130   static int oldTB;
1131   static struct frame *oldF;
1133   NSTRACE (x_set_window_size);
1135   if (view == nil ||
1136       (f == oldF
1137        && rows == oldRows && cols == oldCols
1138        && oldFontWidth == FRAME_COLUMN_WIDTH (f)
1139        && oldFontHeight == FRAME_LINE_HEIGHT (f)
1140        && oldTB == tb))
1141     return;
1143 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1145   BLOCK_INPUT;
1147   check_frame_size (f, &rows, &cols);
1148   oldF = f;
1149   oldRows = rows;
1150   oldCols = cols;
1151   oldFontWidth = FRAME_COLUMN_WIDTH (f);
1152   oldFontHeight = FRAME_LINE_HEIGHT (f);
1153   oldTB = tb;
1155   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1156   compute_fringe_widths (f, 0);
1158   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1159   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1160   
1161   /* If we have a change in toolbar display, calculate height */
1162   if (tb)
1163     /* PENDING: GNUstep has not yet implemented the first method below, added
1164                 in Panther, however the second is incorrect under Cocoa. */
1165 #ifdef NS_IMPL_GNUSTEP
1166     FRAME_NS_TOOLBAR_HEIGHT (f) =
1167       NSHeight ([NSWindow frameRectForContentRect: NSMakeRect (0, 0, 0, 0)
1168                                        styleMask: [window styleMask]])
1169           - FRAME_NS_TITLEBAR_HEIGHT (f);
1170 #else
1171     FRAME_NS_TOOLBAR_HEIGHT (f) = 32;
1172       /* actually get wrong result here if toolbar not yet displayed
1173          NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1174          - FRAME_NS_TITLEBAR_HEIGHT (f); */
1175 #endif
1176   else
1177     FRAME_NS_TOOLBAR_HEIGHT (f) = 0;
1179   wr.size.width = pixelwidth + f->border_width;
1180   wr.size.height = pixelheight + FRAME_NS_TITLEBAR_HEIGHT (f) 
1181                   + FRAME_NS_TOOLBAR_HEIGHT (f);
1183   /* constrain to screen if we can */
1184   if (screen)
1185     {
1186       NSSize sz = [screen visibleFrame].size;
1187       NSSize ez = { wr.size.width - sz.width, wr.size.height - sz.height };
1188       if (ez.width > 0)
1189         {
1190           int cr = ez.width / FRAME_COLUMN_WIDTH (f) + 1;
1191           cols -= cr;
1192           oldCols = cols;
1193           wr.size.width -= cr * FRAME_COLUMN_WIDTH (f);
1194           pixelwidth -= cr * FRAME_COLUMN_WIDTH (f);
1195         }
1196       if (ez.height > 0)
1197         {
1198           int rr = ez.height / FRAME_LINE_HEIGHT (f) + 1;
1199           rows -= rr;
1200           oldRows = rows;
1201           wr.size.height -= rr * FRAME_LINE_HEIGHT (f);
1202           pixelheight -= rr * FRAME_LINE_HEIGHT (f);
1203         }
1204       wr.origin.x = f->left_pos;
1205       wr.origin.y = [screen frame].size.height - NS_TOP_POS (f)
1206         - wr.size.height;
1207     }
1209   [view setRows: rows andColumns: cols];
1210   [window setFrame: wr display: YES];
1212 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1214   /* This is a trick to compensate for Emacs' managing the scrollbar area
1215      as a fixed number of standard character columns.  Instead of leaving
1216      blank space for the extra, we chopped it off above.  Now for
1217      left-hand scrollbars, we shift all rendering to the left by the
1218      difference between the real width and Emacs' imagined one.  For
1219      right-hand bars, don't worry about it since the extra is never used.
1220      (Obviously doesn't work for vertically split windows tho..) */
1221   NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1222     ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1223                   - NS_SCROLL_BAR_WIDTH (f), 0)
1224     : NSMakePoint (0, 0);
1225   [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1226   [view setBoundsOrigin: origin];
1228   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1229   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1230   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1231 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1233   mark_window_cursors_off (XWINDOW (f->root_window));
1234   cancel_mouse_face (f);
1236   UNBLOCK_INPUT;
1240 /* ==========================================================================
1242     Color management
1244    ========================================================================== */
1246 NSColor *
1247 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1249   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1250   return color_table->colors[idx];
1254 unsigned long
1255 ns_index_color (NSColor *color, struct frame *f)
1257   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1258   int idx;
1259   NSNumber *index;
1261   if (!color_table->colors)
1262     {
1263       color_table->size = NS_COLOR_CAPACITY;
1264       color_table->avail = 1; /* skip idx=0 as marker */
1265       color_table->colors =
1266         (NSColor **)xmalloc (color_table->size * sizeof (NSColor *));
1267       color_table->empty_indices = [[NSMutableSet alloc] init];
1268     }
1270   /* do we already have this color ? */
1271   {
1272     int i;
1273     for (i = 1; i < color_table->avail; i++)
1274       {
1275         if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1276           {
1277             [color_table->colors[i] retain];
1278             return i;
1279           }
1280       }
1281   }
1283   if ([color_table->empty_indices count] > 0)
1284     {
1285       index = [color_table->empty_indices anyObject];
1286       [color_table->empty_indices removeObject: index];
1287       idx = [index unsignedIntValue];
1288     }
1289   else
1290     {
1291       if (color_table->avail == color_table->size)
1292         {
1293           color_table->size += NS_COLOR_CAPACITY;
1294           color_table->colors = 
1295             (NSColor **)xrealloc (color_table->colors,
1296                                   color_table->size * sizeof (NSColor *));
1297         }
1298       idx = color_table->avail++;
1299       index = [NSNumber numberWithUnsignedInt: idx];
1300     }
1302   color_table->colors[idx] = color;
1303   [color retain];
1304 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1305   return idx;
1309 void
1310 ns_free_indexed_color (unsigned long idx, struct frame *f)
1312   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1313   NSColor *color;
1314   if (!idx)
1315     return;
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 are similar for hue, saturation, value
1334    - CMYKccmmyykk is similar for cyan, magenta, yellow, black. */
1336   NSColor * new = nil;
1337   const char *hex = NULL;
1338   enum { rgb, argb, hsv, ahsv, cmyk, gray } color_space;
1339   NSString *nsname = [NSString stringWithUTF8String: name];
1341 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1342   BLOCK_INPUT;
1344   if ([nsname isEqualToString: @"ns_selection_color"])
1345     {
1346       nsname = ns_selection_color;
1347       name = [ns_selection_color UTF8String];
1348     }
1350   if (name[0] == '0' || name[0] == '1' || name[0] == '.')
1351     {
1352       /* RGB decimal */
1353       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1354       float r, g, b;
1355       [scanner scanFloat: &r];
1356       [scanner scanFloat: &g];
1357       [scanner scanFloat: &b];
1358       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1359       UNBLOCK_INPUT;
1360       return 0;
1361     }
1363   /* 23: PENDING: emacs seems to downcase everything before passing it here,
1364      which we can work around, except for GRAY, since gray##, where ## is
1365      decimal between 0 and 99, is also an X11 colorname. */
1366   if (name[0] == '#')             /* X11 format */
1367     {
1368       hex = name + 1;
1369       color_space = rgb;
1370     }
1371   else if (!memcmp (name, "RGB", 3) || !memcmp (name, "rgb", 3))
1372     {
1373       hex = name + 3;
1374       color_space = rgb;
1375     }
1376   else if (!memcmp (name, "ARGB", 4) || !memcmp (name, "argb", 4))
1377     {
1378       hex = name + 4;
1379       color_space = argb;
1380     }
1381   else if (!memcmp (name, "HSV", 3) || !memcmp (name, "hsv", 3))
1382     {
1383       hex = name + 3;
1384       color_space = hsv;
1385     }
1386   else if (!memcmp (name, "AHSV", 4) || !memcmp (name, "ahsv", 4))
1387     {
1388       hex = name + 4;
1389       color_space = ahsv;
1390     }
1391   else if (!memcmp (name, "CMYK", 4) || !memcmp (name, "cmyk", 4))
1392     {
1393       hex = name + 4;
1394       color_space = cmyk;
1395     }
1396   else if (!memcmp (name, "GRAY", 4) /*|| !memcmp (name, "gray", 4)*/)
1397     {
1398       hex = name + 4;
1399       color_space = gray;
1400     }
1402   /* Direct colors (hex values) */
1403   if (hex)
1404     {
1405       unsigned int color = 0;
1406       if (sscanf (hex, "%x", &color))
1407         {
1408           float f1 = ((color >> 24) & 0xff) / 255.0;
1409           float f2 = ((color >> 16) & 0xff) / 255.0;
1410           float f3 = ((color >>  8) & 0xff) / 255.0;
1411           float f4 = ((color      ) & 0xff) / 255.0;
1413           switch (color_space)
1414             {
1415             case rgb:
1416               *col = [NSColor colorWithCalibratedRed: f2
1417                                                green: f3
1418                                                 blue: f4
1419                                                alpha: 1.0];
1420               break;
1421             case argb:
1422               *col = [NSColor colorWithCalibratedRed: f2
1423                                                green: f3
1424                                                 blue: f4
1425                                                alpha: f1];
1426               break;
1427             case hsv:
1428               *col = [NSColor colorWithCalibratedHue: f2
1429                                           saturation: f3
1430                                           brightness: f4
1431                                                alpha: 1.0];
1432               break;
1433             case ahsv:
1434               *col = [NSColor colorWithCalibratedHue: f2
1435                                           saturation: f3
1436                                           brightness: f4
1437                                                alpha: f1];
1438               break;
1439             case gray:
1440               *col = [NSColor colorWithCalibratedWhite: f3 alpha: f4];
1441               break;
1442             case cmyk:
1443               *col = [NSColor colorWithDeviceCyan: f1
1444                                           magenta: f2
1445                                            yellow: f3
1446                                             black: f4
1447                                             alpha: 1.0];
1448               break;
1449             }
1450           *col = [*col colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1451           UNBLOCK_INPUT;
1452           return 0;
1453         }
1454     }
1456   /* Otherwise, color is expected to be from a list */
1457   {
1458     NSEnumerator *lenum, *cenum;
1459     NSString *name;
1460     NSColorList *clist;
1461 #ifdef NS_IMPL_GNUSTEP
1462     /* PENDING: who is wrong, the requestor or the implementation? */
1463     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1464         == NSOrderedSame)
1465       nsname = @"highlightColor";
1466 #endif
1467     if ([nsname compare: @"dark blue" options: NSCaseInsensitiveSearch]
1468         == NSOrderedSame
1469       || [nsname compare: @"darkblue" options: NSCaseInsensitiveSearch]
1470         == NSOrderedSame)
1471       nsname = @"navy blue";
1473     lenum = [[NSColorList availableColorLists] objectEnumerator];
1474     while ( (clist = [lenum nextObject]) && new == nil)
1475       {
1476         cenum = [[clist allKeys] objectEnumerator];
1477         while ( (name = [cenum nextObject]) && new == nil )
1478           {
1479             if ([name compare: nsname
1480                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1481               new = [clist colorWithKey: name];
1482           }
1483       }
1484   }
1486   if ( new )
1487     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1488 /*     else
1489        NSLog (@"Failed to find color '%@'", nsname); */
1490   UNBLOCK_INPUT;
1491   return new ? 0 : 1;
1495 static NSColor *
1496 ns_get_color_default (const char *name, NSColor *dflt)
1497 /* --------------------------------------------------------------------------
1498      Parse a color or use a default value
1499    -------------------------------------------------------------------------- */
1501   NSColor * col;
1503   if (ns_get_color (name, &col))
1504     return dflt;
1505   else
1506     return col;
1511 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1512 /* --------------------------------------------------------------------------
1513      Convert a Lisp string object to a NS color
1514    -------------------------------------------------------------------------- */
1516   NSTRACE (ns_lisp_to_color);
1517   if (XTYPE (color) == Lisp_String)
1518     return ns_get_color (XSTRING (color)->data, col);
1519   else if (XTYPE (color) == Lisp_Symbol)
1520     return ns_get_color (XSTRING (XSYMBOL (color)->xname)->data, col);
1521   return 1;
1525 Lisp_Object
1526 ns_color_to_lisp (NSColor *col)
1527 /* --------------------------------------------------------------------------
1528      Convert a color to a lisp string with the RGB equivalent
1529    -------------------------------------------------------------------------- */
1531   float red, green, blue, alpha, gray;
1532   char buf[1024];
1533   const char *str;
1534   NSTRACE (ns_color_to_lisp);
1536   BLOCK_INPUT;
1537   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1539       if ((str =[[col colorNameComponent] UTF8String]))
1540         {
1541           UNBLOCK_INPUT;
1542           return build_string ((char *)str);
1543         }
1545     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1546         getRed: &red green: &green blue: &blue alpha: &alpha];
1547   if (red ==green && red ==blue)
1548     {
1549       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1550             getWhite: &gray alpha: &alpha];
1551       snprintf (buf, sizeof (buf), "GRAY%02.2lx%02.2lx",
1552                lrint (gray * 0xff), lrint (alpha * 0xff));
1553       UNBLOCK_INPUT;
1554       return build_string (buf);
1555     }
1557   snprintf (buf, sizeof (buf), "ARGB%02.2lx%02.2lx%02.2lx%02.2lx",
1558             lrint (alpha*0xff),
1559             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1561   UNBLOCK_INPUT;
1562   return build_string (buf);
1567 ns_defined_color (struct frame *f, char *name, XColor *color_def, int alloc,
1568                   char makeIndex)
1569 /* --------------------------------------------------------------------------
1570    23:   Return 1 if named color found, and set color_def rgb accordingly.
1571          If makeIndex and alloc are nonzero put the color in the color_table,
1572          and set color_def pixel to the resulting index.
1573          If makeIndex is zero, set color_def pixel to ARGB.
1574          Return 0 if not found
1575    -------------------------------------------------------------------------- */
1577   NSColor *temp;
1578   float r, g, b, a;
1579   int notFound = ns_get_color (name, &temp);
1581   NSTRACE (ns_defined_color);
1583   if (notFound)
1584     return 0;
1586   if (makeIndex && alloc)
1587       color_def->pixel = ns_index_color(temp, f);//[temp retain];
1589   [temp getRed: &r green: &g blue: &b alpha: &a];
1590   color_def->red   = r * 256;
1591   color_def->green = g * 256;
1592   color_def->blue  = b * 256;
1594   if (!makeIndex)
1595     color_def->pixel =
1596       ARGB_TO_ULONG((int)(a*256),
1597                     color_def->red, color_def->green, color_def->blue);
1599   return 1;
1603 unsigned long
1604 ns_get_rgb_color (struct frame *f, float r, float g, float b, float a)
1605 /* --------------------------------------------------------------------------
1606     return an autoreleased RGB color
1607    -------------------------------------------------------------------------- */
1609 /*static int c = 1; fprintf (stderr, "color request %d\n", c++); */
1610   if (r < 0.0) r = 0.0;
1611   else if (r > 1.0) r = 1.0;
1612   if (g < 0.0) g = 0.0;
1613   else if (g > 1.0) g = 1.0;
1614   if (b < 0.0) b = 0.0;
1615   else if (b > 1.0) b = 1.0;
1616   if (a < 0.0) a = 0.0;
1617   else if (a > 1.0) a = 1.0;
1618   return (unsigned long) ns_index_color(
1619     [NSColor colorWithCalibratedRed: r green: g blue: b alpha: a], f);
1624 /* ==========================================================================
1626     Mouse handling
1628    ========================================================================== */
1631 void
1632 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1633 /* --------------------------------------------------------------------------
1634      Programmatically reposition mouse pointer in pixel coordinates
1635    -------------------------------------------------------------------------- */
1637   NSTRACE (x_set_mouse_pixel_position);
1638   ns_raise_frame (f);
1639 #if 0
1640   /*PENDING: this does not work, and what about GNUstep? */
1641 #ifdef NS_IMPL_COCOA
1642   [FRAME_NS_VIEW (f) lockFocus];
1643   PSsetmouse ((float)pix_x, (float)pix_y);
1644   [FRAME_NS_VIEW (f) unlockFocus];
1645 #endif
1646 #endif
1650 void
1651 x_set_mouse_position (struct frame *f, int h, int v)
1652 /* --------------------------------------------------------------------------
1653      Programmatically reposition mouse pointer in character coordinates
1654    -------------------------------------------------------------------------- */
1656   int pix_x, pix_y;
1658   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1659   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1661   if (pix_x < 0) pix_x = 0;
1662   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1664   if (pix_y < 0) pix_y = 0;
1665   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1667   x_set_mouse_pixel_position (f, pix_x, pix_y);
1671 static int
1672 note_mouse_movement (struct frame *frame, float x, float y)
1673 /*   ------------------------------------------------------------------------
1674      Called by EmacsView on mouseMovement events.  Passes on
1675      to emacs mainstream code if we moved off of a rect of interest
1676      known as last_mouse_glyph.
1677      ------------------------------------------------------------------------ */
1679   NSTRACE (note_mouse_movement);
1681   XSETFRAME (last_mouse_motion_frame, frame);
1682   
1683   /* Note, this doesn't get called for enter/leave, since we don't have a
1684      position.  Those are taken care of in the corresponding NSView methods. */
1686   /* has movement gone beyond last rect we were tracking? */
1687   if (x < last_mouse_glyph.origin.x ||
1688       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1689       y < last_mouse_glyph.origin.y ||
1690       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1691     {
1692       frame->mouse_moved = 1;
1693       note_mouse_highlight (frame, x, y);
1694       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1695       return 1;
1696     }
1698   return 0;
1702 static void
1703 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1704                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1705                    unsigned long *time)
1706 /* --------------------------------------------------------------------------
1707     External (hook): inform emacs about mouse position and hit parts.
1708     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1709     x & y should be position in the scrollbar (the whole bar, not the handle)
1710     and length of scrollbar respectively
1711    -------------------------------------------------------------------------- */
1713   id view;
1714   NSPoint position;
1715   int xchar, ychar;
1716   Lisp_Object frame, tail;
1717   struct frame *f;
1718   struct ns_display_info *dpyinfo;
1720   NSTRACE (ns_mouse_position);
1722   if (*fp == NULL)
1723     {
1724       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1725       return;
1726     }
1728   dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1730   BLOCK_INPUT;
1732   if (last_mouse_scroll_bar != nil && insist == 0)
1733     {
1734       /* PENDING: we do not use this path at the moment because drag events will
1735          go directly to the EmacsScroller.  Leaving code in for now. */
1736       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1737                                               x: x y: y];
1738       if (time) *time = last_mouse_movement_time;
1739       last_mouse_scroll_bar = nil;
1740     }
1741   else
1742     {
1743       /* Clear the mouse-moved flag for every frame on this display.  */
1744       FOR_EACH_FRAME (tail, frame)
1745         if (FRAME_NS_P (XFRAME (frame))
1746             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1747           XFRAME (frame)->mouse_moved = 0;
1749       last_mouse_scroll_bar = nil;
1750       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1751         f = last_mouse_frame;
1752       else
1753         f = dpyinfo->ns_focus_frame ? dpyinfo->ns_focus_frame
1754                                     : SELECTED_FRAME ();
1756       if (f && f->output_data.ns)  /*PENDING: 2nd check no longer needed? */
1757         {
1758           view = FRAME_NS_VIEW (*fp);
1760           position = [[view window] mouseLocationOutsideOfEventStream];
1761           position = [view convertPoint: position fromView: nil];
1762           remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1763 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1765           if (bar_window) *bar_window = Qnil;
1766           if (part) *part = 0; /*scroll_bar_handle; */
1768           if (x) XSETINT (*x, lrint (position.x));
1769           if (y) XSETINT (*y, lrint (position.y));
1770           if (time) *time = last_mouse_movement_time;
1771           *fp = f;
1772         }
1773     }
1775   UNBLOCK_INPUT;
1779 static void
1780 ns_frame_up_to_date (struct frame *f)
1781 /* --------------------------------------------------------------------------
1782     External (hook): Fix up mouse highlighting right after a full update.
1783     Some highlighting was deferred if GC was happening during
1784     note_mouse_highlight (), while other highlighting was deferred for update.
1785    -------------------------------------------------------------------------- */
1787   NSTRACE (ns_frame_up_to_date);
1789   if (FRAME_NS_P (f))
1790     {
1791       struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1792       if ((dpyinfo->mouse_face_deferred_gc||f ==dpyinfo->mouse_face_mouse_frame)
1793       /*&& dpyinfo->mouse_face_mouse_frame*/)
1794         {
1795           BLOCK_INPUT;
1796           if (dpyinfo->mouse_face_mouse_frame)
1797             note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
1798                                   dpyinfo->mouse_face_mouse_x,
1799                                   dpyinfo->mouse_face_mouse_y);
1800           dpyinfo->mouse_face_deferred_gc = 0;
1801           UNBLOCK_INPUT;
1802         }
1803     }
1807 void
1808 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1809 /* --------------------------------------------------------------------------
1810     External (RIF): set frame mouse pointer type.
1811    -------------------------------------------------------------------------- */
1813   NSTRACE (ns_define_frame_cursor);
1814   if (FRAME_POINTER_TYPE (f) != cursor)
1815     {
1816       EmacsView *view = FRAME_NS_VIEW (f);
1817       FRAME_POINTER_TYPE (f) = cursor;
1818       [[view window] invalidateCursorRectsForView: view];
1819     }
1824 /* ==========================================================================
1826     Keyboard handling
1828    ========================================================================== */
1831 static unsigned
1832 ns_convert_key (unsigned code)
1833 /* --------------------------------------------------------------------------
1834     Internal call used by NSView-keyDown.
1835    -------------------------------------------------------------------------- */
1837   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1838                                 / sizeof (convert_ns_to_X_keysym[0]));
1839   unsigned keysym;
1840   /* An array would be faster, but less easy to read. */
1841   for (keysym = 0; keysym < last_keysym; keysym += 2)
1842     if (code == convert_ns_to_X_keysym[keysym])
1843       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1844   return 0;
1845 /* if decide to use keyCode and Carbon table, use this line:
1846      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1850 char *
1851 x_get_keysym_name (int keysym)
1852 /* --------------------------------------------------------------------------
1853     Called by keyboard.c.  Not sure if the return val is important, except
1854     that it be unique.
1855    -------------------------------------------------------------------------- */
1857   static char value[16];
1858   NSTRACE (x_get_keysym_name);
1859   sprintf (value, "%d", keysym);
1860   return value;
1865 /* ==========================================================================
1867     Block drawing operations
1869    ========================================================================== */
1872 static void
1873 ns_redraw_scroll_bars (struct frame *f)
1875   int i;
1876   id view;
1877   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1878   NSTRACE (ns_judge_scroll_bars);
1879   for (i =[subviews count]-1; i >= 0; i--)
1880     {
1881       view = [subviews objectAtIndex: i];
1882       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1883       [view display];
1884     }
1888 void
1889 ns_clear_frame (struct frame *f)
1890 /* --------------------------------------------------------------------------
1891       External (hook): Erase the entire frame
1892    -------------------------------------------------------------------------- */
1894   NSView *view = FRAME_NS_VIEW (f);
1895   NSRect r;
1897   NSTRACE (ns_clear_frame);
1898   if (ns_in_resize)
1899     return;
1901  /* comes on initial frame because we have
1902     after-make-frame-functions = select-frame */
1903  if (!FRAME_DEFAULT_FACE (f))
1904    return;
1906   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
1908   output_cursor.hpos = output_cursor.vpos = 0;
1909   output_cursor.x = -1;
1911   r = [view bounds];
1913   BLOCK_INPUT;
1914   ns_focus (f, &r, 1);
1915   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
1916   NSRectFill (r);
1917   ns_unfocus (f);
1919 #ifdef NS_IMPL_COCOA
1920   [[view window] display];  /* redraw resize handle */
1921 #endif
1923   /* as of 2006/11 or so this is now needed */
1924   ns_redraw_scroll_bars (f);
1925   UNBLOCK_INPUT;
1929 void
1930 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
1931 /* --------------------------------------------------------------------------
1932    23: External (RIF):  Clear section of frame
1933    -------------------------------------------------------------------------- */
1935   NSRect r = NSMakeRect (x, y, width, height);
1936   NSView *view = FRAME_NS_VIEW (f);
1937   struct face *face = FRAME_DEFAULT_FACE (f);
1939   if (!view || !face)
1940     return;
1942   r = NSIntersectionRect (r, [view frame]);
1943   ns_focus (f, &r, 1);
1944   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
1946 #ifdef NS_IMPL_COCOA
1947   {
1948     /* clip out the resize handle */
1949     NSWindow *window = [FRAME_NS_VIEW (f) window];
1950     NSRect ir =
1951       [view convertRect: ns_resize_handle_rect (window) fromView: nil];
1953     ir = NSIntersectionRect (r, ir);
1954     if (NSIsEmptyRect (ir))
1955       {
1956 #endif
1958   NSRectFill (r);
1960 #ifdef NS_IMPL_COCOA
1961       }
1962     else
1963       {
1964         NSRect r1 = r, r2 = r; /* upper and lower non-intersecting */
1965         r1.size.height -= ir.size.height;
1966         r2.origin.y += r1.size.height;
1967         r2.size.width -= ir.size.width;
1968         r2.size.height = ir.size.height;
1969         NSRectFill (r1);
1970         NSRectFill (r2);
1971       }
1972   }
1973 #endif
1975   ns_unfocus (f);
1976   return;
1980 static void
1981 ns_scroll_run (struct window *w, struct run *run)
1982 /* --------------------------------------------------------------------------
1983    23: External (RIF):  Insert or delete n lines at line vpos
1984    -------------------------------------------------------------------------- */
1986   struct frame *f = XFRAME (w->frame);
1987   int x, y, width, height, from_y, to_y, bottom_y;
1989   NSTRACE (ns_scroll_run);
1991   /* begin copy from other terms */
1992   /* Get frame-relative bounding box of the text display area of W,
1993      without mode lines.  Include in this box the left and right
1994      fringe of W.  */
1995   window_box (w, -1, &x, &y, &width, &height);
1997   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
1998   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
1999   bottom_y = y + height;
2001   if (to_y < from_y)
2002     {
2003       /* Scrolling up.  Make sure we don't copy part of the mode
2004          line at the bottom.  */
2005       if (from_y + run->height > bottom_y)
2006         height = bottom_y - from_y;
2007       else
2008         height = run->height;
2009     }
2010   else
2011     {
2012       /* Scolling down.  Make sure we don't copy over the mode line.
2013          at the bottom.  */
2014       if (to_y + run->height > bottom_y)
2015         height = bottom_y - to_y;
2016       else
2017         height = run->height;
2018     }
2019   /* end copy from other terms */
2021   if (height == 0)
2022       return;
2024   BLOCK_INPUT;
2026   updated_window = w;
2027   x_clear_cursor (w);
2029   {
2030     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2031     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2032     NSPoint dstOrigin = NSMakePoint (x, to_y);
2034     ns_focus (f, &dstRect, 1);
2035     NSCopyBits (0, srcRect , dstOrigin);
2036     ns_unfocus (f);
2037   }
2039   UNBLOCK_INPUT;
2043 static void
2044 ns_after_update_window_line (struct glyph_row *desired_row)
2045 /* --------------------------------------------------------------------------
2046    23: External (RIF): preparatory to fringe update after text was updated
2047    -------------------------------------------------------------------------- */
2049   struct window *w = updated_window;
2050   struct frame *f;
2051   int width, height;
2053   NSTRACE (ns_after_update_window_line);
2055   /* begin copy from other terms */
2056   xassert (w);
2058   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2059     desired_row->redraw_fringe_bitmaps_p = 1;
2061   /* When a window has disappeared, make sure that no rest of
2062      full-width rows stays visible in the internal border.
2063      Under NS this is drawn inside the fringes. */
2064   if (windows_or_buffers_changed
2065       && (f = XFRAME (w->frame),
2066           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2067           width != 0)
2068       && (height = desired_row->visible_height,
2069           height > 0))
2070     {
2071       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2073       /* Internal border is drawn below the tool bar.  */
2074       if (WINDOWP (f->tool_bar_window)
2075           && w == XWINDOW (f->tool_bar_window))
2076         y -= width;
2077       /* end copy from other terms */
2079       BLOCK_INPUT;
2080       if (!desired_row->full_width_p)
2081         {
2082           int x1 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2083             + WINDOW_LEFT_FRINGE_WIDTH (w);
2084           int x2 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2085             + FRAME_PIXEL_WIDTH (f) - NS_SCROLL_BAR_WIDTH (f)
2086             - WINDOW_RIGHT_FRINGE_WIDTH (w)
2087             - FRAME_INTERNAL_BORDER_WIDTH (f);
2088           ns_clear_frame_area (f, x1, y, width, height);
2089           ns_clear_frame_area (f, x2, y, width, height);
2090         }
2091       UNBLOCK_INPUT;
2092     }
2096 static void
2097 ns_shift_glyphs_for_insert (struct frame *f,
2098                            int x, int y, int width, int height,
2099                            int shift_by)
2100 /* --------------------------------------------------------------------------
2101    23: External (RIF): copy an area horizontally, don't worry about clearing src
2102    -------------------------------------------------------------------------- */
2104   NSRect srcRect = NSMakeRect (x, y, width, height);
2105   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2106   NSPoint dstOrigin = dstRect.origin;
2108   NSTRACE (ns_shift_glyphs_for_insert);
2110   ns_focus (f, &dstRect, 1);
2111   NSCopyBits (0, srcRect, dstOrigin);
2112   ns_unfocus (f);
2117 /* ==========================================================================
2119     Character encoding and metrics
2121    ========================================================================== */
2124 static inline void
2125 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2126 /* --------------------------------------------------------------------------
2127    23:  External (RIF); compute left/right overhang of whole string and set in s
2128    -------------------------------------------------------------------------- */
2130   struct face *face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2131   struct font *font = s->font; /*face->font; */
2133   if (s->char2b)
2134     {
2135       struct font_metrics metrics;
2136       unsigned int codes[2];
2137       codes[0] = *(s->char2b);
2138       codes[1] = *(s->char2b + s->nchars - 1);
2140       font->driver->text_extents (font, codes, 2, &metrics);
2141       s->left_overhang = -metrics.lbearing;
2142       s->right_overhang =
2143         metrics.rbearing > metrics.width ? metrics.rbearing - metrics.width : 0;
2144     }
2145   else
2146     {
2147       s->left_overhang = 0;
2148       s->right_overhang = ((struct nsfont_info *)font)->ital ?
2149         FONT_HEIGHT (font) * 0.2 : 0;
2150     }
2155 /* ==========================================================================
2157     Fringe and cursor drawing
2159    ========================================================================== */
2162 extern int max_used_fringe_bitmap;
2163 static void
2164 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2165                       struct draw_fringe_bitmap_params *p)
2166 /* --------------------------------------------------------------------------
2167    23: External (RIF); fringe-related
2168    -------------------------------------------------------------------------- */
2170   struct frame *f = XFRAME (WINDOW_FRAME (w));
2171   struct face *face = p->face;
2172   int rowY;
2173   static EmacsImage **bimgs = NULL;
2174   static int nBimgs = 0;
2175   /* NS-specific: move internal border inside fringe */
2176   int x = p->bx < 0 ? p->x : p->bx;
2177   int wd = p->bx < 0 ? p->wd : p->nx;
2178   BOOL fringeOnVeryLeft =
2179       x - WINDOW_LEFT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w)
2180       - FRAME_INTERNAL_BORDER_WIDTH (f) < 10;
2181   BOOL fringeOnVeryRight =
2182       FRAME_PIXEL_WIDTH (f) - x - wd - FRAME_INTERNAL_BORDER_WIDTH (f)
2183       - WINDOW_RIGHT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w) < 10;
2184   int xAdjust = FRAME_INTERNAL_BORDER_WIDTH (f) *
2185     (fringeOnVeryLeft ? -1 : (fringeOnVeryRight ? 1 : 0));
2187   /* grow bimgs if needed */
2188   if (nBimgs < max_used_fringe_bitmap)
2189     {
2190       EmacsImage **newBimgs =
2191         xmalloc (max_used_fringe_bitmap * sizeof (EmacsImage *));
2192       bzero (newBimgs, max_used_fringe_bitmap * sizeof (EmacsImage *));
2194       if (nBimgs)
2195         {
2196           bcopy (bimgs, newBimgs, nBimgs * sizeof (EmacsImage *));
2197           xfree (bimgs);
2198         }
2200       bimgs = newBimgs;
2201       nBimgs = max_used_fringe_bitmap;
2202     }
2204   /* Must clip because of partially visible lines.  */
2205   rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2206   if (p->y < rowY)
2207     {
2208       /* Adjust position of "bottom aligned" bitmap on partially
2209          visible last row.  */
2210       int oldY = row->y;
2211       int oldVH = row->visible_height;
2212       row->visible_height = p->h;
2213       row->y -= rowY - p->y;
2214       ns_clip_to_row (w, row, -1, NULL);
2215       row->y = oldY;
2216       row->visible_height = oldVH;
2217     }
2218   else
2219     ns_clip_to_row (w, row, -1, YES);
2221   if (p->bx >= 0 && !p->overlay_p)
2222     {
2223       int yAdjust = rowY - FRAME_INTERNAL_BORDER_WIDTH (f) < 5 ?
2224         -FRAME_INTERNAL_BORDER_WIDTH (f) : 0;
2225       int yIncr = FRAME_PIXEL_HEIGHT (f) - (p->by+yAdjust + p->ny) < 5 ?
2226         FRAME_INTERNAL_BORDER_WIDTH (f) : 0;
2227       if (yAdjust)
2228         yIncr += FRAME_INTERNAL_BORDER_WIDTH (f);
2229       NSRect r = NSMakeRect (p->bx+xAdjust, p->by+yAdjust, p->nx, p->ny+yIncr);
2230       NSRectClip (r);
2231       [ns_lookup_indexed_color(face->background, f) set];
2232       NSRectFill (r);
2233     }
2235   if (p->which)
2236     {
2237       NSRect r = NSMakeRect (p->x+xAdjust, p->y, p->wd, p->h);
2238       NSPoint pt = r.origin;
2239       EmacsImage *img = bimgs[p->which - 1];
2241       if (!img)
2242         {
2243           unsigned short *bits = p->bits + p->dh;
2244           int len = 8 * p->h/8;
2245           int i;
2246           unsigned char *cbits = xmalloc (len);
2248           for (i =0; i<len; i++)
2249             cbits[i] = ~(bits[i] & 0xff);
2250           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2251                                            flip: NO];
2252           bimgs[p->which - 1] = img;
2253           xfree (cbits);
2254         }
2256       NSRectClip (r);
2257       /* Since we composite the bitmap instead of just blitting it, we need
2258          to erase the whole background. */
2259       [ns_lookup_indexed_color(face->background, f) set];
2260       NSRectFill (r);
2261       pt.y += p->h;
2262       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2263       [img compositeToPoint: pt operation: NSCompositeSourceOver];
2264     }
2265   ns_unfocus (f);
2269 void
2270 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2271                        int x, int y, int cursor_type, int cursor_width,
2272                        int on_p, int active_p)
2273 /* --------------------------------------------------------------------------
2274      External call (RIF): draw cursor
2275    -------------------------------------------------------------------------- */
2277   NSRect r, s;
2278   int fx, fy, h;
2279   struct frame *f = WINDOW_XFRAME (w);
2280   struct glyph *phys_cursor_glyph;
2281   int overspill;
2282   unsigned char drawGlyph = 0, cursorType, oldCursorType;
2284   NSTRACE (dumpcursor);
2286   if (!on_p)
2287       return;
2289   w->phys_cursor_type = cursor_type;
2290   w->phys_cursor_on_p = 1;
2292   if (cursor_type == NO_CURSOR)
2293     {
2294       w->phys_cursor_width = 0;
2295       return;
2296     }
2298   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2299     {
2300       if (glyph_row->exact_window_width_line_p
2301           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2302         {
2303           glyph_row->cursor_in_fringe_p = 1;
2304           draw_fringe_bitmap (w, glyph_row, 0);
2305         }
2306       return;
2307     }
2309   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2311   r.origin.x = fx, r.origin.y = fy;
2312   r.size.height = h;
2313   r.size.width = w->phys_cursor_width;
2315   /* PENDING: if we overwrite the internal border area, it does not get erased;
2316      fix by truncating cursor, but better would be to erase properly */
2317   overspill = r.origin.x + r.size.width -
2318     WINDOW_TEXT_TO_FRAME_PIXEL_X (w, WINDOW_BOX_RIGHT_EDGE_X (w) 
2319       - WINDOW_TOTAL_FRINGE_WIDTH (w) - FRAME_INTERNAL_BORDER_WIDTH (f));
2320   if (overspill > 0)
2321     r.size.width -= overspill;
2323   /* PENDING: 23: use emacs stored f->cursor_type instead of ns-specific */
2324   oldCursorType = FRAME_CURSOR (f);
2325   cursorType = FRAME_CURSOR (f) = FRAME_NEW_CURSOR (f);
2326   f->output_data.ns->current_cursor_color =
2327      f->output_data.ns->desired_cursor_color;
2329   /* PENDING: only needed in rare cases with last-resort font in HELLO..
2330      should we do this more efficiently? */
2331   ns_clip_to_row (w, glyph_row, -1, NULL);
2332 /*  ns_focus (f, &r, 1); */
2334   if (FRAME_LAST_INACTIVE (f))
2335     {
2336       /* previously hollow box; clear entire area */
2337       [FRAME_BACKGROUND_COLOR (f) set];
2338       NSRectFill (r);
2339       drawGlyph = 1;
2340       FRAME_LAST_INACTIVE (f) = NO;
2341     }
2343   /* prepare to draw */
2344   if (cursorType == no_highlight || cursor_type == NO_CURSOR)
2345     {
2346       /* clearing for blink: erase the cursor itself */
2347       [FRAME_BACKGROUND_COLOR (f) set];
2348       cursorType = oldCursorType; /* just clear what we had before */
2349     }
2350   else
2351       [FRAME_CURSOR_COLOR (f) set];
2353   if (!active_p)
2354     {
2355       /* inactive window: ignore what we just set and use a hollow box */
2356       cursorType = hollow_box;
2357       [FRAME_CURSOR_COLOR (f) set];
2358     }
2360   switch (cursorType)
2361     {
2362     case no_highlight:
2363       break;
2364     case filled_box:
2365       NSRectFill (r);
2366       drawGlyph = 1;
2367       break;
2368     case hollow_box:
2369       NSRectFill (r);
2370       [FRAME_BACKGROUND_COLOR (f) set];
2371       NSRectFill (NSInsetRect (r, 1, 1));
2372       [FRAME_CURSOR_COLOR (f) set];
2373       drawGlyph = 1;
2374       break;
2375     case underscore:
2376       s = r;
2377       s.origin.y += lrint (0.75 * s.size.height);
2378       s.size.height = lrint (s.size.height * 0.25);
2379       NSRectFill (s);
2380       break;
2381     case bar:
2382       s = r;
2383       s.size.width = 1;
2384       NSRectFill (s);
2385       break;
2386     }
2387   ns_unfocus (f);
2389   /* if needed, draw the character under the cursor */
2390   if (drawGlyph)
2391     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2395 static void
2396 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2397 /* --------------------------------------------------------------------------
2398      External (RIF): Draw a vertical line.
2399    -------------------------------------------------------------------------- */
2401   struct frame *f = XFRAME (WINDOW_FRAME (w));
2402   struct face *face;
2403   NSRect r = NSMakeRect (x, y0, 2, y1-y0);
2405   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2406   if (face)
2407       [ns_lookup_indexed_color(face->foreground, f) set];
2409   ns_focus (f, &r, 1);
2410   NSDrawGroove (r, r);
2411   ns_unfocus (f);
2415 void
2416 show_hourglass (struct atimer *timer)
2418   if (hourglass_shown_p)
2419     return;
2421   BLOCK_INPUT;
2423   /*PENDING: add NSProgressIndicator to selected frame (see macfns.c) */
2425   hourglass_shown_p = 1;
2426   UNBLOCK_INPUT;
2430 void
2431 hide_hourglass ()
2433   if (!hourglass_shown_p)
2434     return;
2436   /*PENDING: remove NSProgressIndicator from all frames */
2438   hourglass_shown_p = 0;
2439   UNBLOCK_INPUT;
2444 /* ==========================================================================
2446     Glyph drawing operations
2448    ========================================================================== */
2451 static inline NSRect
2452 /* --------------------------------------------------------------------------
2453     Under NS we draw internal borders inside fringes, and want full-width
2454     rendering to go all the way to edge.  This function makes that correction.
2455    -------------------------------------------------------------------------- */
2456 ns_fix_rect_ibw (NSRect r, int fibw, int frame_pixel_width)
2458   if (r.origin.y <= fibw+1)
2459     {
2460       r.size.height += r.origin.y;
2461       r.origin.y = 0;
2462     }
2463   if (r.origin.x <= fibw+1)
2464     {
2465       r.size.width += r.origin.x;
2466       r.origin.x = 0;
2467     }
2468   if (frame_pixel_width - (r.origin.x+r.size.width) <= fibw+1)
2469     r.size.width += fibw;
2471   return r;
2475 static int
2476 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2477 /* --------------------------------------------------------------------------
2478     Wrapper utility to account for internal border width on full-width lines,
2479     and allow top full-width rows to hit the frame top.  nr should be pointer
2480     to two successive NSRects.  Number of rects actually used is returned.
2481    -------------------------------------------------------------------------- */
2483   int n = get_glyph_string_clip_rects (s, nr, 2);
2484   if (s->row->full_width_p)
2485     {
2486       *nr = ns_fix_rect_ibw (*nr, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2487                             FRAME_PIXEL_WIDTH (s->f));
2488       if (n == 2)
2489         *nr = ns_fix_rect_ibw (*(nr+1), FRAME_INTERNAL_BORDER_WIDTH (s->f),
2490                               FRAME_PIXEL_WIDTH (s->f));
2491     }
2492   return n;
2496 static void
2497 ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char right_p)
2498 /* --------------------------------------------------------------------------
2499     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2500     Note we can't just use an NSDrawRect command, because of the possibility
2501     of some sides not being drawn, and because the rect will be filled.
2502    -------------------------------------------------------------------------- */
2504   NSRect s = r;
2505   [col set];
2507   /* top, bottom */
2508   s.size.height = thickness;
2509   NSRectFill (s);
2510   s.origin.y += r.size.height - thickness;
2511   NSRectFill (s);
2513   s.size.height = r.size.height;
2514   s.origin.y = r.origin.y;
2516   /* left, right (optional) */
2517   s.size.width = thickness;
2518   if (left_p)
2519     NSRectFill (s);
2520   if (right_p)
2521     {
2522       s.origin.x += r.size.width - thickness;
2523       NSRectFill (s);
2524     }
2528 static void
2529 ns_draw_relief (NSRect r, int thickness, char raised_p,
2530                char top_p, char bottom_p, char left_p, char right_p,
2531                struct glyph_string *s)
2532 /* --------------------------------------------------------------------------
2533     Draw a relief rect inside r, optionally leaving some sides open.
2534     Note we can't just use an NSDrawBezel command, because of the possibility
2535     of some sides not being drawn, and because the rect will be filled.
2536    -------------------------------------------------------------------------- */
2538   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2539   NSColor *newBaseCol = nil;
2540   NSRect sr = r;
2542   NSTRACE (ns_draw_relief);
2544   /* set up colors */
2546   if (s->face->use_box_color_for_shadows_p)
2547     {
2548       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2549     }
2550 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2551            && s->img->pixmap
2552            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2553        {
2554          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2555        } */
2556   else
2557     {
2558       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2559     }
2561   if (newBaseCol == nil)
2562     newBaseCol = [NSColor grayColor];
2564   if (newBaseCol != baseCol)  /* PENDING: better check */
2565     {
2566       [baseCol release];
2567       baseCol = [newBaseCol retain];
2568       [lightCol release];
2569       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2570       [darkCol release];
2571       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2572     }
2574   [(raised_p ? lightCol : darkCol) set];
2576   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2578   /* top */
2579   sr.size.height = thickness;
2580   if (top_p) NSRectFill (sr);
2582   /* left */
2583   sr.size.height = r.size.height;
2584   sr.size.width = thickness;
2585   if (left_p) NSRectFill (sr);
2587   [(raised_p ? darkCol : lightCol) set];
2589   /* bottom */
2590   sr.size.width = r.size.width;
2591   sr.size.height = thickness;
2592   sr.origin.y += r.size.height - thickness;
2593   if (bottom_p) NSRectFill (sr);
2595   /* right */
2596   sr.size.height = r.size.height;
2597   sr.origin.y = r.origin.y;
2598   sr.size.width = thickness;
2599   sr.origin.x += r.size.width - thickness;
2600   if (right_p) NSRectFill (sr);
2604 static void
2605 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2606 /* --------------------------------------------------------------------------
2607       Function modeled after x_draw_glyph_string_box ().
2608       Sets up parameters for drawing.
2609    -------------------------------------------------------------------------- */
2611   int right_x, last_x;
2612   char left_p, right_p;
2613   struct glyph *last_glyph;
2614   NSRect r;
2615   int thickness;
2616   struct face *face;
2618   if (s->hl == DRAW_MOUSE_FACE)
2619     {
2620       face = FACE_FROM_ID
2621         (s->f, FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
2622       if (!face)
2623         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2624     }
2625   else
2626     face = s->face;
2628   thickness = face->box_line_width;
2630   NSTRACE (ns_dumpglyphs_box_or_relief);
2632   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2633             ? WINDOW_RIGHT_EDGE_X (s->w)
2634             : window_box_right (s->w, s->area));
2635   last_glyph = (s->cmp || s->img
2636                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2638   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2639               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2641   left_p = (s->first_glyph->left_box_line_p
2642             || (s->hl == DRAW_MOUSE_FACE
2643                 && (s->prev == NULL || s->prev->hl != s->hl)));
2644   right_p = (last_glyph->right_box_line_p
2645              || (s->hl == DRAW_MOUSE_FACE
2646                  && (s->next == NULL || s->next->hl != s->hl)));
2648   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2650   /* expand full-width row over internal borders */
2651   if (s->row->full_width_p)
2652     r = ns_fix_rect_ibw (r, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2653                         FRAME_PIXEL_WIDTH (s->f));
2655   if (s->face->box == FACE_SIMPLE_BOX)
2656     {
2657       xassert (s->face->box_color != nil);
2658       ns_draw_box (r, abs (thickness),
2659                    ns_lookup_indexed_color (face->box_color, s->f),
2660                   left_p, right_p);
2661     }
2662   else
2663     {
2664       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2665                      1, 1, left_p, right_p, s);
2666     }
2670 static void
2671 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2672 /* --------------------------------------------------------------------------
2673       Modeled after x_draw_glyph_string_background, which draws BG in
2674       certain cases.  Others are left to the text rendering routine.
2675    -------------------------------------------------------------------------- */
2677   NSTRACE (ns_maybe_dumpglyphs_background);
2679   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2680     {
2681       int box_line_width = max (s->face->box_line_width, 0);
2682       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2683           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2684         {
2685           struct face *face;
2686           if (s->hl == DRAW_MOUSE_FACE)
2687             {
2688               face = FACE_FROM_ID
2689                 (s->f, FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
2690               if (!face)
2691                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2692             }
2693           else
2694             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2695           if (!face->stipple)
2696             [(NS_FACE_BACKGROUND (face) != nil
2697               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2698               : FRAME_BACKGROUND_COLOR (s->f)) set];
2699           else
2700             {
2701               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2702               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2703             }
2705           if (s->hl != DRAW_CURSOR)
2706             {
2707               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2708                                     s->background_width,
2709                                     s->height-2*box_line_width);
2711               /* expand full-width row over internal borders */
2712               if (s->row->full_width_p)
2713                 {
2714                   int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2715                   if (r.origin.y <= fibw+1 + box_line_width)
2716                     {
2717                       r.size.height += r.origin.y;
2718                       r.origin.y = 0;
2719                     }
2720                   if (r.origin.x <= fibw+1)
2721                     {
2722                       r.size.width += 2*r.origin.x;
2723                       r.origin.x = 0;
2724                     }
2725                   if (FRAME_PIXEL_WIDTH (s->f) - (r.origin.x + r.size.width)
2726                       <= fibw+1)
2727                     r.size.width += fibw;
2728                 }
2730               NSRectFill (r);
2731             }
2733           s->background_filled_p = 1;
2734         }
2735     }
2739 static void
2740 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2741 /* --------------------------------------------------------------------------
2742       Renders an image and associated borders.
2743    -------------------------------------------------------------------------- */
2745   EmacsImage *img = s->img->pixmap;
2746   int box_line_vwidth = max (s->face->box_line_width, 0);
2747   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2748   int bg_x, bg_y, bg_height;
2749   int th;
2750   char raised_p;
2751   NSRect br;
2753   NSTRACE (ns_dumpglyphs_image);
2755   if (s->face->box != FACE_NO_BOX
2756       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2757     x += abs (s->face->box_line_width);
2759   bg_x = x;
2760   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2761   bg_height = s->height;
2762   /* other terms have this, but was causing problems w/tabbar mode */
2763   /* - 2 * box_line_vwidth; */
2765   if (s->slice.x == 0) x += s->img->hmargin;
2766   if (s->slice.y == 0) y += s->img->vmargin;
2768   /* Draw BG: if we need larger area than image itself cleared, do that,
2769      otherwise, since we composite the image under NS (instead of mucking
2770      with its background color), we must clear just the image area. */
2771   [ns_lookup_indexed_color (NS_FACE_BACKGROUND
2772             (FACE_FROM_ID (s->f, s->first_glyph->face_id)), s->f) set];
2774   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2775       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2776     {
2777       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
2778       s->background_filled_p = 1;
2779     }
2780   else
2781     {
2782       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
2783     }
2785   /* expand full-width row over internal borders */
2786   if (s->row->full_width_p)
2787     {
2788       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2789       if (br.origin.y <= fibw+1 + box_line_vwidth)
2790         {
2791           br.size.height += br.origin.y;
2792           br.origin.y = 0;
2793         }
2794       if (br.origin.x <= fibw+1 + box_line_vwidth)
2795         {
2796           br.size.width += br.origin.x;
2797           br.origin.x = 0;
2798         }
2799       if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) <= fibw+1)
2800         br.size.width += fibw;
2801     }
2803   NSRectFill (br);
2805   /* Draw the image.. do we need to draw placeholder if img ==nil? */
2806   if (img != nil)
2807     [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
2808                 operation: NSCompositeSourceOver];
2810   /* Draw relief, if requested */
2811   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
2812     {
2813       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
2814         {
2815           th = tool_bar_button_relief >= 0 ?
2816             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
2817           raised_p = (s->hl == DRAW_IMAGE_RAISED);
2818         }
2819       else
2820         {
2821           th = abs (s->img->relief);
2822           raised_p = (s->img->relief > 0);
2823         }
2825       r.origin.x = x - th;
2826       r.origin.y = y - th;
2827       r.size.width = s->slice.width + 2*th-1;
2828       r.size.height = s->slice.height + 2*th-1;
2829       ns_draw_relief (r, th, raised_p,
2830                      s->slice.y == 0,
2831                      s->slice.y + s->slice.height == s->img->height,
2832                      s->slice.x == 0,
2833                      s->slice.x + s->slice.width == s->img->width, s);
2834     }
2838 static void
2839 ns_draw_glyph_string (struct glyph_string *s)
2840 /* --------------------------------------------------------------------------
2841       External (RIF): Main draw-text call.
2842    -------------------------------------------------------------------------- */
2844   /*PENDING (optimize): focus for box and contents draw */
2845   NSRect r[2];
2846   int n;
2847   char box_drawn_p = 0;
2849   NSTRACE (ns_draw_glyph_string);
2851   if (s->next && s->right_overhang && !s->for_overlaps && s->hl != DRAW_CURSOR)
2852     {
2853       xassert (s->next->img == NULL);
2854       n = ns_get_glyph_string_clip_rect (s->next, r);
2855       ns_focus (s->f, r, n);
2856       ns_maybe_dumpglyphs_background (s->next, 1);
2857       ns_unfocus (s->f);
2858     }
2860   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
2861         && (s->first_glyph->type == CHAR_GLYPH
2862             || s->first_glyph->type == COMPOSITE_GLYPH))
2863     {
2864       n = ns_get_glyph_string_clip_rect (s, r);
2865       ns_focus (s->f, r, n);
2866       ns_maybe_dumpglyphs_background (s, 1);
2867       ns_dumpglyphs_box_or_relief (s);
2868       ns_unfocus (s->f);
2869       box_drawn_p = 1;
2870     }
2872   switch (s->first_glyph->type)
2873     {
2875     case IMAGE_GLYPH:
2876       n = ns_get_glyph_string_clip_rect (s, r);
2877       ns_focus (s->f, r, n);
2878       ns_dumpglyphs_image (s, r[0]);
2879       ns_unfocus (s->f);
2880       break;
2882     case STRETCH_GLYPH:
2883       if (!s->background_filled_p)
2884         {
2885           *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
2887           if (!s->row->full_width_p)
2888             {
2889               /* truncate to avoid overwriting fringe and/or scrollbar */
2890               int overrun = max (0, (s->x + s->background_width)
2891                                  - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
2892                                     - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
2893               r[0].size.width -= overrun;
2895               /* PENDING: Try to work between problem where a stretch glyph on
2896                  a partially-visible bottom row will clear part of the
2897                  modeline, and another where list-buffers headers and similar
2898                  rows erroneously have visible_height set to 0.  Not sure
2899                  where this is coming from as other terms seem not to show. */
2900               r[0].size.height = min (s->height, s->row->visible_height);
2901             }
2903           /* expand full-width rows over internal borders */
2904           else
2905             {
2906               r[0] = ns_fix_rect_ibw (r[0], FRAME_INTERNAL_BORDER_WIDTH (s->f),
2907                                      FRAME_PIXEL_WIDTH (s->f));
2908             }
2910           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
2911              overwriting cursor (usually when cursor on a tab) */
2912           if (s->hl == DRAW_CURSOR)
2913             {
2914               r[0].origin.x += s->width;
2915               r[0].size.width -= s->width;
2916             }
2918           ns_focus (s->f, r, 1);
2919           [ns_lookup_indexed_color (NS_FACE_BACKGROUND
2920                (FACE_FROM_ID (s->f, s->first_glyph->face_id)), s->f) set];
2921           NSRectFill (r[0]);
2922           ns_unfocus (s->f);
2923           s->background_filled_p = 1;
2924         }
2925       break;
2927     case CHAR_GLYPH:
2928     case COMPOSITE_GLYPH:
2929       n = ns_get_glyph_string_clip_rect (s, r);
2930       ns_focus (s->f, r, n);
2932       if (s->for_overlaps || s->gidx > 0)
2933         s->background_filled_p = 1;
2934       else      /* 1 */
2935         ns_maybe_dumpglyphs_background
2936           (s, s->first_glyph->type == COMPOSITE_GLYPH);
2938       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
2939                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
2940                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
2941                       NS_DUMPGLYPH_NORMAL));
2942       ns_tmp_font = (struct nsfont_info *)s->face->font;
2943       if (ns_tmp_font == ~0 || ns_tmp_font == NULL)
2944           ns_tmp_font = FRAME_FONT (s->f);
2946       ns_tmp_font->font.driver->draw
2947         (s, 0, s->nchars, s->x, s->y,
2948          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
2949          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
2951       ns_unfocus (s->f);
2952       break;
2954     default:
2955       abort ();
2956     }
2958   /* Draw box if not done already. */
2959   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
2960     {
2961       n = ns_get_glyph_string_clip_rect (s, r);
2962       ns_focus (s->f, r, n);
2963       ns_dumpglyphs_box_or_relief (s);
2964       ns_unfocus (s->f);
2965     }
2971 /* ==========================================================================
2973     Event loop
2975    ========================================================================== */
2978 static void
2979 ns_send_appdefined (int value)
2980 /* --------------------------------------------------------------------------
2981     Internal: post an appdefined event which EmacsApp-sendEvent will
2982               recognize and take as a command to halt the event loop.
2983    -------------------------------------------------------------------------- */
2985   /*NSTRACE (ns_send_appdefined); */
2987   /* Only post this event if we haven't already posted one.  This will end
2988        the [NXApp run] main loop after having processed all events queued at
2989        this moment.  */
2990   if (send_appdefined)
2991     {
2992       NSEvent *nxev;
2994       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
2995       send_appdefined = NO;
2997       /* Don't need wakeup timer any more */
2998       if (timed_entry)
2999         {
3000           [timed_entry invalidate];
3001           [timed_entry release];
3002           timed_entry = nil;
3003         }
3005       /* Ditto for file descriptor poller */
3006       if (fd_entry)
3007         {
3008           [fd_entry invalidate];
3009           [fd_entry release];
3010           fd_entry = nil;
3011         }
3013       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3014                                 location: NSMakePoint (0, 0)
3015                            modifierFlags: 0
3016                                timestamp: 0
3017                             windowNumber: [[NSApp mainWindow] windowNumber]
3018                                  context: [NSApp context]
3019                                  subtype: 0
3020                                    data1: value
3021                                    data2: 0];
3023       /* Post an application defined event on the event queue.  When this is
3024          received the [NXApp run] will return, thus having processed all
3025          events which are currently queued.  */
3026       [NSApp postEvent: nxev atStart: NO];
3027     }
3031 static int
3032 ns_read_socket (struct terminal *terminal, int expected,
3033                 struct input_event *hold_quit)
3034 /* --------------------------------------------------------------------------
3035      External (hook): Post an event to ourself and keep reading events until
3036      we read it back again.  In effect process all events which were waiting.
3037    23: Now we have to manage the event buffer ourselves.
3038    -------------------------------------------------------------------------- */
3040   struct input_event ev;
3041   int nevents;
3042   static NSDate *lastCheck = nil;
3043 /*  NSTRACE (ns_read_socket); */
3045   if (interrupt_input_blocked)
3046     {
3047       interrupt_input_pending = 1;
3048       return -1;
3049     }
3051   interrupt_input_pending = 0;
3052   BLOCK_INPUT;
3054 #ifdef COCOA_EXPERIMENTAL_CTRL_G
3055   /* causes Feval to abort; unclear on why this isn't in calling code */
3056   ++handling_signal;
3057 #endif
3059   n_emacs_events_pending = 0;
3060   EVENT_INIT (ev);
3061   emacs_event = &ev;
3062   q_event_ptr = hold_quit;
3064   /* we manage autorelease pools by allocate/reallocate each time around
3065      the loop; strict nesting is occasionally violated but seems not to
3066      matter.. earlier methods using full nesting caused major memory leaks */
3067   [outerpool release];
3068   outerpool = [[NSAutoreleasePool alloc] init];
3070   /* If have pending open-file requests, attend to the next one of those. */
3071   if (ns_pending_files && [ns_pending_files count] != 0
3072       && [NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3073     {
3074       [ns_pending_files removeObjectAtIndex: 0];
3075     }
3076   /* Deal with pending service requests. */
3077   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3078     && [NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3079                      withArg: [ns_pending_service_args objectAtIndex: 0]])
3080     {
3081       [ns_pending_service_names removeObjectAtIndex: 0];
3082       [ns_pending_service_args removeObjectAtIndex: 0];
3083     }
3084   else
3085     {
3086       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3087          to ourself, otherwise [NXApp run] will never exit.  */
3088       send_appdefined = YES;
3090       /*PENDING: from termhooks.h: */
3091       /* XXX Please note that a non-zero value of EXPECTED only means that
3092      there is available input on at least one of the currently opened
3093      terminal devices -- but not necessarily on this device.
3094      Therefore, in most cases EXPECTED should be simply ignored. */
3095       /* However, if in ns_select, this is called from gobble_input, which
3096          appears to set it correctly for our purposes, and always assuming
3097          !expected causes 100% CPU usage. */
3098       if (!inNsSelect || !expected)
3099         {
3100           /* Post an application defined event on the event queue.  When this is
3101              received the [NXApp run] will return, thus having processed all
3102              events which are currently queued, if any.  */
3103           ns_send_appdefined (-1);
3104         }
3106       [NSApp run];
3107     }
3109   nevents = n_emacs_events_pending;
3110   n_emacs_events_pending = 0;
3111   emacs_event = q_event_ptr = NULL;
3113 #ifdef COCOA_EXPERIMENTAL_CTRL_G
3114   --handling_signal;
3115 #endif
3116   UNBLOCK_INPUT;
3117   return nevents;
3122 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3123            fd_set *exceptfds, struct timeval *timeout)
3124 /* --------------------------------------------------------------------------
3125      Replacement for select, checking for events
3126    -------------------------------------------------------------------------- */
3128   int result;
3129   double time;
3130   NSEvent *ev;
3131 /*  NSTRACE (ns_select); */
3133   if (NSApp == nil /* || ([NSApp isActive] == NO &&
3134                       [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil
3135  inMode:NSDefaultRunLoopMode dequeue:NO] == nil) */)
3136     return select (nfds, readfds, writefds, exceptfds, timeout);
3138   /* Save file descriptor set, which gets overwritten in calls to select ()
3139      Note, this is called from process.c, and only readfds is ever set */
3140   if (readfds)
3141     {
3142       memcpy (&select_readfds, readfds, sizeof (fd_set));
3143       select_nfds = nfds;
3144     }
3145   else
3146     select_nfds = 0;
3148     /* Try an initial select for pending data on input files */
3149   select_timeout.tv_sec = select_timeout.tv_usec = 0;
3150   result = select (nfds, readfds, writefds, exceptfds, &select_timeout);
3151   if (result)
3152     return result;
3154   /* if (!timeout || timed_entry || fd_entry)
3155        fprintf (stderr, "assertion failed: timeout null or timed_entry/fd_entry non-null in ns_select\n"); */
3157     /* set a timeout and run the main AppKit event loop while continuing
3158        to monitor the files */
3159   time = ((double) timeout->tv_sec) + ((double) timeout->tv_usec)/1000000.0;
3160   timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3161                                            target: NSApp
3162                                          selector: @selector (timeout_handler:)
3163                                          userInfo: 0
3164                                           repeats: YES] /* for safe removal */
3165                                                          retain];
3167   /* set a periodic task to try the select () again */
3168   fd_entry = [[NSTimer scheduledTimerWithTimeInterval: 0.1
3169                                                target: NSApp
3170                                              selector: @selector (fd_handler:)
3171                                              userInfo: 0
3172                                               repeats: YES]
3173                retain];
3175   if (!NILP (ns_cursor_blink_mode) && !cursor_blink_entry)
3176     {
3177       if (!NUMBERP (ns_cursor_blink_rate))
3178         ns_cursor_blink_rate = make_float (0.5);
3179       cursor_blink_entry = [[NSTimer
3180         scheduledTimerWithTimeInterval: XFLOATINT (ns_cursor_blink_rate)
3181                                 target: NSApp
3182                               selector: @selector (cursor_blink_handler:)
3183                               userInfo: 0
3184                                repeats: YES]
3185                              retain];
3186     }
3187   else if (NILP (ns_cursor_blink_mode) && cursor_blink_entry)
3188     {
3189       if (NUMBERP (ns_cursor_blink_rate))
3190           ns_cursor_blink_rate = Qnil;
3191       struct ns_display_info *dpyinfo = ns_display_list; /* HACK */
3192       [cursor_blink_entry invalidate];
3193       [cursor_blink_entry release];
3194       cursor_blink_entry = 0;
3195       if (dpyinfo->ns_highlight_frame)
3196         {
3197           Lisp_Object tem = 
3198             get_frame_param (dpyinfo->ns_highlight_frame, Qcursor_type);
3199           dpyinfo->ns_highlight_frame->output_data.ns->desired_cursor =
3200             ns_lisp_to_cursor_type (tem);
3201         }
3202     }
3204   /* Let Application dispatch events until it receives an event of the type
3205        NX_APPDEFINED, which should only be sent by timeout_handler.  */
3206   inNsSelect = 1;
3207   gobble_input (timeout ? 1 : 0);
3208   ev = last_appdefined_event;
3209   inNsSelect = 0;
3211   if (ev)
3212     {
3213       int t;
3214       if ([ev type] != NSApplicationDefined)
3215         abort ();
3217       t = [ev data1];
3218       last_appdefined_event = 0;
3220       if (t == -2)
3221         {
3222           /* The NX_APPDEFINED event we received was a timeout. */
3223           return 0;
3224         }
3225       else if (t == -1)
3226         {
3227           /* The NX_APPDEFINED event we received was the result of
3228              at least one real input event arriving.  */
3229           errno = EINTR;
3230           return -1;
3231         }
3232       else
3233         {
3234           /* Received back from select () in fd_handler; copy the results */
3235           if (readfds)
3236             memcpy (readfds, &select_readfds, sizeof (fd_set));
3237           return t;
3238         }
3239     }
3240   /* never reached, shut compiler up */
3241   return 0;
3246 /* ==========================================================================
3248     Scrollbar handling
3250    ========================================================================== */
3253 static void
3254 ns_set_vertical_scroll_bar (struct window *window,
3255                            int portion, int whole, int position)
3256 /* --------------------------------------------------------------------------
3257       External (hook): Update or add scrollbar
3258    -------------------------------------------------------------------------- */
3260   Lisp_Object win;
3261   NSRect r, v;
3262   struct frame *f = XFRAME (WINDOW_FRAME (window));
3263   EmacsView *view = FRAME_NS_VIEW (f);
3264   int window_y, window_height;
3265   BOOL barOnVeryLeft, barOnVeryRight;
3266   int top, left, height, width, sb_width, sb_left;
3267   EmacsScroller *bar;
3268 static int count = 0;
3270   /* optimization; display engine sends WAY too many of these.. */
3271   if (!NILP (window->vertical_scroll_bar))
3272     {
3273       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3274       if ([bar checkSamePosition: position portion: portion whole: whole])
3275         {
3276           if (view->scrollbarsNeedingUpdate == 0)
3277             {
3278               if (!windows_or_buffers_changed)
3279                   return;
3280             }
3281           else
3282             view->scrollbarsNeedingUpdate--;
3283         }
3284     }
3286   NSTRACE (ns_set_vertical_scroll_bar);
3288   /* Get dimensions.  */
3289   window_box (window, -1, 0, &window_y, 0, &window_height);
3290   top = window_y;
3291   height = window_height;
3292   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3293   left = WINDOW_SCROLL_BAR_AREA_X (window);
3295   if (top < 5) /* top scrollbar adjustment */
3296     {
3297       top -= FRAME_INTERNAL_BORDER_WIDTH (f);
3298       height += FRAME_INTERNAL_BORDER_WIDTH (f);
3299     }
3301   /* allow for displaying a skinnier scrollbar than char area allotted */
3302   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3303     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3305   barOnVeryLeft = left < 5;
3306   barOnVeryRight = FRAME_PIXEL_WIDTH (f) - left - width < 5;
3307   sb_left = left + FRAME_INTERNAL_BORDER_WIDTH (f)
3308       * (barOnVeryLeft ? -1 : (barOnVeryRight ? 1 : 0));
3310   r = NSMakeRect (sb_left, top, sb_width, height);
3311   /* the parent view is flipped, so we need to flip y value */
3312   v = [view frame];
3313   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3315   XSETWINDOW (win, window);
3316   BLOCK_INPUT;
3318   /* we want at least 5 lines to display a scrollbar */
3319   if (WINDOW_TOTAL_LINES (window) < 5)
3320     {
3321       if (!NILP (window->vertical_scroll_bar))
3322         {
3323           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3324           [bar removeFromSuperview];
3325           window->vertical_scroll_bar = Qnil;
3326         }
3327       ns_clear_frame_area (f, sb_left, top, width, height);
3328       UNBLOCK_INPUT;
3329       return;
3330     }
3332   if (NILP (window->vertical_scroll_bar))
3333     {
3334       ns_clear_frame_area (f, sb_left, top, width, height);
3335       bar = [[EmacsScroller alloc] initFrame: r window: win];
3336       window->vertical_scroll_bar = make_save_value (bar, 0);
3337     }
3338   else
3339     {
3340       NSRect oldRect;
3341       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3342       oldRect = [bar frame];
3343       r.size.width = oldRect.size.width;
3344       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3345         {
3346           if (oldRect.origin.x != r.origin.x)
3347               ns_clear_frame_area (f, sb_left, top, width, height);
3348           [bar setFrame: r];
3349         }
3350     }
3352   [bar setPosition: position portion: portion whole: whole];
3353   UNBLOCK_INPUT;
3357 static void
3358 ns_condemn_scroll_bars (struct frame *f)
3359 /* --------------------------------------------------------------------------
3360      External (hook): arrange for all frame's scrollbars to be removed
3361      at next call to judge_scroll_bars, except for those redeemed.
3362    -------------------------------------------------------------------------- */
3364   int i;
3365   id view;
3366   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3368   NSTRACE (ns_condemn_scroll_bars);
3370   for (i =[subviews count]-1; i >= 0; i--)
3371     {
3372       view = [subviews objectAtIndex: i];
3373       if ([view isKindOfClass: [EmacsScroller class]])
3374         [view condemn];
3375     }
3379 static void
3380 ns_redeem_scroll_bar (struct window *window)
3381 /* --------------------------------------------------------------------------
3382      External (hook): arrange to spare this window's scrollbar
3383      at next call to judge_scroll_bars.
3384    -------------------------------------------------------------------------- */
3386   id bar;
3387   NSTRACE (ns_redeem_scroll_bar);
3388   if (!NILP (window->vertical_scroll_bar))
3389     {
3390       bar =XNS_SCROLL_BAR (window->vertical_scroll_bar);
3391       [bar reprieve];
3392     }
3396 static void
3397 ns_judge_scroll_bars (struct frame *f)
3398 /* --------------------------------------------------------------------------
3399      External (hook): destroy all scrollbars on frame that weren't
3400      redeemed after call to condemn_scroll_bars.
3401    -------------------------------------------------------------------------- */
3403   int i;
3404   id view;
3405   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3406   NSTRACE (ns_judge_scroll_bars);
3407   for (i =[subviews count]-1; i >= 0; i--)
3408     {
3409       view = [subviews objectAtIndex: i];
3410       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3411       [view judge];
3412     }
3417 /* ==========================================================================
3419     Miscellaneous, mainly stubbed-out functions added in 23
3421    ========================================================================== */
3424 void
3425 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
3431 /* ==========================================================================
3433     Initialization
3435    ========================================================================== */
3437 static Lisp_Object ns_string_to_lispmod (char *s)
3438 /* --------------------------------------------------------------------------
3439      Convert modifier name to lisp symbol
3440    -------------------------------------------------------------------------- */
3442   if (!strncmp (SDATA (SYMBOL_NAME (Qmeta)), s, 10))
3443     return Qmeta;
3444   else if (!strncmp (SDATA (SYMBOL_NAME (Qsuper)), s, 10))
3445     return Qsuper;
3446   else if (!strncmp (SDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3447     return Qcontrol;
3448   else if (!strncmp (SDATA (SYMBOL_NAME (Qalt)), s, 10))
3449     return Qalt;
3450   else if (!strncmp (SDATA (SYMBOL_NAME (Qhyper)), s, 10))
3451     return Qhyper;
3452   else if (!strncmp (SDATA (SYMBOL_NAME (Qnone)), s, 10))
3453     return Qnone;
3454   else
3455     return Qnil;
3459 static Lisp_Object ns_mod_to_lisp (int m)
3460 /* --------------------------------------------------------------------------
3461      Convert modifier code (see lisp.h) to lisp symbol
3462    -------------------------------------------------------------------------- */
3464   if (m == CHAR_META)
3465     return Qmeta;
3466   else if (m == CHAR_SUPER)
3467     return Qsuper;
3468   else if (m == CHAR_CTL)
3469     return Qcontrol;
3470   else if (m == CHAR_ALT)
3471     return Qalt;
3472   else if (m == CHAR_HYPER)
3473     return Qhyper;
3474   else /* if (m == 0) */
3475     return Qnone;
3479 static void
3480 ns_set_default_prefs ()
3481 /* --------------------------------------------------------------------------
3482       Initialize preference variables to defaults
3483    -------------------------------------------------------------------------- */
3485   ns_alternate_modifier = Qmeta;
3486   ns_command_modifier = Qsuper;
3487   ns_control_modifier = Qcontrol;
3488   ns_function_modifier = Qnone;
3489   ns_cursor_blink_rate = Qnil;
3490   ns_cursor_blink_mode = Qnil;
3491   ns_expand_space = make_float (0.0);
3492   ns_antialias_text = YES;
3493   ns_antialias_threshold = 10.0;
3494   ns_use_qd_smoothing = NO;
3495   ns_use_system_highlight_color = YES;
3499 static void
3500 ns_default (const char *parameter, Lisp_Object *result,
3501            Lisp_Object yesval, Lisp_Object noval,
3502            BOOL is_float, BOOL is_modstring)
3503 /* --------------------------------------------------------------------------
3504       Check a parameter value in user's preferences
3505    -------------------------------------------------------------------------- */
3507   const char *value;
3509   if ( (value =[[[NSUserDefaults standardUserDefaults]
3510                    stringForKey: [NSString stringWithUTF8String: parameter]]
3511                 UTF8String]) )
3512     {
3513       double f;
3514       char *pos;
3515       if (strcasecmp (value, "YES") == 0)
3516         *result = yesval;
3517       else if (strcasecmp (value, "NO") == 0)
3518         *result = noval;
3519       else if (is_float && (f = strtod (value, &pos), pos != value))
3520         *result = make_float (f);
3521       else if (is_modstring && value)
3522         *result = ns_string_to_lispmod (value);
3523       else fprintf (stderr,
3524                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3525     }
3529 void
3530 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3531 /* --------------------------------------------------------------------------
3532       Initialize global info and storage for display.
3533    -------------------------------------------------------------------------- */
3535     NSScreen *screen = [NSScreen mainScreen];
3536     NSWindowDepth depth = [screen depth];
3538     dpyinfo->width = [screen frame].size.width;
3539     dpyinfo->height = [screen frame].size.height;
3540     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3541     dpyinfo->resy = 72.27;
3542     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3543                                                   NSColorSpaceFromDepth (depth)]
3544                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3545                                                  NSColorSpaceFromDepth (depth)];
3546     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3547     dpyinfo->image_cache = make_image_cache ();
3548     dpyinfo->color_table =
3549       (struct ns_color_table *)xmalloc (sizeof (struct ns_color_table));
3550     dpyinfo->color_table->colors = NULL;
3551     dpyinfo->root_window = 42; /* a placeholder.. */
3553     dpyinfo->mouse_face_mouse_frame = NULL;
3554     dpyinfo->mouse_face_deferred_gc = 0;
3555     dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
3556     dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
3557     dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
3558     dpyinfo->mouse_face_window = dpyinfo->mouse_face_overlay = Qnil;
3559     dpyinfo->mouse_face_hidden = 0;
3561     dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
3562     dpyinfo->mouse_face_defer = 0;
3564     dpyinfo->ns_highlight_frame = dpyinfo->ns_focus_frame = NULL;
3566     dpyinfo->n_fonts = 0;
3567     dpyinfo->smallest_font_height = 1;
3568     dpyinfo->smallest_char_width = 1;
3572 /* 23: Needed as new part of display engine; this and next define public
3573       functions in this file (well, many of them, anyway). */
3574 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3575          with using despite presence in the "system dependent" redisplay
3576          interface.  In addition, many of the ns_ methods have code that is
3577          shared with all terms, indicating need for further refactoring. */
3578 extern frame_parm_handler ns_frame_parm_handlers[];
3579 static struct redisplay_interface ns_redisplay_interface =
3581   ns_frame_parm_handlers,
3582   x_produce_glyphs, /*generic OK */
3583   x_write_glyphs, /*generic OK */
3584   x_insert_glyphs, /*generic OK */
3585   x_clear_end_of_line, /*generic OK */
3586   ns_scroll_run, /*23 */
3587   ns_after_update_window_line, /*23: added */
3588   ns_update_window_begin, /*23: split from update_begin */
3589   ns_update_window_end, /*23: split from update_end */
3590   x_cursor_to, /*generic OK */
3591   ns_flush,
3592   0, /* flush_display_optional */
3593   x_clear_window_mouse_face, /*generic OK */
3594   x_get_glyph_overhangs, /*23: generic OK */
3595   x_fix_overlapping_area, /*generic OK */
3596   ns_draw_fringe_bitmap, /*23 */
3597   0, /* define_fringe_bitmap */ /*PENDING: simplify ns_draw_fringe_bitmap? */
3598   0, /* destroy_fringe_bitmap */
3599   ns_compute_glyph_string_overhangs, /*23 */
3600   ns_draw_glyph_string, /*23: interface to nsfont.m */
3601   ns_define_frame_cursor, /*23 */
3602   ns_clear_frame_area, /*23 */
3603   ns_draw_window_cursor, /*23: revamped ns_dumpcursor */
3604   ns_draw_vertical_window_border,
3605   ns_shift_glyphs_for_insert
3609 static void
3610 ns_delete_display (struct ns_display_info *dpyinfo)
3612   /*PENDING... */
3616 /* This function is called when the last frame on a display is deleted. */
3617 static void
3618 ns_delete_terminal (struct terminal *terminal)
3620   struct ns_display_info *dpyinfo = terminal->display_info.ns;
3621   int i;
3623   /* Protect against recursive calls.  Fdelete_frame in
3624      delete_terminal calls us back when it deletes our last frame.  */
3625   if (!terminal->name)
3626     return;
3628   BLOCK_INPUT;
3630   x_destroy_all_bitmaps (dpyinfo);
3631   ns_delete_display (dpyinfo);
3632   UNBLOCK_INPUT;
3636 static struct terminal *
3637 ns_create_terminal (struct ns_display_info *dpyinfo)
3638 /* --------------------------------------------------------------------------
3639       Set up use of NS before we make the first connection.
3640    -------------------------------------------------------------------------- */
3642   struct terminal *terminal;
3644   NSTRACE (ns_create_terminal);
3646   terminal = create_terminal ();
3648   terminal->type = output_ns;
3649   terminal->display_info.ns = dpyinfo;
3650   dpyinfo->terminal = terminal;
3652   terminal->rif = &ns_redisplay_interface;
3654   terminal->clear_frame_hook = ns_clear_frame;
3655   terminal->ins_del_lines_hook = 0; /* 23: vestigial? */
3656   terminal->delete_glyphs_hook = 0; /* 23: vestigial? */
3657   terminal->ring_bell_hook = ns_ring_bell;
3658   terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
3659   terminal->set_terminal_modes_hook = ns_set_terminal_modes;
3660   terminal->update_begin_hook = ns_update_begin;
3661   terminal->update_end_hook = ns_update_end;
3662   terminal->set_terminal_window_hook = NULL; /* 23: vestigial? */
3663   terminal->read_socket_hook = ns_read_socket;
3664   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
3665   terminal->mouse_position_hook = ns_mouse_position;
3666   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
3667   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
3669   terminal->fullscreen_hook = 0; /*XTfullscreen_hook;//23.50 */
3671   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
3672   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
3673   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
3674   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
3676   terminal->delete_frame_hook = x_destroy_window;
3677   terminal->delete_terminal_hook = ns_delete_terminal;
3679   terminal->scroll_region_ok = 1;
3680   terminal->char_ins_del_ok = 1;
3681   terminal->line_ins_del_ok = 1;
3682   terminal->fast_clear_end_of_line = 1;
3683   terminal->memory_below_frame = 0;
3685   return terminal;
3689 void
3690 ns_initialize ()
3691 /* --------------------------------------------------------------------------
3692    Mainly vestigial under NS now that ns_create_terminal () does most things.
3693    -------------------------------------------------------------------------- */
3695   baud_rate = 38400;
3696   Fset_input_interrupt_mode (Qt);
3700 struct ns_display_info *
3701 ns_term_init (Lisp_Object display_name)
3702 /* --------------------------------------------------------------------------
3703      Start the Application and get things rolling.
3704    -------------------------------------------------------------------------- */
3706   extern Lisp_Object Fset_input_mode (Lisp_Object, Lisp_Object,
3707                                      Lisp_Object, Lisp_Object);
3708   struct terminal *terminal;
3709   struct ns_display_info *dpyinfo;
3710   static int ns_initialized = 0;
3711   Lisp_Object tmp;
3713   NSTRACE (ns_term_init);
3715   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
3716   /*GSDebugAllocationActive (YES); */
3717   BLOCK_INPUT;
3718 handling_signal = 0;
3720   if (!ns_initialized)
3721     {
3722       ns_initialize ();
3723       ns_initialized = 1;
3724     }
3726   ns_pending_files = [[NSMutableArray alloc] init];
3727   ns_pending_service_names = [[NSMutableArray alloc] init];
3728   ns_pending_service_args = [[NSMutableArray alloc] init];
3730   /* Start app and create the main menu, window, view.
3731      Needs to be here because ns_initialize_display_info () uses AppKit classes.
3732      The view will then ask the NSApp to stop and return to Emacs. */
3733   [EmacsApp sharedApplication];
3734   if (NSApp == nil)
3735     return NULL;
3736   [NSApp setDelegate: NSApp];
3738   /* debugging: log all notifications */
3739   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
3740                                          selector: @selector (logNotification:)
3741                                              name: nil object: nil]; */
3743   dpyinfo = (struct ns_display_info *)xmalloc (sizeof (struct ns_display_info));
3744   bzero (dpyinfo, sizeof (struct ns_display_info));
3746   ns_initialize_display_info (dpyinfo);
3747   terminal = ns_create_terminal (dpyinfo);
3749   terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
3750   init_kboard (terminal->kboard);
3751   terminal->kboard->Vwindow_system = Qns;
3752   terminal->kboard->next_kboard = all_kboards;
3753   all_kboards = terminal->kboard;
3754   /* Don't let the initial kboard remain current longer than necessary.
3755      That would cause problems if a file loaded on startup tries to
3756      prompt in the mini-buffer.  */
3757   if (current_kboard == initial_kboard)
3758     current_kboard = terminal->kboard;
3759   terminal->kboard->reference_count++;
3761   dpyinfo->next = ns_display_list;
3762   ns_display_list = dpyinfo;
3764   /* Put it on ns_display_name_list */
3765   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
3766                                 ns_display_name_list);
3767 /*      ns_display_name_list = Fcons (Fcons (display_name,
3768                                            Fcons (Qnil, dpyinfo->xrdb)),
3769                                     ns_display_name_list); */
3770   dpyinfo->name_list_element = XCAR (ns_display_name_list);
3772   /* Set the name of the terminal. */
3773   terminal->name = (char *) xmalloc (SBYTES (display_name) + 1);
3774   strncpy (terminal->name, SDATA (display_name), SBYTES (display_name));
3775   terminal->name[SBYTES (display_name)] = 0;
3777   UNBLOCK_INPUT; 
3779   /* Read various user defaults. */
3780   ns_set_default_prefs ();
3781   ns_default ("AlternateModifier", &ns_alternate_modifier,
3782              Qnil, Qnil, NO, YES);
3783   if (NILP (ns_alternate_modifier))
3784     ns_alternate_modifier = Qmeta;
3785   ns_default ("CommandModifier", &ns_command_modifier,
3786              Qnil, Qnil, NO, YES);
3787   if (NILP (ns_command_modifier))
3788     ns_command_modifier = Qsuper;
3789   ns_default ("ControlModifier", &ns_control_modifier,
3790              Qnil, Qnil, NO, YES);
3791   if (NILP (ns_control_modifier))
3792     ns_control_modifier = Qcontrol;
3793   ns_default ("FunctionModifier", &ns_function_modifier,
3794              Qnil, Qnil, NO, YES);
3795   if (NILP (ns_function_modifier))
3796     ns_function_modifier = Qnone;
3797   ns_default ("CursorBlinkRate", &ns_cursor_blink_rate,
3798              make_float (0.5), Qnil, YES, NO);
3799   if (NUMBERP (ns_cursor_blink_rate))
3800     ns_cursor_blink_mode = Qt;
3801   ns_default ("ExpandSpace", &ns_expand_space,
3802              make_float (0.5), make_float (0.0), YES, NO);
3803   ns_default ("GSFontAntiAlias", &ns_antialias_text,
3804              YES, NO, NO, NO);
3805   tmp = Qnil;
3806   ns_default ("AppleAntiAliasingThreshold", &tmp,
3807              make_float (10.0), make_float (6.0), YES, NO);
3808   ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
3809   ns_default ("UseQuickdrawSmoothing", &ns_use_qd_smoothing,
3810              YES, NO, NO, NO);
3811   ns_default ("UseSystemHighlightColor", &ns_use_system_highlight_color,
3812              YES, NO, NO, NO);
3813   if (ns_use_system_highlight_color == YES)
3814     {
3815       ns_selection_color = [[NSUserDefaults standardUserDefaults]
3816                                stringForKey: @"AppleHighlightColor"];
3817       if (ns_selection_color == nil)
3818         ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
3819     }
3820   else
3821     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
3823   {
3824     id cl;
3825     Lisp_Object tem, tem1;
3826     extern Lisp_Object Vsource_directory;
3828     cl = [NSColorList colorListNamed: @"Emacs"];
3830     if ( cl == nil )
3831       {
3832         /* first try data_dir, then invocation-dir
3833            and finally source-directory/etc */
3834         tem1 = tem =
3835           Fexpand_file_name (build_string ("Emacs.clr"), Vdata_directory);
3836         if (NILP (Ffile_exists_p (tem)))
3837           {
3838             tem = Fexpand_file_name (build_string ("Emacs.clr"),
3839                                      Vinvocation_directory);
3840             if (NILP (Ffile_exists_p (tem)))
3841               {
3842                 Lisp_Object newdir =
3843                   Fexpand_file_name (build_string ("etc/"),
3844                                      Vsource_directory);
3845                 tem = Fexpand_file_name (build_string ("Emacs.clr"),
3846                                          newdir);
3847               }
3848           }
3850         cl = [[NSColorList alloc]
3851                initWithName: @"Emacs"
3852                    fromFile: [NSString stringWithCString: XSTRING (tem)->data]];
3853         if (cl ==nil)
3854           fatal ("Could not find %s.\n", XSTRING (tem1)->data);
3855         [cl writeToFile: nil];
3856       }
3857   }
3859   {
3860     char c[128];
3861 #ifdef NS_IMPL_GNUSTEP
3862     strncpy (c, gnustep_base_version, sizeof (c));
3863 #else
3864     /*PSnextrelease (128, c); */
3865     snprintf (c, sizeof (c), "%g", NSAppKitVersionNumber);
3866 #endif
3867     Vwindow_system_version = build_string (c);
3868   }
3870   delete_keyboard_wait_descriptor (0);
3872 /* Set up OS X app menu */
3873 #ifdef NS_IMPL_COCOA
3874   {
3875     NSMenu *appMenu;
3876     id<NSMenuItem> item;
3877     /* set up the application menu */
3878     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
3879     [svcsMenu setAutoenablesItems: NO];
3880     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
3881     [appMenu setAutoenablesItems: NO];
3882     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
3884     [appMenu insertItemWithTitle: @"About Emacs"
3885                           action: @selector (orderFrontStandardAboutPanel:)
3886                    keyEquivalent: @""
3887                          atIndex: 0];
3888     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
3889     [appMenu insertItemWithTitle: @"Preferences..."
3890                           action: @selector (showPreferencesWindow:)
3891                    keyEquivalent: @","
3892                          atIndex: 2];
3893     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
3894     item = [appMenu insertItemWithTitle: @"Services"
3895                                  action: @selector (menuDown:)
3896                           keyEquivalent: @""
3897                                 atIndex: 4];
3898     [appMenu setSubmenu: svcsMenu forItem: item];
3899 /*    [svcsMenu setSupercell: item]; */
3900     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
3901     [appMenu insertItemWithTitle: @"Hide Emacs"
3902                           action: @selector (hide:)
3903                    keyEquivalent: @"h"
3904                          atIndex: 6];
3905     item =  [appMenu insertItemWithTitle: @"Hide Others"
3906                           action: @selector (hideOtherApplications:)
3907                    keyEquivalent: @"h"
3908                          atIndex: 7];
3909     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
3910     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
3911     [appMenu insertItemWithTitle: @"Quit Emacs"
3912                           action: @selector (terminate:)
3913                    keyEquivalent: @"q"
3914                          atIndex: 9];
3916     item = [mainMenu insertItemWithTitle: @"Emacs"
3917                                   action: @selector (menuDown:)
3918                            keyEquivalent: @""
3919                                  atIndex: 0];
3920     [mainMenu setSubmenu: appMenu forItem: item];
3922     [NSApp setMainMenu: mainMenu];
3923     [NSApp setAppleMenu: appMenu];
3924     [NSApp setServicesMenu: svcsMenu];
3925     /* Needed at least on Cocoa, to get dock menu to show windows */
3926     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
3927   }
3928 #endif /* MAC OS X menu setup */
3930   [NSApp run];
3932   return dpyinfo;
3936 extern Lisp_Object Vauto_save_list_file_name;
3937 void
3938 ns_term_shutdown (int sig)
3940   /* code not reached in emacs.c after this is called by shut_down_emacs: */
3941   if (STRINGP (Vauto_save_list_file_name))
3942     unlink (XSTRING (Vauto_save_list_file_name)->data);
3944   ns_shutdown_properly = YES;
3945   [NSApp terminate: NSApp];
3949 void
3950 syms_of_nsterm ()
3952   NSTRACE (syms_of_nsterm);
3953   DEFVAR_LISP ("ns-input-file", &ns_input_file,
3954               "The file specified in the last NS event.");
3955   ns_input_file =Qnil;
3957   DEFVAR_LISP ("ns-input-text", &ns_input_text,
3958               "The data received in the last NS text drag event.");
3959   ns_input_text =Qnil;
3961   DEFVAR_LISP ("ns-working-text", &ns_working_text,
3962               "String for visualizing working composition sequence.");
3963   ns_working_text =Qnil;
3965   DEFVAR_LISP ("ns-input-font", &ns_input_font,
3966               "The font specified in the last NS event.");
3967   ns_input_font =Qnil;
3969   DEFVAR_LISP ("ns-input-fontsize", &ns_input_fontsize,
3970               "The fontsize specified in the last NS event.");
3971   ns_input_fontsize =Qnil;
3973   DEFVAR_LISP ("ns-input-line", &ns_input_line,
3974                "The line specified in the last NS event.");
3975   ns_input_line =Qnil;
3977   DEFVAR_LISP ("ns-input-color", &ns_input_color,
3978                "The color specified in the last NS event.");
3979   ns_input_color =Qnil;
3981   DEFVAR_LISP ("ns-input-spi-name", &ns_input_spi_name,
3982                "The service name specified in the last NS event.");
3983   ns_input_spi_name =Qnil;
3985   DEFVAR_LISP ("ns-input-spi-arg", &ns_input_spi_arg,
3986                "The service argument specified in the last NS event.");
3987   ns_input_spi_arg =Qnil;
3989   DEFVAR_LISP ("ns-alternate-modifier", &ns_alternate_modifier,
3990                "This variable describes the behavior of the alternate or option key.\n\
3991 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
3992 Set to none means that the alternate / option key is not interpreted by Emacs\n\
3993 at all, allowing it to be used at a lower level for accented character entry.");
3995   DEFVAR_LISP ("ns-command-modifier", &ns_command_modifier,
3996                "This variable describes the behavior of the command key.\n\
3997 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
3999   DEFVAR_LISP ("ns-control-modifier", &ns_control_modifier,
4000                "This variable describes the behavior of the control key.\n\
4001 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
4003   DEFVAR_LISP ("ns-function-modifier", &ns_function_modifier,
4004                "This variable describes the behavior of the function key (on laptops).\n\
4005 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
4006 Set to none means that the function key is not interpreted by Emacs at all,\n\
4007 allowing it to be used at a lower level for accented character entry.");
4009   DEFVAR_LISP ("ns-cursor-blink-rate", &ns_cursor_blink_rate,
4010                "Rate at which the Emacs cursor blinks (in seconds).\n\
4011 Set to nil to disable blinking.");
4013   DEFVAR_LISP ("ns-cursor-blink-mode", &ns_cursor_blink_mode,
4014                "Internal variable -- use M-x blink-cursor-mode or preferences\n\
4015 panel to control this setting.");
4017   DEFVAR_LISP ("ns-expand-space", &ns_expand_space,
4018                "Amount by which spacing between lines is expanded (positive)\n\
4019 or shrunk (negative).  Zero (the default) means standard line height.\n\
4020 (This variable should only be read, never set.)");
4022   DEFVAR_BOOL ("ns-antialias-text", &ns_antialias_text,
4023                "Non-nil (the default) means to render text antialiased. Only has an effect on OS X Panther and above.");
4025   DEFVAR_BOOL ("ns-use-qd-smoothing", &ns_use_qd_smoothing,
4026                "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).");
4028   DEFVAR_BOOL ("ns-use-system-highlight-color",
4029                &ns_use_system_highlight_color,
4030                "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'.");
4032   staticpro (&ns_display_name_list);
4033   ns_display_name_list = Qnil;
4035   staticpro (&last_mouse_motion_frame);
4036   last_mouse_motion_frame = Qnil;
4038 /*23: now apparently we need to tell emacs what modifiers there are.. */
4039   Qmodifier_value = intern ("modifier-value");
4040   Qalt = intern ("alt");
4041   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
4042   Qhyper = intern ("hyper");
4043   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
4044   Qmeta = intern ("meta");
4045   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
4046   Qsuper = intern ("super");
4047   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
4048   Qcontrol = intern ("control");
4049   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
4051   /*PENDING: move to common code */
4052   DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
4053                doc: /* If not nil, Emacs uses toolkit scroll bars.  */);
4054 #ifdef USE_TOOLKIT_SCROLL_BARS
4055   Vx_toolkit_scroll_bars = Qt; 
4056 #else
4057   Vx_toolkit_scroll_bars = Qnil;
4058 #endif
4060   /* these are unsupported but we need the declarations to avoid whining
4061      messages from cus-start.el */
4062   DEFVAR_BOOL ("x-use-underline-position-properties",
4063                &x_use_underline_position_properties,
4064      doc: /* NOT SUPPORTED UNDER NS.
4065 *Non-nil means make use of UNDERLINE_POSITION font properties.
4066 A value of nil means ignore them.  If you encounter fonts with bogus
4067 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
4068 to 4.1, set this to nil.
4070 NOTE: Not supported on Mac yet.  */);
4071   x_use_underline_position_properties = 0;
4073   DEFVAR_BOOL ("x-underline-at-descent-line",
4074                &x_underline_at_descent_line,
4075      doc: /* NOT SUPPORTED UNDER NS.
4076 *Non-nil means to draw the underline at the same place as the descent line.
4077 A value of nil means to draw the underline according to the value of the
4078 variable `x-use-underline-position-properties', which is usually at the
4079 baseline level.  The default value is nil.  */);
4080   x_underline_at_descent_line = 0;
4082   /* Tell emacs about this window system. */
4083   Fprovide (intern ("ns-windowing"), Qnil);
4084   /* PENDING: try to move this back into lisp (ns-win.el loaded too late
4085               right now */
4086   {
4087     Lisp_Object args[3] = { intern ("ns-version-string"), build_string ("9.0"),
4088                     build_string ("NS Window system port version number.") };
4089     Fdefconst (Flist (3, args));
4090   }
4095 /* ==========================================================================
4097     EmacsApp implementation
4099    ========================================================================== */
4102 @implementation EmacsApp
4104 - (void)logNotification: (NSNotification *)notification
4106   const char *name = [[notification name] UTF8String];
4107   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4108       && !strstr (name, "WindowNumber"))
4109     NSLog (@"notification: '%@'", [notification name]);
4113 - (void)sendEvent: (NSEvent *)theEvent
4114 /* --------------------------------------------------------------------------
4115      Events posted by ns_send_appdefined interrupt the run loop here
4116    -------------------------------------------------------------------------- */
4118   int type = [theEvent type];
4119   NSWindow *window = [theEvent window];
4120 /*  NSTRACE (sendEvent); */
4121 /*fprintf (stderr, "received event of type %d\n", [theEvent type]); */
4123   if (type == NSCursorUpdate && window == nil)
4124     {
4125       fprintf (stderr, "Dropping external cursor update event.\n");
4126       return;
4127     }
4129 #ifdef NS_IMPL_COCOA
4130   /* pass mouse down in resize handle and subsequent drags directly to
4131      EmacsWindow so we can generate continuous redisplays */
4132   if (ns_in_resize)
4133     {
4134       if (type == NSLeftMouseDragged)
4135         {
4136           [window mouseDragged: theEvent];
4137           return;
4138         }
4139       else if (type == NSLeftMouseUp)
4140         {
4141           [window mouseUp: theEvent];
4142           return;
4143         }
4144     }
4145   else if (type == NSLeftMouseDown)
4146     {
4147       NSRect r = ns_resize_handle_rect (window);
4148       if (NSPointInRect ([theEvent locationInWindow], r))
4149         {
4150           ns_in_resize = YES;
4151           [window mouseDown: theEvent];
4152           return;
4153         }
4154     }
4155 #endif
4157   if (type == NSApplicationDefined)
4158     {
4159       last_appdefined_event = theEvent;
4160       [self stop: self];
4161     }
4163   [super sendEvent: theEvent];
4167 - (void)showPreferencesWindow: (id)sender
4169   if (prefsController == nil)
4170     prefsController = [[EmacsPrefsController alloc] init];
4171   [prefsController showForFrame: SELECTED_FRAME ()];
4175 /* **************************************************************************
4177       EmacsApp delegate implementation
4179    ************************************************************************** */
4181 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4182 /* --------------------------------------------------------------------------
4183      When application is loaded, terminate event loop in ns_term_init
4184    -------------------------------------------------------------------------- */
4186   NSTRACE (applicationDidFinishLaunching);
4187   [NSApp setServicesProvider: NSApp];
4188   ns_send_appdefined (-2);
4192 - (void) terminate: (id)sender
4194   BLOCK_INPUT;
4195   if (ns_shutdown_properly)
4196     [super terminate: sender];
4197   else
4198     {
4199 /*    Fkill_emacs (Qnil); */
4200       ns_shutdown_properly = YES;
4201       Feval (Fcons (intern ("save-buffers-kill-emacs"), Qnil));
4202     }
4203   UNBLOCK_INPUT;
4207 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4209   if (ns_shutdown_properly)
4210     return NSTerminateNow;
4212   Lisp_Object contents = list3 (build_string ("Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?"),
4213       Fcons (build_string ("Cancel"), Qnil),
4214       Fcons (build_string ("Save and Exit"), Qt));
4215   Lisp_Object res = ns_popup_dialog (Qt, contents, Qnil);
4216 fprintf (stderr, "res = %d\n", res ==Qt);
4217   if (res == Qt)
4218     {
4219       Feval (Fcons (intern ("save-buffers-kill-emacs"), Qnil));
4220       return NSTerminateNow;
4221     }
4222   return NSTerminateCancel;
4226 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4227 -(BOOL) openFile: (NSString *)fileName
4229   struct frame *emacsframe = SELECTED_FRAME ();
4230   NSEvent *theEvent = [NSApp currentEvent];
4232   if (!emacs_event)
4233     return NO;
4235   emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4236   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4237   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4238   ns_input_line = Qnil; /* can be start or cons start,end */
4239   emacs_event->modifiers =0;
4240   EV_TRAILER (theEvent);
4242   return YES;
4246 /*   Notification from the Workspace to open a file */
4247 - (BOOL)application: sender openFile: (NSString *)file
4249   [ns_pending_files addObject: file];
4250   return YES;
4254 /*   Open a file as a temporary file */
4255 - (BOOL)application: sender openTempFile: (NSString *)file
4257   [ns_pending_files addObject: file];
4258   return YES;
4262 /*   Notification from the Workspace to open a file noninteractively (?) */
4263 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4265   [ns_pending_files addObject: file];
4266   return YES;
4270 /*   Notification from the Workspace to open multiple files */
4271 - (void)application: sender openFiles: (NSArray *)fileList
4273   NSEnumerator *files = [fileList objectEnumerator];
4274   NSString *file;
4275   while ((file = [files nextObject]) != nil)
4276     [ns_pending_files addObject: file];
4277   return YES;
4280 /*PENDING: these may help w/IO switching btwn terminal and NSApp */
4281 - (void)applicationDidBecomeActive: (NSNotification *)notification
4284 - (void)applicationDidResignActive: (NSNotification *)notification
4286   ns_send_appdefined (-1);
4291 /* ==========================================================================
4293     EmacsApp aux handlers for managing event loop
4295    ========================================================================== */
4298 - (void)timeout_handler: (NSTimer *)timedEntry
4299 /* --------------------------------------------------------------------------
4300      The timeout specified to ns_select has passed.
4301    -------------------------------------------------------------------------- */
4303   /*NSTRACE (timeout_handler); */
4304   ns_send_appdefined (-2);
4307 extern void update_window_cursor (struct window *w, int on);
4309 - (void)cursor_blink_handler: (NSTimer *)cursorEntry
4310 /* --------------------------------------------------------------------------
4311      Flash the cursor
4312    -------------------------------------------------------------------------- */
4314   struct ns_display_info *dpyinfo = ns_display_list; /*HACK, but OK for now */
4315   struct frame *f = dpyinfo->ns_highlight_frame;
4316   NSTRACE (cursor_blink_handler);
4318   if (!f)
4319     return;
4320   if (f->output_data.ns->current_cursor == no_highlight)
4321     {
4322       Lisp_Object tem = get_frame_param (f, Qcursor_type);
4323       f->output_data.ns->desired_cursor = ns_lisp_to_cursor_type (tem);
4324     }
4325   else
4326     {
4327       f->output_data.ns->desired_cursor = no_highlight;
4328     }
4329   update_window_cursor (XWINDOW (FRAME_SELECTED_WINDOW (f)), 1);
4330   /*x_update_cursor (f, 1); */
4334 - (void)fd_handler: (NSTimer *) fdEntry
4335 /* --------------------------------------------------------------------------
4336      Check data waiting on file descriptors and terminate if so
4337    -------------------------------------------------------------------------- */
4339   int result;
4340   /* NSTRACE (fd_handler); */
4342   if (select_nfds == 0)
4343     return;
4345   memcpy (&t_readfds, &select_readfds, sizeof (fd_set));
4347   select_timeout.tv_sec = select_timeout.tv_usec = 0;
4348   result = select (select_nfds, &t_readfds, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
4349                   &select_timeout);
4350   if (result)
4351     {
4352       memcpy (&select_readfds, &t_readfds, sizeof (fd_set));
4353       ns_send_appdefined (result);
4354     }
4359 /* ==========================================================================
4361     Service provision
4363    ========================================================================== */
4365 /* called from system: queue for next pass through event loop */
4366 - (void)requestService: (NSPasteboard *)pboard
4367               userData: (NSString *)userData
4368                  error: (NSString **)error
4370   [ns_pending_service_names addObject: userData];
4371   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4372       SDATA (ns_string_from_pasteboard (pboard))]];
4376 /* called from ns_read_socket to clear queue */
4377 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4379   struct frame *emacsframe = SELECTED_FRAME ();
4380   NSEvent *theEvent = [NSApp currentEvent];
4382   if (!emacs_event)
4383     return NO;
4385   emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4386   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4387   ns_input_spi_name = build_string ([name UTF8String]);
4388   ns_input_spi_arg = build_string ([arg UTF8String]);
4389   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4390   EV_TRAILER (theEvent);
4392   return YES;
4396 @end  /* EmacsApp */
4400 /* ==========================================================================
4402     EmacsView implementation
4404    ========================================================================== */
4407 @implementation EmacsView
4409 /* needed to inform when window closed from LISP */
4410 - (void) setWindowClosing: (BOOL)closing
4412   windowClosing = closing;
4416 - (void)dealloc
4418   NSTRACE (EmacsView_dealloc);
4419   [toolbar release];
4420   [super dealloc];
4424 /* called on font panel selection */
4425 - (void)changeFont: (id)sender
4427   NSEvent *e =[[self window] currentEvent];
4428   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4429   id newFont;
4430   float size;
4432   NSTRACE (changeFont);
4433   if (!emacs_event)
4434     return;
4436   if (newFont = [sender convertFont:
4437                            ((struct nsfont_info *)face->font)->nsfont])
4438     {
4439       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4440       emacs_event->modifiers = 0;
4441       emacs_event->code = KEY_NS_CHANGE_FONT;
4443       size = [newFont pointSize];
4444       /* PENDING: stick w/integer sizes for now. */
4445 /*        if (size == lrint (size)) */
4446         ns_input_fontsize = make_number (lrint (size));
4447 /*          else
4448             ns_input_fontsize = make_float (size); */
4449       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4450       EV_TRAILER (e);
4451     }
4455 - (BOOL)acceptsFirstResponder
4457   NSTRACE (acceptsFirstResponder);
4458   return YES;
4462 - (void)resetCursorRects
4464   NSRect visible = [self visibleRect];
4465   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4466   NSTRACE (resetCursorRects);
4468   if (currentCursor == nil)
4469     currentCursor = [NSCursor arrowCursor];
4471   if (!NSIsEmptyRect (visible))
4472     [self addCursorRect: visible cursor: currentCursor];
4473   [currentCursor setOnMouseEntered: YES];
4477 /*****************************************************************************/
4478 /* Keyboard handling. */
4479 #define NS_KEYLOG 0
4481 - (void)keyDown: (NSEvent *)theEvent
4483   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
4484   int code;
4485   unsigned fnKeysym = 0;
4486   int flags;
4487   static NSMutableArray *nsEvArray;
4488   static BOOL firstTime = YES;
4490   NSTRACE (keyDown);
4492   /* Rhapsody and OS X give up and down events for the arrow keys */
4493   if ([theEvent type] != NSKeyDown)
4494     return;
4496   if (!emacs_event)
4497     return;
4499 /*#if defined (COCOA_EXPERIMENTAL_CTRL_G) */
4500  if (![[self window] isKeyWindow])
4501    {
4502      /* PENDING: Using NO_SOCK_SIGIO like Carbon causes a condition in which,
4503         when Emacs display updates a different frame from the current one,
4504         and temporarily selects it, then processes some interrupt-driven
4505         input (dispnew.c:3878), OS will send the event to the correct NSWindow,
4506         but for some reason that window has its first responder set to the
4507         NSView most recently updated (I guess), which is not the correct one.
4508         UPDATE: After multi-TTY merge this happens even w/o NO_SOCK_SIGIO */
4509      if ([[theEvent window] isKindOfClass: [EmacsWindow class]])
4510          [[(EmacsView *)[theEvent window] delegate] keyDown: theEvent];
4511      return;
4512    }
4513 /*#endif */
4515   if (nsEvArray == nil)
4516     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4518   [NSCursor setHiddenUntilMouseMoves: YES];
4520   if (dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4521     {
4522       clear_mouse_face (dpyinfo);
4523       dpyinfo->mouse_face_hidden = 1;
4524     }
4526   if (!processingCompose)
4527     {
4528       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4529         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4530       /* (Carbon way: [theEvent keyCode]) */
4532       /* is it a "function key"? */
4533       fnKeysym = ns_convert_key (code);
4534       if (fnKeysym)
4535         {
4536           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4537              because Emacs treats Delete and KP-Delete same (in simple.el). */
4538           if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4539             code = 0xFF08; /* backspace */
4540           else
4541             code = fnKeysym;
4542         }
4544       /* are there modifiers? */
4545       emacs_event->modifiers = 0;
4546       flags = [theEvent modifierFlags];
4548       if (flags & NSHelpKeyMask)
4549           emacs_event->modifiers |= hyper_modifier;
4551       if (flags & NSShiftKeyMask)
4552         emacs_event->modifiers |= shift_modifier;
4554       if (flags & NSCommandKeyMask)
4555         {
4556           emacs_event->modifiers |= lisp_to_mod (ns_command_modifier);
4557           /* if super (default), take input manager's word so things like
4558              dvorak / qwerty layout work */
4559           if (EQ (ns_command_modifier, Qsuper)
4560               && !fnKeysym
4561               && [[theEvent characters] length] != 0)
4562             {
4563               /* PENDING: the code we get will be unshifted, so if we have
4564                  a shift modifier, must convert ourselves */
4565               if (!(flags & NSShiftKeyMask))
4566                 code = [[theEvent characters] characterAtIndex: 0];
4567 #if 0
4568               /* this is ugly and also requires linking w/Carbon framework
4569                  (for LMGetKbdType) so for now leave this rare (?) case
4570                  undealt with.. in future look into CGEvent methods */
4571               else
4572                 {
4573                   long smv = GetScriptManagerVariable (smKeyScript);
4574                   Handle uchrHandle = GetResource
4575                     ('uchr', GetScriptVariable (smv, smScriptKeys));
4576                   UInt32 dummy = 0;
4577                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
4578                                  [[theEvent characters] characterAtIndex: 0],
4579                                  kUCKeyActionDisplay,
4580                                  (flags & ~NSCommandKeyMask) >> 8,
4581                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
4582                                  &dummy, 1, &dummy, &code);
4583                   code &= 0xFF;
4584                 }
4585 #endif
4586             }
4587         }
4589       if (flags & NSControlKeyMask)
4590           emacs_event->modifiers |= lisp_to_mod (ns_control_modifier);
4592       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
4593           emacs_event->modifiers |= lisp_to_mod (ns_function_modifier);
4595       if (flags & NSAlternateKeyMask) /* default = meta */
4596         {
4597           if (EQ (ns_alternate_modifier, Qnone) && !fnKeysym)
4598             {   /* accept pre-interp alt comb */
4599               if ([[theEvent characters] length] > 0)
4600                 code = [[theEvent characters] characterAtIndex: 0];
4601               /*HACK: clear lone shift modifier to stop next if from firing */
4602               if (emacs_event->modifiers == shift_modifier)
4603                 emacs_event->modifiers = 0;
4604             }
4605           else
4606               emacs_event->modifiers |= lisp_to_mod (ns_alternate_modifier);
4607         }
4609 /*fprintf (stderr,"code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",code,fnKeysym,flags,emacs_event->modifiers); */
4611       /* if it was a function key or had modifiers, pass it directly to emacs */
4612       if (fnKeysym || (emacs_event->modifiers
4613                        && [[theEvent charactersIgnoringModifiers] length] > 0))
4614 /*[[theEvent characters] length] */
4615         {
4616           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4617           if (code < 0x20)
4618             code |= (1<<28)|(3<<16);
4619           else if (code == 0x7f)
4620             code |= (1<<28)|(3<<16);
4621           else if (!fnKeysym)
4622             emacs_event->kind = code > 0xFF
4623               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4625           emacs_event->code = code;
4626           EV_TRAILER (theEvent);
4627           return;
4628         }
4629     }
4631   /* if we get here we should send the key for input manager processing */
4632   if (firstTime && [[NSInputManager currentInputManager]
4633                      wantsToDelayTextChangeNotifications] == NO)
4634     fprintf (stderr,
4635           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
4636   firstTime = NO;
4638   if (NS_KEYLOG && !processingCompose)
4639     fprintf (stderr, "Begin compose sequence.\n");
4641   processingCompose = YES;
4642   [nsEvArray addObject: theEvent];
4643   [self interpretKeyEvents: nsEvArray];
4644   [nsEvArray removeObject: theEvent];
4648 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
4651 /* <NSTextInput>: called through when done composing */
4652 - (void)insertText: (id)aString
4654   int code;
4655   int len = [(NSString *)aString length];
4656   int i;
4658 if (NS_KEYLOG) NSLog (@"insertText '%@'\tlen = %d", aString, len);
4659   processingCompose = NO;
4661   if (!emacs_event)
4662     return;
4664   /* first, clear any working text */
4665   if (workingText != nil)
4666     [self deleteWorkingText];
4668   /* now insert the string as keystrokes */
4669   for (i =0; i<len; i++)
4670     {
4671       code = [aString characterAtIndex: i];
4672       /* PENDING: still need this? */
4673       if (code == 0x2DC)
4674         code = '~'; /* 0x7E */
4675       emacs_event->modifiers = 0;
4676       emacs_event->kind =
4677         code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4678       emacs_event->code = code;
4679       EV_TRAILER ((id)nil);
4680     }
4684 /* <NSTextInput>: inserts display of composing characters */
4685 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
4687   NSString *str = [aString respondsToSelector: @selector (string)] ?
4688     [aString string] : aString;
4689   if (NS_KEYLOG)
4690     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
4691            selRange.length, selRange.location);
4693   if (workingText != nil)
4694     [self deleteWorkingText];
4695   if ([str length] == 0)
4696     return;
4698   if (!emacs_event)
4699     return;
4701   processingCompose = YES;
4702   workingText = [str copy];
4703   ns_working_text = build_string ([workingText UTF8String]);
4705   /* if in "echo area", not true minibuffer, can't show chars in interactive
4706      mode, so call using eval; otherwise we send a key event, which was the
4707      original way this was done */
4708   if (!EQ (Feval (Fcons (intern ("ns-in-echo-area"), Qnil)), Qnil))
4709     {
4710       Feval (Fcons (intern ("ns-echo-working-text"), Qnil));
4711       ns_send_appdefined (-1);
4712     }
4713   else
4714     {
4715       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4716       emacs_event->code = KEY_NS_INSERT_WORKING_TEXT;
4717       EV_TRAILER ((id)nil);
4718     }
4722 /* delete display of composing characters [not in <NSTextInput>] */
4723 - (void)deleteWorkingText
4725   if (workingText == nil)
4726     return;
4727   if (NS_KEYLOG)
4728     fprintf (stderr, "deleteWorkingText len =%d\n", [workingText length]);
4729   [workingText release];
4730   workingText = nil;
4731   processingCompose = NO;
4733   if (!emacs_event)
4734     return;
4736   if (!EQ (Feval (Fcons (intern ("ns-in-echo-area"), Qnil)), Qnil))
4737     {
4738       Feval (Fcons (intern ("ns-unecho-working-text"), Qnil));
4739       ns_send_appdefined (-1);
4740     }
4741   else
4742     {
4743       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4744       emacs_event->code = KEY_NS_DELETE_WORKING_TEXT;
4745       EV_TRAILER ((id)nil);
4746     }
4750 - (BOOL)hasMarkedText
4752   return workingText != nil;
4755 - (NSRange)markedRange
4757   NSRange rng = workingText != nil
4758     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
4759 if (NS_KEYLOG) NSLog (@"markedRange request");
4760   return rng;
4763 - (void)unmarkText
4765 if (NS_KEYLOG) NSLog (@"unmark (accept) text");
4766   [self deleteWorkingText];
4767   processingCompose = NO;
4770 /* used to position char selection windows, etc. */
4771 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
4773   NSRect rect;
4774   NSPoint pt;
4775   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
4776 if (NS_KEYLOG) NSLog (@"firstRectForCharRange request");
4778   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
4779   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
4780   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
4781   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
4782                                        +FRAME_LINE_HEIGHT (emacsframe));
4784   pt = [self convertPoint: pt toView: nil];
4785   pt = [[self window] convertBaseToScreen: pt];
4786   rect.origin = pt;
4787   return rect;
4790 - (long)conversationIdentifier
4792   return (long)self;
4795 /*PENDING: below here not yet implemented correctly, but may not be needed */
4797 - (void)doCommandBySelector: (SEL)aSelector
4799   if (NS_KEYLOG) NSLog (@"Do command by selector: %@",
4800                        NSStringFromSelector (aSelector));
4802   if (aSelector == @selector (deleteBackward:))
4803     {
4804       /* happens when user backspaces over an ongoing composition:
4805          throw a 'delete' into the event queue */
4806       if (!emacs_event)
4807         return;
4808       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4809       emacs_event->code = 0xFF08;
4810       EV_TRAILER ((id)nil);
4811     }
4814 - (NSArray *)validAttributesForMarkedText
4816   static NSArray *arr = nil;
4817   if (arr == nil) arr = [NSArray new];
4818  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
4819   return arr;
4822 - (NSRange)selectedRange
4824 if (NS_KEYLOG) NSLog (@"selectedRange request");
4825   return NSMakeRange (NSNotFound, 0);
4828 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
4830 if (NS_KEYLOG) NSLog (@"characterIndexForPoint request");
4831   return 0;
4834 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
4836   static NSAttributedString *str = nil;
4837   if (str == nil) str = [NSAttributedString new];
4838 if (NS_KEYLOG) NSLog (@"attributedSubstringFromRange request");
4839   return str;
4842 /* End <NSTextInput> impl. */
4843 /*****************************************************************************/
4846 /* This is what happens when the user presses a mouse button.  */
4847 - (void)mouseDown: (NSEvent *)theEvent
4849   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
4850   Lisp_Object window;
4852   NSTRACE (mouseDown);
4854   [self deleteWorkingText];
4856   if (!emacs_event)
4857     return;
4859   last_mouse_frame = emacsframe;
4860   /* appears to be needed to prevent spurious movement events generated on
4861      button clicks */
4862   last_mouse_frame->mouse_moved = 0;
4864   if ([theEvent type] == NSScrollWheel)
4865     {
4866       float delta = [theEvent deltaY];
4867       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
4868       if (delta == 0)
4869         return;
4870       emacs_event->kind = WHEEL_EVENT;
4871       emacs_event->code = 0;
4872       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
4873         ((delta > 0) ? up_modifier : down_modifier);
4874     }
4875   else
4876     {
4877       emacs_event->kind = MOUSE_CLICK_EVENT;
4878       emacs_event->code = EV_BUTTON (theEvent);
4879       emacs_event->modifiers = EV_MODIFIERS (theEvent)
4880                              | EV_UDMODIFIERS (theEvent);
4881     }
4882   XSETINT (emacs_event->x, lrint (p.x));
4883   XSETINT (emacs_event->y, lrint (p.y));
4884   EV_TRAILER (theEvent);
4888 - (void)mouseUp: (NSEvent *)theEvent
4890   NSTRACE (mouseUp);
4891   [self mouseDown: theEvent];
4895 - (void)rightMouseDown: (NSEvent *)theEvent
4897   NSTRACE (rightMouseDown);
4898   [self mouseDown: theEvent];
4902 - (void)rightMouseUp: (NSEvent *)theEvent
4904   NSTRACE (rightMouseUp);
4905   [self mouseDown: theEvent];
4909 - (void) scrollWheel: (NSEvent *)theEvent
4911   NSTRACE (scrollWheel);
4912   [self mouseDown: theEvent];
4916 /* Tell emacs the mouse has moved. */
4917 - (void)mouseMoved: (NSEvent *)e
4919   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
4920   Lisp_Object frame;
4922   NSTRACE (mouseMoved);
4924   last_mouse_movement_time = EV_TIMESTAMP (e);
4925   last_mouse_motion_position =
4926     [self convertPoint: [e locationInWindow] fromView: nil];
4928   /* update any mouse face */
4929   if (dpyinfo->mouse_face_hidden)
4930     {
4931       dpyinfo->mouse_face_hidden = 0;
4932       clear_mouse_face (dpyinfo);
4933     }
4935   /* tooltip handling */
4936   previous_help_echo_string = help_echo_string;
4937   help_echo_string = Qnil;
4939   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
4940                             last_mouse_motion_position.y))
4941     help_echo_string = previous_help_echo_string;
4943   XSETFRAME (frame, emacsframe);
4944   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
4945     {
4946       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
4947          (note_mouse_highlight), which is called through the
4948          note_mouse_movement () call above */
4949       gen_help_event (help_echo_string, frame, help_echo_window,
4950                       help_echo_object, help_echo_pos);
4951     }
4952   else
4953     {
4954       help_echo_string = Qnil;
4955       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
4956     }
4958   if (emacsframe->mouse_moved && send_appdefined)
4959     ns_send_appdefined (-1);
4963 - (void)mouseDragged: (NSEvent *)e
4965   NSTRACE (mouseDragged);
4966   [self mouseMoved: e];
4970 - (void)rightMouseDragged: (NSEvent *)e
4972   NSTRACE (rightMouseDragged);
4973   [self mouseMoved: e];
4977 - (BOOL)windowShouldClose: (id)sender
4979   NSEvent *e =[[self window] currentEvent];
4981   NSTRACE (windowShouldClose);
4982   windowClosing = YES;
4983   if (ns_window_num <= 1)
4984     return NO;
4985   if (!emacs_event)
4986     return NO;
4987   emacs_event->kind = DELETE_WINDOW_EVENT;
4988   emacs_event->modifiers = 0;
4989   emacs_event->code = 0;
4990   EV_TRAILER (e);
4991   /* Don't close this window, let this be done from lisp code.  */
4992   return NO;
4996 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
4997 /* normalize frame to gridded text size */
4999   NSTRACE (windowWillResize);
5000 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5002   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5003 #ifdef NS_IMPL_GNUSTEP
5004                                         frameSize.width + 3);
5005 #else
5006                                         frameSize.width);
5007 #endif
5008   if (cols < MINWIDTH)
5009     cols = MINWIDTH;
5010   frameSize.width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (emacsframe, cols);
5012   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, frameSize.height
5013 #ifdef NS_IMPL_GNUSTEP
5014       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + 3
5015         - FRAME_NS_TOOLBAR_HEIGHT (emacsframe));
5016 #else
5017       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5018         - FRAME_NS_TOOLBAR_HEIGHT (emacsframe));
5019 #endif
5020   if (rows < MINHEIGHT)
5021     rows = MINHEIGHT;
5022   frameSize.height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows)
5023                        + FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5024                        + FRAME_NS_TOOLBAR_HEIGHT (emacsframe);
5025 #ifdef NS_IMPL_COCOA
5026   {
5027     /* this sets window title to have size in it; the wm does this under GS */
5028     NSRect r = [[self window] frame];
5029     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5030       {
5031         if (old_title != 0)
5032           {
5033             xfree (old_title);
5034             old_title = 0;
5035           }
5036       }
5037     else
5038       {
5039         char *size_title;
5040         NSWindow *window = [self window];
5041         if (old_title == 0)
5042           {
5043             const char *t = [[[self window] title] UTF8String];
5044             char *pos = strstr (t, "  â€”  ");
5045             if (pos)
5046               *pos = '\0';
5047             old_title = (char *) xmalloc (strlen (t) + 1);
5048             strcpy (old_title, t);
5049           }
5050         size_title = xmalloc (strlen (old_title) + 40);
5051         sprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5052         [window setTitle: [NSString stringWithUTF8String: size_title]];
5053         [window display];
5054         xfree (size_title);
5055       }
5056   }
5057 #endif /* NS_IMPL_COCOA */
5058 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5060   return frameSize;
5064 - (void)windowDidResize: (NSNotification *)notification
5066   NSWindow *theWindow = [notification object];
5068 #ifdef NS_IMPL_GNUSTEP
5069    /* in GNUstep, at least currently, it's possible to get a didResize
5070       without getting a willResize.. therefore we need to act as if we got
5071       the willResize now */
5072   NSSize sz = [theWindow frame].size;
5073   sz = [self windowWillResize: theWindow toSize: sz];
5074 #endif /* NS_IMPL_GNUSTEP */
5076   NSTRACE (windowDidResize);
5077 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5079 #ifdef NS_IMPL_COCOA
5080   if (old_title != 0)
5081     {
5082       xfree (old_title);
5083       old_title = 0;
5084     }
5085 #endif /* NS_IMPL_COCOA */
5087   if (cols > 0 && rows > 0)
5088     x_set_window_size (emacsframe, 0, cols, rows);
5090   ns_send_appdefined (-1);
5091   [NSApp stopModal];
5095 - (void)windowDidBecomeKey: (NSNotification *)notification
5097   int val = ns_lisp_to_cursor_type (get_frame_param (emacsframe, Qcursor_type));
5098   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5099   struct frame *old_focus = dpyinfo->ns_focus_frame;
5101   NSTRACE (windowDidBecomeKey);
5103   if (emacsframe != old_focus)
5104     dpyinfo->ns_focus_frame = emacsframe;
5105   /*/last_mouse_frame = emacsframe;? */
5107   if (val >= 0)
5108     {
5109       FRAME_NEW_CURSOR (emacsframe) = val;
5110 /*    x_update_cursor (emacsframe, 1); // will happen in ns_frame_rehighlight */
5111     }
5113   ns_frame_rehighlight (emacsframe);
5115   if (emacs_event)
5116     {
5117       emacs_event->kind = FOCUS_IN_EVENT;
5118       EV_TRAILER ((id)nil);
5119     }
5123 - (void)windowDidResignKey: (NSNotification *)notification
5125   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5126   NSTRACE (windowDidResignKey);
5128   if (!windowClosing && [[self window] isVisible] == YES)
5129     {
5130       FRAME_NEW_CURSOR (emacsframe) = hollow_box;
5131       x_update_cursor (emacsframe, 1);
5132       FRAME_LAST_INACTIVE (emacsframe) = YES;
5133     }
5135   if (dpyinfo->ns_highlight_frame == emacsframe)
5136     dpyinfo->ns_highlight_frame = 0;
5137   if (dpyinfo->ns_focus_frame == emacsframe)
5138     dpyinfo->ns_focus_frame = 0;
5140   if (dpyinfo->mouse_face_mouse_frame == emacsframe)
5141     {
5142       clear_mouse_face (dpyinfo);
5143       dpyinfo->mouse_face_mouse_frame = 0;
5144     }
5146   if (emacs_event)
5147     {
5148       [self deleteWorkingText];
5149       emacs_event->kind = FOCUS_IN_EVENT;
5150       EV_TRAILER ((id)nil);
5151     }
5155 - (void)windowWillMiniaturize: sender
5157   NSTRACE (windowWillMiniaturize);
5161 - (BOOL)isFlipped
5163   return YES;
5167 - (BOOL)isOpaque
5169   return NO;
5173 - initFrameFromEmacs: (struct frame *)f
5175   NSRect r, wr;
5176   Lisp_Object tem;
5177   NSWindow *win;
5178   NSButton *toggleButton;
5179   int vbextra = NS_SCROLL_BAR_WIDTH (f);
5180   NSSize sz;
5181   NSColor *col;
5182   NSString *name;
5184   NSTRACE (initFrameFromEmacs);
5186   windowClosing = NO;
5187   processingCompose = NO;
5188   scrollbarsNeedingUpdate = 0;
5190 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5192   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5193                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5194   [self initWithFrame: r];
5196   FRAME_NS_VIEW (f) = self;
5197   emacsframe = f;
5198   old_title = 0;
5200   win = [[EmacsWindow alloc]
5201             initWithContentRect: r
5202                       styleMask: (NSResizableWindowMask |
5203                                   NSMiniaturizableWindowMask |
5204                                   NSClosableWindowMask)
5205                         backing: NSBackingStoreBuffered
5206                           defer: YES];
5208   wr = [win frame];
5209   f->border_width = wr.size.width - r.size.width;
5210   FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5212   [win setAcceptsMouseMovedEvents: YES];
5213   [win setDelegate: self];
5214   [win useOptimizedDrawing: YES];
5216   sz.width = FRAME_COLUMN_WIDTH (f);
5217   sz.height = FRAME_LINE_HEIGHT (f);
5218   [win setResizeIncrements: sz];
5220   [[win contentView] addSubview: self];
5222   if (ns_drag_types)
5223     [self registerForDraggedTypes: ns_drag_types];
5225   tem = f->name;
5226   name = [NSString stringWithUTF8String:
5227                    NILP (tem) ? (unsigned char *)"Emacs" : XSTRING (tem)->data];
5228   [win setTitle: name];
5230   /* toolbar support */
5231   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5232                          [NSString stringWithFormat: @"Emacs Frame %d",
5233                                    ns_window_num]];
5234   [win setToolbar: toolbar];
5235   [toolbar setVisible: NO];
5236 #ifdef NS_IMPL_COCOA
5237   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5238   [toggleButton setTarget: self];
5239   [toggleButton setAction: @selector (toggleToolbar: )];
5240 #endif
5241   FRAME_NS_TOOLBAR_HEIGHT (f) = 0;
5243   tem = f->icon_name;
5244   if (!NILP (tem))
5245     [win setMiniwindowTitle:
5246            [NSString stringWithUTF8String: XSTRING (tem)->data]];
5248   {
5249     NSScreen *screen = [win screen];
5251     if (screen != 0)
5252       [win setFrameTopLeftPoint: NSMakePoint
5253            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5254             IN_BOUND (-SCREENMAX,
5255                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5256   }
5258   [win makeFirstResponder: self];
5260   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5261                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5262   [win setBackgroundColor: col];
5263   if ([col alphaComponent] != 1.0)
5264     [win setOpaque: NO];
5266   [self allocateGState];
5268   ns_window_num++;
5269   return self;
5273 - (void)windowDidMove: sender
5275   NSWindow *win = [self window];
5276   NSRect r = [win frame];
5277   NSScreen *screen = [win screen];
5278   NSRect sr = [screen frame];
5280   NSTRACE (windowDidMove);
5282   if (!emacsframe->output_data.ns)
5283     return;
5284   if (screen != nil)
5285     {
5286       emacsframe->left_pos = r.origin.x; /* - sr.origin.x; */
5287       emacsframe->top_pos = sr.size.height -
5288         (r.origin.y + r.size.height); /* + sr.origin.y; */
5289     }
5292 #ifdef NS_IMPL_COCOA
5293 /* if we don't do this manually, the window will resize but not move */
5294 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5296   [[self window] setFrame: newFrame display: NO];
5297   return YES;
5299 #endif
5301 /* Implement this to control size of frame on zoom.
5302 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5303                         defaultFrame:(NSRect)defaultFrame; */
5306 - (void)windowDidDeminiaturize: sender
5308   NSTRACE (windowDidDeminiaturize);
5309   if (!emacsframe->output_data.ns)
5310     return;
5311   emacsframe->async_visible   = 1;
5312   emacsframe->async_iconified = 0;
5313   windows_or_buffers_changed++;
5315   if (emacs_event)
5316     {
5317       emacs_event->kind = ICONIFY_EVENT;
5318       EV_TRAILER ((id)nil);
5319     }
5323 - (void)windowDidExpose: sender
5325   NSTRACE (windowDidExpose);
5326   if (!emacsframe->output_data.ns)
5327     return;
5328   emacsframe->async_visible = 1;
5329   SET_FRAME_GARBAGED (emacsframe);
5331   if (send_appdefined)
5332     ns_send_appdefined (-1);
5336 - (void)windowDidMiniaturize: sender
5338   NSTRACE (windowDidMiniaturize);
5339   if (!emacsframe->output_data.ns)
5340     return;
5342   emacsframe->async_iconified = 1;
5344   if (emacs_event)
5345     {
5346       emacs_event->kind = ICONIFY_EVENT;
5347       EV_TRAILER ((id)nil);
5348     }
5352 - (void)mouseEntered: (NSEvent *)theEvent
5354   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5355   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5356   NSTRACE (mouseEntered);
5358   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5362 - (void)mouseExited: (NSEvent *)theEvent
5364   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5365   NSRect r;
5366   struct ns_display_info *dpyinfo =
5367       emacsframe ? FRAME_NS_DISPLAY_INFO (emacsframe) : NULL;
5369   NSTRACE (mouseExited);
5371   if (dpyinfo || !emacsframe)
5372     return;
5374   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5376   if (emacsframe == dpyinfo->mouse_face_mouse_frame)
5377     {
5378       clear_mouse_face (dpyinfo);
5379       dpyinfo->mouse_face_mouse_frame = 0;
5380     }
5384 - menuDown: sender
5386   NSTRACE (menuDown);
5387   if (context_menu_value == -1)
5388     context_menu_value = [sender tag];
5389   else
5390     find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
5391                                   emacsframe->menu_bar_vector, [sender tag]);
5392   ns_send_appdefined (-1);
5393   return self;
5397 - (EmacsToolbar *)toolbar
5399   return toolbar;
5403 /* this gets called on toolbar button click */
5404 - toolbarClicked: (id)item
5406   NSEvent *theEvent;
5407   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
5409   NSTRACE (toolbarClicked);
5411   if (!emacs_event)
5412     return self;
5414   /* send first event (for some reason two needed) */
5415   theEvent =[[self window] currentEvent];
5416   emacs_event->kind = TOOL_BAR_EVENT;
5417   XSETFRAME (emacs_event->arg, emacsframe);
5418   EV_TRAILER (theEvent);
5420   emacs_event->kind = TOOL_BAR_EVENT;
5421 /*   XSETINT (emacs_event->code, 0); */
5422   emacs_event->arg = AREF (emacsframe->tool_bar_items,
5423                           idx + TOOL_BAR_ITEM_KEY);
5424   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5425   EV_TRAILER (theEvent);
5426   return self;
5430 - toggleToolbar: (id)sender
5432   Lisp_Object lispFrame;
5433   XSETFRAME (lispFrame, emacsframe);
5434   Feval (Fcons (intern ("ns-toggle-toolbar"), Fcons (lispFrame, Qnil)));
5435   SET_FRAME_GARBAGED (emacsframe);
5436   ns_send_appdefined (-1);
5440 - (void)drawRect: (NSRect)rect
5442   int x = NSMinX (rect), y = NSMinY (rect);
5443   int width = NSWidth (rect), height = NSHeight (rect);
5445   NSTRACE (drawRect);
5447   if (!emacsframe || !emacsframe->output_data.ns)
5448     return;
5450   if (!ns_in_resize)
5451     ns_clear_frame_area (emacsframe, x, y, width, height);
5452   expose_frame (emacsframe, x, y, width, height);
5454   emacsframe->async_visible = 1;
5455   emacsframe->async_iconified = 0;
5457 /*    SET_FRAME_GARBAGED (emacsframe);
5458       ns_send_appdefined (-1); */
5462 /* NSDraggingDestination protocol methods.  Actually this is not really a
5463    protocol, but a category of Object.  O well...  */
5465 -(unsigned int) draggingEntered: (id <NSDraggingInfo>) sender
5467   NSTRACE (draggingEntered);
5468   return NSDragOperationGeneric;
5472 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
5474   return YES;
5478 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
5480   id pb;
5481   int x, y;
5482   NSString *type;
5483   NSEvent *theEvent = [[self window] currentEvent];
5484   NSPoint position;
5486   NSTRACE (performDragOperation);
5488   if (!emacs_event)
5489     return;
5491   position = [self convertPoint: [sender draggingLocation] fromView: nil];
5492   x = lrint (position.x);  y = lrint (position.y);
5494   pb = [sender draggingPasteboard];
5495   type = [pb availableTypeFromArray: ns_drag_types];
5496   if (type == 0)
5497     {
5498       return NO;
5499     }
5500   else if ([type isEqualToString: NSFilenamesPboardType])
5501     {
5502       NSArray *files;
5503       NSEnumerator *fenum;
5504       NSString *file;
5506       if (!(files = [pb propertyListForType: type]))
5507         return NO;
5509       fenum = [files objectEnumerator];
5510       while ( (file = [fenum nextObject]) )
5511         {
5512           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5513           emacs_event->code = KEY_NS_DRAG_FILE;
5514           XSETINT (emacs_event->x, x);
5515           XSETINT (emacs_event->y, y);
5516           ns_input_file = append2 (ns_input_file,
5517                                    build_string ([file UTF8String]));
5518           emacs_event->modifiers = EV_MODIFIERS (theEvent);
5519           EV_TRAILER (theEvent);
5520         }
5521       return YES;
5522     }
5523   else if ([type isEqualToString: NSURLPboardType])
5524     {
5525       NSString *file;
5526       NSURL *fileURL;
5528       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
5529           [fileURL isFileURL] == NO)
5530         return NO;
5532       file = [fileURL path];
5533       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5534       emacs_event->code = KEY_NS_DRAG_FILE;
5535       XSETINT (emacs_event->x, x);
5536       XSETINT (emacs_event->y, y);
5537       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
5538       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5539       EV_TRAILER (theEvent);
5540       return YES;
5541     }
5542   else if ([type isEqualToString: NSStringPboardType]
5543            || [type isEqualToString: NSTabularTextPboardType])
5544     {
5545       NSString *data;
5547       if (! (data = [pb stringForType: type]))
5548         return NO;
5550       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5551       emacs_event->code = KEY_NS_DRAG_TEXT;
5552       XSETINT (emacs_event->x, x);
5553       XSETINT (emacs_event->y, y);
5554       ns_input_text = build_string ([data UTF8String]);
5555       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5556       EV_TRAILER (theEvent);
5557       return YES;
5558     }
5559   else if ([type isEqualToString: NSColorPboardType])
5560     {
5561       NSColor *c = [NSColor colorFromPasteboard: pb];
5562       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5563       emacs_event->code = KEY_NS_DRAG_COLOR;
5564       XSETINT (emacs_event->x, x);
5565       XSETINT (emacs_event->y, y);
5566       ns_input_color = ns_color_to_lisp (c);
5567       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5568       EV_TRAILER (theEvent);
5569       return YES;
5570     }
5571   else if ([type isEqualToString: NSFontPboardType])
5572     {
5573       /* impl based on GNUstep NSTextView.m */
5574       NSData *data = [pb dataForType: NSFontPboardType];
5575       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
5576       NSFont *font = [dict objectForKey: NSFontAttributeName];
5577       char fontSize[10];
5579       if (font == nil)
5580         return NO;
5582       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5583       emacs_event->code = KEY_NS_CHANGE_FONT;
5584       XSETINT (emacs_event->x, x);
5585       XSETINT (emacs_event->y, y);
5586       ns_input_font = build_string ([[font fontName] UTF8String]);
5587       snprintf (fontSize, 10, "%f", [font pointSize]);
5588       ns_input_fontsize = build_string (fontSize);
5589       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5590       EV_TRAILER (theEvent);
5591       return YES;
5592     }
5593   else
5594     {
5595       error ("Invalid data type in dragging pasteboard.");
5596       return NO;
5597     }
5601 - validRequestorForSendType: (NSString *)typeSent
5602                  returnType: (NSString *)typeReturned
5604   NSTRACE (validRequestorForSendType);
5605   if ([ns_send_types indexOfObjectIdenticalTo: typeSent] != NSNotFound &&
5606       [ns_return_types indexOfObjectIdenticalTo: typeSent] != NSNotFound)
5607     return self;
5609   return [super validRequestorForSendType: typeSent
5610                                returnType: typeReturned];
5614 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
5615    (gives a miniaturized version of the window); currently we use the latter for
5616    frames whose active buffer doesn't correspond to any file
5617    (e.g., '*scratch*') */
5618 - setMiniwindowImage: (BOOL) setMini
5620   id image = [[self window] miniwindowImage];
5621   NSTRACE (setMiniwindowImage);
5623   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
5624      about "AppleDockIconEnabled" notwithstanding, however the set message
5625      below has its effect nonetheless. */
5626   if (image != emacsframe->output_data.ns->miniimage)
5627     {
5628       if (image && [image isKindOfClass: [EmacsImage class]])
5629         [image release];
5630       [[self window] setMiniwindowImage:
5631                        setMini ? emacsframe->output_data.ns->miniimage : nil];
5632     }
5634   return self;
5638 - (void) setRows: (int) r andColumns: (int) c
5640   rows = r;
5641   cols = c;
5644 @end  /* EmacsView */
5648 /* ==========================================================================
5650     EmacsWindow implementation
5652    ========================================================================== */
5654 @implementation EmacsWindow
5656 /* called only on resize clicks by special case in EmacsApp-sendEvent */
5657 - (void)mouseDown: (NSEvent *)theEvent
5659   if (ns_in_resize)
5660     {
5661       NSSize size = [[theEvent window] frame].size;
5662       grabOffset = [theEvent locationInWindow];
5663       grabOffset.x = size.width - grabOffset.x;
5664     }
5665   else
5666     [super mouseDown: theEvent];
5670 /* stop resizing */
5671 - (void)mouseUp: (NSEvent *)theEvent
5673   if (ns_in_resize)
5674     {
5675       struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
5676       ns_in_resize = NO;
5677       ns_set_name_as_filename (f);
5678       [self display];
5679       ns_send_appdefined (-1);
5680     }
5681   else
5682     [super mouseUp: theEvent];
5686 /* send resize events */
5687 - (void)mouseDragged: (NSEvent *)theEvent
5689   if (ns_in_resize)
5690     {
5691       NSPoint p = [theEvent locationInWindow];
5692       NSSize size, vettedSize, origSize = [self frame].size;
5694       size.width = p.x + grabOffset.x;
5695       size.height = origSize.height - p.y + grabOffset.y;
5697       if (size.width == origSize.width && size.height == origSize.height)
5698         return;
5700       vettedSize = [[self delegate] windowWillResize: self toSize: size];
5701       if (vettedSize.width != size.width || vettedSize.height != size.height)
5702         {
5703           [[NSNotificationCenter defaultCenter]
5704             postNotificationName: NSWindowDidResizeNotification
5705                           object: self];
5706         }
5707     }
5708   else
5709     [super mouseDragged: theEvent];
5712 @end /* EmacsWindow */
5715 /* ==========================================================================
5717     EmacsScroller implementation
5719    ========================================================================== */
5722 @implementation EmacsScroller
5724 /* for repeat button push */
5725 #define SCROLL_BAR_FIRST_DELAY 0.5
5726 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
5728 + (float) scrollerWidth
5730   /* PENDING: if we want to allow variable widths, this is the place to do it,
5731      however neither GNUstep nor Cocoa support it very well */
5732   return [NSScroller scrollerWidth];
5736 - initFrame: (NSRect )r window: (Lisp_Object)nwin
5738   NSTRACE (EmacsScroller_initFrame);
5740   r.size.width = [EmacsScroller scrollerWidth];
5741   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
5742   [self setContinuous: YES];
5743   [self setEnabled: YES];
5745   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
5746      locked against the right, top and bottom edges. */
5747   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
5749   win = nwin;
5750   condemned = NO;
5751   pixel_height = NSHeight (r);
5752   min_portion = 20 / pixel_height;
5754   frame = XFRAME (XWINDOW (win)->frame);
5755   if (FRAME_LIVE_P (frame))
5756     {
5757       int i;
5758       EmacsView *view = FRAME_NS_VIEW (frame);
5759       NSView *sview = [[view window] contentView];
5760       NSArray *subs = [sview subviews];
5762       /* disable optimization stopping redraw of other scrollbars */
5763       view->scrollbarsNeedingUpdate = 0;
5764       for (i =[subs count]-1; i >= 0; i--)
5765         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
5766           view->scrollbarsNeedingUpdate++;
5767       [sview addSubview: self];
5768     }
5770 /*  [self setFrame: r]; */
5772   return self;
5776 - (void)setFrame: (NSRect)newRect
5778   NSTRACE (EmacsScroller_setFrame);
5779 /*  BLOCK_INPUT; */
5780   pixel_height = NSHeight (newRect);
5781   min_portion = 20 / pixel_height;
5782   [super setFrame: newRect];
5783   [self display];
5784 /*  UNBLOCK_INPUT; */
5788 - (void)dealloc
5790   NSTRACE (EmacsScroller_dealloc);
5791   if (!NILP (win))
5792     XWINDOW (win)->vertical_scroll_bar = Qnil;
5793   [super dealloc];
5797 - condemn
5799   NSTRACE (condemn);
5800   condemned =YES;
5801   return self;
5805 - reprieve
5807   NSTRACE (reprieve);
5808   condemned =NO;
5809   return self;
5813 - judge
5815   NSTRACE (judge);
5816   if (condemned)
5817     {
5818       BLOCK_INPUT;
5819       /* ensure other scrollbar updates after deletion */
5820       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
5821       if (view != nil)
5822         view->scrollbarsNeedingUpdate++;
5823       [self removeFromSuperview];
5824       [self release];
5825       UNBLOCK_INPUT;
5826     }
5827   return self;
5831 - (void)resetCursorRects
5833   NSRect visible = [self visibleRect];
5834   NSTRACE (resetCursorRects);
5836   if (!NSIsEmptyRect (visible))
5837     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
5838   [[NSCursor arrowCursor] setOnMouseEntered: YES];
5842 - (int) checkSamePosition: (int) position portion: (int) portion
5843                     whole: (int) whole
5845   return em_position ==position && em_portion ==portion && em_whole ==whole
5846     && portion != whole; /* needed for resize empty buf */
5850 - setPosition: (int)position portion: (int)portion whole: (int)whole
5852   NSTRACE (setPosition);
5854   em_position = position;
5855   em_portion = portion;
5856   em_whole = whole;
5858   if (portion >= whole)
5859     [self setFloatValue: 0.0 knobProportion: 1.0];
5860   else
5861     {
5862       float pos, por;
5863       portion = max ((float)whole*min_portion/pixel_height, portion);
5864       pos = (float)position / (whole - portion);
5865       por = (float)portion/whole;
5866       [self setFloatValue: pos knobProportion: por];
5867     }
5868 #ifdef NS_IMPL_GNUSTEP
5869   [self display];
5870 #endif
5871   return self;
5874 /* PENDING: unused at moment (see ns_mouse_position) at the moment because
5875    drag events will go directly to the EmacsScroller.  Leaving in for now. */
5876 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
5877                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
5879   *part = last_hit_part;
5880   *window = win;
5881   XSETINT (*y, pixel_height);
5882   if ([self floatValue] > 0.999)
5883     XSETINT (*x, pixel_height);
5884   else
5885     XSETINT (*x, pixel_height * [self floatValue]);
5889 /* set up emacs_event */
5890 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
5892   if (!emacs_event)
5893     return;
5895   emacs_event->part = last_hit_part;
5896   emacs_event->code = 0;
5897   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
5898   emacs_event->frame_or_window = win;
5899   emacs_event->timestamp = EV_TIMESTAMP (e);
5900   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
5901   emacs_event->arg = Qnil;
5902   XSETINT (emacs_event->x, loc * pixel_height);
5903   XSETINT (emacs_event->y, pixel_height-20);
5905   n_emacs_events_pending++;
5906   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
5907   EVENT_INIT (*emacs_event);
5908   ns_send_appdefined (-1);
5912 /* called manually thru timer to implement repeated button action w/hold-down */
5913 - repeatScroll: (NSTimer *)scrollEntry
5915   NSEvent *e = [[self window] currentEvent];
5916   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
5917   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
5919   /* clear timer if need be */
5920   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
5921     {
5922         [scroll_repeat_entry invalidate];
5923         [scroll_repeat_entry release];
5924         scroll_repeat_entry = nil;
5926         if (inKnob)
5927           return self;
5929         scroll_repeat_entry =
5930           [[NSTimer scheduledTimerWithTimeInterval:
5931                       SCROLL_BAR_CONTINUOUS_DELAY
5932                                             target: self
5933                                           selector: @selector (repeatScroll:)
5934                                           userInfo: 0
5935                                            repeats: YES]
5936             retain];
5937     }
5939   [self sendScrollEventAtLoc: 0 fromEvent: e];
5940   return self;
5944 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
5945    mouseDragged events without going into a modal loop. */
5946 - (void)mouseDown: (NSEvent *)e
5948   NSRect sr, kr;
5949   /* hitPart is only updated AFTER event is passed on */
5950   NSScrollerPart part = [self testPart: [e locationInWindow]];
5951   double inc = 0.0, loc, kloc, pos;
5952   int edge = 0;
5954   NSTRACE (EmacsScroller_mouseDown);
5956   switch (part)
5957     {
5958     case NSScrollerDecrementPage:
5959         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
5960     case NSScrollerIncrementPage:
5961         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
5962     case NSScrollerDecrementLine:
5963       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
5964     case NSScrollerIncrementLine:
5965       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
5966     case NSScrollerKnob:
5967       last_hit_part = scroll_bar_handle; break;
5968     case NSScrollerKnobSlot:  /* GNUstep-only */
5969       last_hit_part = scroll_bar_move_ratio; break;
5970     default:  /* NSScrollerNoPart? */
5971       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %d\n", part);
5972       return;
5973     }
5975   if (inc != 0.0)
5976     {
5977       pos = 0;      /* ignored */
5979       /* set a timer to repeat, as we can't let superclass do this modally */
5980       scroll_repeat_entry =
5981         [[NSTimer scheduledTimerWithTimeInterval: 0.5
5982                                           target: self
5983                                         selector: @selector (repeatScroll:)
5984                                         userInfo: 0
5985                                          repeats: YES]
5986           retain];
5987     }
5988   else
5989     {
5990       /* handle, or on GNUstep possibly slot */
5991       NSEvent *fake_event;
5993       /* compute float loc in slot and mouse offset on knob */
5994       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
5995                       toView: nil];
5996       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
5997       if (loc <= 0.0)
5998         {
5999           loc = 0.0;
6000           edge = -1;
6001         }
6002       else if (loc >= NSHeight (sr))
6003         {
6004           loc = NSHeight (sr);
6005           edge = 1;
6006         }
6008       if (edge)
6009         kloc = 0.5 * edge;
6010       else
6011         {
6012           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
6013                           toView: nil];
6014           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
6015         }
6016       last_mouse_offset = kloc;
6018       /* if knob, tell emacs a location offset by knob pos
6019          (to indicate top of handle) */
6020       if (part == NSScrollerKnob)
6021           pos = (loc - last_mouse_offset) / NSHeight (sr);
6022       else
6023         /* else this is a slot click on GNUstep: go straight there */
6024         pos = loc / NSHeight (sr);
6026       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
6027       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
6028                                       location: [e locationInWindow]
6029                                  modifierFlags: [e modifierFlags]
6030                                      timestamp: [e timestamp]
6031                                   windowNumber: [e windowNumber]
6032                                        context: [e context]
6033                                    eventNumber: [e eventNumber]
6034                                     clickCount: [e clickCount]
6035                                       pressure: [e pressure]];
6036       [super mouseUp: fake_event];
6037     }
6039   if (part != NSScrollerKnob)
6040     [self sendScrollEventAtLoc: pos fromEvent: e];
6044 /* Called as we manually track scroller drags, rather than superclass. */
6045 - (void)mouseDragged: (NSEvent *)e
6047     NSRect sr;
6048     double loc, pos;
6049     int edge = 0;
6051     NSTRACE (EmacsScroller_mouseDragged);
6053       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6054                       toView: nil];
6055       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6057       if (loc <= 0.0)
6058         {
6059           loc = 0.0;
6060           edge = -1;
6061         }
6062       else if (loc >= NSHeight (sr) + last_mouse_offset)
6063         {
6064           loc = NSHeight (sr) + last_mouse_offset;
6065           edge = 1;
6066         }
6068       pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
6069       [self sendScrollEventAtLoc: pos fromEvent: e];
6073 - (void)mouseUp: (NSEvent *)e
6075   if (scroll_repeat_entry)
6076     {
6077       [scroll_repeat_entry invalidate];
6078       [scroll_repeat_entry release];
6079       scroll_repeat_entry = nil;
6080     }
6081   last_hit_part = 0;
6085 /* treat scrollwheel events in the bar as though they were in the main window */
6086 - (void) scrollWheel: (NSEvent *)theEvent
6088   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
6089   [view mouseDown: theEvent];
6092 @end  /* EmacsScroller */
6096 /* ==========================================================================
6098     EmacsPrefsController implementation
6100    ========================================================================== */
6103 @implementation EmacsPrefsController
6105 /* in Tiger+, can just do [popup selectItemWithTag: tag]; */
6106 static void selectItemWithTag (NSPopUpButton *popup, int tag)
6108   NSEnumerator *items = [[popup itemArray] objectEnumerator];
6109   NSMenuItem *item;
6110   while (item = [items nextObject])
6111     {
6112       if ([item tag] == tag)
6113         {
6114           [popup selectItem: item];
6115           return;
6116         }
6117     }
6120 - init
6122   [NSBundle loadNibNamed: @"preferences" owner: self];
6123   return self;
6127 - (void) showForFrame: (struct frame *)f
6129   frame = f;
6130   [self setPanelFromValues];
6131   [prefsWindow makeKeyAndOrderFront: self];
6132   [prefsWindow display];
6136 - (void) setPanelFromValues
6138   int cursorType =
6139     ns_lisp_to_cursor_type (get_frame_param (frame, Qcursor_type));
6140   prevExpandSpace = XFLOATINT (ns_expand_space);
6141   prevBlinkRate = NILP (ns_cursor_blink_rate)
6142     ? 0 : XFLOATINT (ns_cursor_blink_rate);
6144 #ifdef NS_IMPL_COCOA
6145   prevUseHighlightColor = ns_use_system_highlight_color;
6146 #endif
6148   [expandSpaceSlider setFloatValue: prevExpandSpace];
6149   [cursorBlinkSlider setFloatValue: prevBlinkRate];
6150   [cursorTypeMatrix selectCellWithTag: (cursorType == filled_box ? 1 :
6151                                         (cursorType == bar ? 2 :
6152                                          (cursorType == underscore ? 3 : 4)))];
6153   selectItemWithTag (alternateModMenu, lisp_to_mod (ns_alternate_modifier));
6154   selectItemWithTag (commandModMenu, lisp_to_mod (ns_command_modifier));
6155 #ifdef NS_IMPL_COCOA
6156   selectItemWithTag (controlModMenu, lisp_to_mod (ns_control_modifier));
6157   selectItemWithTag (functionModMenu, lisp_to_mod (ns_function_modifier));
6158   [smoothFontsCheck setState: ns_antialias_text ? YES : NO];
6159   [useQuickdrawCheck setState: ns_use_qd_smoothing ? YES : NO];
6160   [useSysHiliteCheck setState: prevUseHighlightColor ? YES : NO];
6161 #endif
6165 - (void) setValuesFromPanel
6167   int cursorTag = [[cursorTypeMatrix selectedCell] tag];
6168   int altTag = [[alternateModMenu selectedItem] tag];
6169   int cmdTag = [[commandModMenu selectedItem] tag];
6170 #ifdef NS_IMPL_COCOA
6171   int ctrlTag = [[controlModMenu selectedItem] tag];
6172   int fnTag = [[functionModMenu selectedItem] tag];
6173 #endif
6174   float blinkRate = [cursorBlinkSlider floatValue];
6175   float expandSpace = [expandSpaceSlider floatValue];
6176   Lisp_Object old_cursor_blink_mode;
6178   if (expandSpace != prevExpandSpace)
6179     {
6180       ns_expand_space = make_float (expandSpace);
6181       /* PENDING: more needed: store needed metrics in nsfont_info, update
6182          frame default font max_bounds and fontp, recompute faces */
6183 /*         FRAME_LINE_HEIGHT (frame) *= (expandSpace / prevExpandSpace);
6184            x_set_window_size (frame, 0, frame->text_cols, frame->text_lines); */
6185       prevExpandSpace = expandSpace;
6186     }
6187   if (blinkRate != prevBlinkRate)
6188     {
6189       old_cursor_blink_mode = ns_cursor_blink_mode;
6190       if (blinkRate == 0.0)
6191         {
6192           ns_cursor_blink_rate = Qnil;
6193           ns_cursor_blink_mode = Qnil;
6194         }
6195       else
6196         {
6197           ns_cursor_blink_rate = make_float (blinkRate);
6198           ns_cursor_blink_mode = Qt;
6199         }
6200       if (ns_cursor_blink_mode != old_cursor_blink_mode)
6201           Feval (Fcons (intern ("blink-cursor-mode"), Qnil));
6203       if (blinkRate != 0.0 && prevBlinkRate != 0.0)
6204         {  /* if changed rates, remove blink handler so change picked up */
6205           struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
6206           [cursor_blink_entry invalidate];
6207           [cursor_blink_entry release];
6208           cursor_blink_entry = 0;
6209           if (dpyinfo->ns_highlight_frame)
6210             {
6211               Lisp_Object tem =
6212                 get_frame_param (dpyinfo->ns_highlight_frame, Qcursor_type);
6213               dpyinfo->ns_highlight_frame->output_data.ns->desired_cursor =
6214                 ns_lisp_to_cursor_type (tem);
6215             }
6216         }
6217       prevBlinkRate = blinkRate;
6218     }
6219   FRAME_NEW_CURSOR (frame) =
6220                          (cursorTag == 1 ? filled_box :
6221                           (cursorTag == 2 ? bar :
6222                            (cursorTag == 3 ? underscore : hollow_box)));
6223   store_frame_param (frame, Qcursor_type,
6224                     ns_cursor_type_to_lisp (FRAME_NEW_CURSOR (frame)));
6225   ns_alternate_modifier = ns_mod_to_lisp (altTag);
6226   ns_command_modifier = ns_mod_to_lisp (cmdTag);
6227 #ifdef NS_IMPL_COCOA
6228   ns_control_modifier = ns_mod_to_lisp (ctrlTag);
6229   ns_function_modifier = ns_mod_to_lisp (fnTag);
6230   ns_antialias_text = [smoothFontsCheck state];
6231   ns_use_qd_smoothing = [useQuickdrawCheck state];
6232   ns_use_system_highlight_color = [useSysHiliteCheck state];
6233   if (ns_use_system_highlight_color != prevUseHighlightColor)
6234     {
6235       prevUseHighlightColor = ns_use_system_highlight_color;
6236       if (ns_use_system_highlight_color == YES)
6237         {
6238           ns_selection_color = [[NSUserDefaults standardUserDefaults]
6239                                  stringForKey: @"AppleHighlightColor"];
6240           if (ns_selection_color == nil)
6241             ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
6242         }
6243       else
6244         ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
6245     }
6246 #endif /* NS_IMPL_COCOA */
6247   Fcall_interactively (intern ("ns-save-preferences"), Qnil, Qnil);
6251 /* buttons */
6252 - (IBAction)cancel: (id)sender
6254   [prefsWindow close];
6258 - (IBAction)ok: (id)sender
6260   [self setValuesFromPanel];
6261   [prefsWindow close];
6265 - (IBAction)resetToDefaults: (id)sender
6267   ns_set_default_prefs ();
6268   [self setPanelFromValues];
6272 - (IBAction)runHelp: (id)sender
6274   Feval (Fcons (intern ("info"),
6275               Fcons (build_string ("(ns-emacs)Preferences Panel"), Qnil)));
6276   SET_FRAME_GARBAGED (frame);
6277   ns_send_appdefined (-1);
6281 - (IBAction)setColors: (id)sender
6283   Lisp_Object lispFrame;
6284   XSETFRAME (lispFrame, frame);
6285   Fns_popup_color_panel (lispFrame);
6289 - (IBAction)setDefaultFont: (id)sender
6291   Lisp_Object lispFrame;
6292   XSETFRAME (lispFrame, frame);
6293   Fns_popup_font_panel (lispFrame);
6296 @end  /* EmacsPrefsController */
6301 /* ==========================================================================
6303    Font-related functions; these used to be in nsfaces.m
6305    ========================================================================== */
6308 Lisp_Object
6309 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
6311   struct font *font = XFONT_OBJECT (font_object);
6313   if (fontset < 0)
6314     fontset = fontset_from_font (font_object);
6315   FRAME_FONTSET (f) = fontset;
6317   if (FRAME_FONT (f) == font)
6318     /* This font is already set in frame F.  There's nothing more to
6319        do.  */
6320     return font_object;
6322   FRAME_FONT (f) = font;
6324   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
6325   FRAME_COLUMN_WIDTH (f) = font->average_width;
6326   FRAME_SPACE_WIDTH (f) = font->space_width;
6327   FRAME_LINE_HEIGHT (f) = font->height;
6329   compute_fringe_widths (f, 1);
6331   /* Compute the scroll bar width in character columns.  */
6332   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6333     {
6334       int wid = FRAME_COLUMN_WIDTH (f);
6335       FRAME_CONFIG_SCROLL_BAR_COLS (f)
6336         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
6337     }
6338   else
6339     {
6340       int wid = FRAME_COLUMN_WIDTH (f);
6341       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6342     }
6344   /* Now make the frame display the given font.  */
6345   if (FRAME_NS_WINDOW (f) != 0)
6346         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6348   return font_object;
6352 Lisp_Object
6353 ns_list_fonts (FRAME_PTR f, Lisp_Object pattern, int size, int maxnames)
6354 /* --------------------------------------------------------------------------
6355      This is used by the xfaces system.  It is expected to speak XLFD.
6356    -------------------------------------------------------------------------- */
6358   Lisp_Object list = Qnil,
6359     rpattern,
6360     key,
6361     tem,
6362     args[2];
6363   struct re_pattern_buffer *bufp;
6364   id fm = [NSFontManager sharedFontManager];
6365   NSEnumerator *fenum, *senum;
6366   NSArray *membInfo;
6367   NSString *fontname;
6368   const char *xlfdName;
6369   char *pattFam;
6370   char *patt;
6371   NSString *famName;
6373   NSTRACE (ns_list_fonts);
6375   CHECK_STRING (pattern);
6376   patt = XSTRING (pattern)->data;
6378 #if 0
6379 /* temporary: for font_backend, we use fontsets, and when these are defined,
6380    the old XLFD-based system is used; eventually this will be replaced by
6381    backend code, but for now we allow specs that are just family names */
6382       /* if pattern is not XLFD, panic now */
6383       if (patt[0] != '-')
6384         error ("ns_list_fonts: X font name (XLFD) expected.");
6386       /* if unicode encoding not requested, also die */
6387       if (!strstr (patt, "iso10646") && patt[strlen (patt)-3] != '*')
6388         return Qnil;
6389 #endif /* 0 */
6391   key = f ? Fcons (pattern, make_number (maxnames)) : Qnil;
6392   tem = f ? XCDR (FRAME_NS_DISPLAY_INFO (f)->name_list_element) : Qnil;
6394   /* See if we cached the result for this particular query.
6395      The cache is an alist of the form:
6396      ((((PATTERN . MAXNAMES) FONTNAME) ...) ...)
6397   */
6398   if (f && !NILP (list = Fassoc (key, tem)))
6399     {
6400       list = Fcdr_safe (list);
6401       /* We have a cached list.  Don't have to get the list again.  */
6402       if (!NILP (list))
6403         return list;
6404     }
6406   if (patt[0] != '-')
6407       pattFam = patt;
6408   else
6409       pattFam = ns_xlfd_to_fontname (patt);
6410   /*PENDING: '*' at beginning matches literally.. */
6411   if (pattFam[0] == '*')
6412     pattFam[0] = '.';
6414   /* must start w/family name, but can have other stuff afterwards
6415     (usually bold and italic specifiers) */
6416   args[0] = build_string ("^");
6417   args[1] = build_string (pattFam);
6418   rpattern = Fconcat (2, args);
6419   bufp = compile_pattern (rpattern, 0, Vascii_canon_table, 0, 0);
6421   list = Qnil;
6422   fenum = [[fm availableFontFamilies] objectEnumerator];
6423   while ( (famName = [fenum nextObject]) )
6424     {
6425       NSMutableString *tmp = [famName mutableCopy];
6426       const char *fname;
6427       NSRange r;
6429       /* remove spaces, to look like postscript name */
6430       while ((r = [tmp rangeOfString: @" "]).location != NSNotFound)
6431         [tmp deleteCharactersInRange: r];
6433       fname = [tmp UTF8String];
6434       int len = strlen (fname);
6435       BOOL foundItal;
6436       const char *synthItalFont;
6438       if (re_search (bufp, fname, len, 0, len, 0) >= 0)
6439         {
6440           /* Found a family.  Add all variants.  If we have no italic variant,
6441              add a synthItal. */
6442           senum =[[fm availableMembersOfFontFamily: famName] objectEnumerator];
6443           foundItal = NO;
6444           synthItalFont = NULL;
6445           while (membInfo = [senum nextObject])
6446             {
6447               xlfdName =
6448                 ns_fontname_to_xlfd ([[membInfo objectAtIndex: 0] UTF8String]);
6449               list = Fcons (build_string (xlfdName), list);
6450               if (!synthItalFont)
6451                 {
6452                   NSString *synthName =
6453                     [[membInfo objectAtIndex: 0]
6454                       stringByAppendingString: @"-synthItal"];
6455                   synthItalFont = [synthName UTF8String];
6456                 }
6457               else if ([[membInfo objectAtIndex: 3] intValue]
6458                          & NSItalicFontMask)
6459                 foundItal = YES;
6460             }
6461           if (foundItal == NO)
6462             {
6463               xlfdName = ns_fontname_to_xlfd (synthItalFont);
6464               list = Fcons (build_string (xlfdName), list);
6465             }
6466         }
6467       [tmp release];
6468     }
6470   /* fallback */
6471   if (XFASTINT (Flength (list)) == 0)
6472       list = Fcons (build_string (ns_fontname_to_xlfd ("Monaco")), list);
6474   /* store result in cache */
6475   if (f != NULL)
6476     XCDR_AS_LVALUE (FRAME_NS_DISPLAY_INFO (f)->name_list_element)
6477       = Fcons (Fcons (key, list),
6478                XCDR (FRAME_NS_DISPLAY_INFO (f)->name_list_element));
6479   return list;
6483 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
6485 const char *
6486 ns_font_to_xlfd (NSFont *nsfont)
6487 /* --------------------------------------------------------------------------
6488     Convert an NS font name to an X font name (XLFD).
6489     The string returned is temporarily allocated.
6490    -------------------------------------------------------------------------- */
6492   NSFontManager *mgr = [NSFontManager sharedFontManager];
6493   NSString *sname = [nsfont /*familyName*/fontName];
6494   char *famName = [sname UTF8String];
6495   char *weightStr = [mgr fontNamed: sname hasTraits: NSBoldFontMask] ?
6496       "bold" : "medium";
6497   char *slantStr = [mgr fontNamed: sname hasTraits: NSItalicFontMask] ?
6498       "i" : "r";
6499   int size = [nsfont pointSize];
6500   int aWidth = lrint (10.0 * [nsfont widthOfString: @"a"]);
6501   const char *xlfd;
6502   int i, len;
6504   /* change '-' to '$' to avoid messing w/XLFD separator */
6505   for (len =strlen (famName), i =0; i<len; i++)
6506     if (famName[i] == '-')
6507       {
6508         famName[i] = '\0';
6509         break;
6510       }
6512   xlfd = [[NSString stringWithFormat:
6513                        @"-apple-%s-%s-%s-normal--%d-%d-75-75-m-%d-iso10646-1",
6514                        famName, weightStr, slantStr, size, 10*size, aWidth]
6515                   UTF8String];
6516 /*fprintf (stderr, "converted '%s' to '%s'\n",name,xlfd); */
6517   return xlfd;
6520 const char *
6521 ns_fontname_to_xlfd (const char *name)
6522 /* --------------------------------------------------------------------------
6523     Convert an NS font name to an X font name (XLFD).
6524     Sizes are set to 0.
6525     The string returned is temporarily allocated.
6526    -------------------------------------------------------------------------- */
6528   char famName[180];
6529   char *weightStr = strcasestr (name, "bold") ? "bold" : "medium";
6530   char *slantStr = strcasestr (name, "italic") || strcasestr (name, "oblique")
6531     || strcasestr (name, "synthital") ? "i" : "r";
6532   int i, len;
6533   const char *xlfd;
6535   /* change '-' to '$' to avoid messing w/XLFD separator, and ' ' to '_' */
6536   bzero (famName, 180);
6537   bcopy (name, famName, max (strlen (name), 179));
6538   for (len =strlen (famName), i =0; i<len; i++)
6539     {
6540       if (famName[i] == '-')
6541         famName[i] = '$';
6542       else if (famName[i] == ' ')
6543         famName[i] = '_';
6544     }
6546   xlfd = [[NSString stringWithFormat:
6547                            @"-apple-%s-%s-%s-normal--0-0-75-75-m-0-iso10646-1",
6548                            famName, weightStr, slantStr]
6549                   UTF8String];
6550 /*fprintf (stderr, "converted '%s' to '%s'\n",name,xlfd); */
6551   return xlfd;
6555 const char *
6556 ns_xlfd_to_fontname (const char *xlfd)
6557 /* --------------------------------------------------------------------------
6558     Convert an X font name (XLFD) to an NS font name.
6559     Only family is used.
6560     The string returned is temporarily allocated.
6561    -------------------------------------------------------------------------- */
6563   char *name = xmalloc (180);
6564   int i, len;
6565   const char *ret;
6566   
6567   if (!strncmp (xlfd, "--", 2))
6568     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
6569   else
6570     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
6572   /* stopgap for malformed XLFD input */
6573   if (strlen (name) == 0)
6574     strcpy (name, "Monaco");
6576   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
6577      also uppercase after '-' or ' ' */
6578   name[0] = toupper (name[0]);
6579   for (len =strlen (name), i =0; i<len; i++)
6580     {
6581       if (name[i] == '$')
6582         {
6583           name[i] = '-';
6584           if (i+1<len)
6585             name[i+1] = toupper (name[i+1]);
6586         }
6587       else if (name[i] == '_')
6588         {
6589           name[i] = ' ';
6590           if (i+1<len)
6591             name[i+1] = toupper (name[i+1]);
6592         }
6593     }
6594 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
6595   ret = [[NSString stringWithUTF8String: name] UTF8String];
6596   xfree (name);
6597   return ret;
6600 /* arch-tag: 6eaa8f7d-a69b-4e1c-b43d-ab31defbe0d2
6601    (do not change this comment) */