* nsterm.m (EV_TRAILER): Always use emacsframe for frame_or_window. (ns_font_to_xlfd...
[emacs/old-mirror.git] / src / nsterm.m
blobfba0e726e4736a49414ff07f52fc350a2e04ba97
1 /* NeXT/Open/GNUstep / MacOSX communication module.
2    Copyright (C) 1989, 1993, 1994, 2005, 2006, 2008, 2009
3      Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
21 Originally by Carl Edman
22 Updated by Christian Limpach (chris@nice.ch)
23 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
24 MacOSX/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
25 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
28 /* This should be the first include, as it may set up #defines affecting
29    interpretation of even the system includes. */
30 #include "config.h"
32 #include <math.h>
33 #include <sys/types.h>
34 #include <time.h>
35 #include <unistd.h>
37 #include "lisp.h"
38 #include "blockinput.h"
39 #include "sysselect.h"
40 #include "nsterm.h"
41 #include "systime.h"
42 #include "character.h"
43 #include "fontset.h"
44 #include "composite.h"
45 #include "ccl.h"
47 #include "termhooks.h"
48 #include "termopts.h"
49 #include "termchar.h"
51 #include "window.h"
52 #include "keyboard.h"
54 #include "font.h"
56 /* call tracing */
57 #if 0
58 int term_trace_num = 0;
59 #define NSTRACE(x)        fprintf (stderr, "%s:%d: [%d] " #x "\n",         \
60                                 __FILE__, __LINE__, ++term_trace_num)
61 #else
62 #define NSTRACE(x)
63 #endif
66 /* ==========================================================================
68     Local declarations
70    ========================================================================== */
72 /* Special keycodes that we pass down the event chain */
73 #define KEY_NS_POWER_OFF               ((1<<28)|(0<<16)|1)
74 #define KEY_NS_OPEN_FILE               ((1<<28)|(0<<16)|2)
75 #define KEY_NS_OPEN_TEMP_FILE          ((1<<28)|(0<<16)|3)
76 #define KEY_NS_DRAG_FILE               ((1<<28)|(0<<16)|4)
77 #define KEY_NS_DRAG_COLOR              ((1<<28)|(0<<16)|5)
78 #define KEY_NS_DRAG_TEXT               ((1<<28)|(0<<16)|6)
79 #define KEY_NS_CHANGE_FONT             ((1<<28)|(0<<16)|7)
80 #define KEY_NS_OPEN_FILE_LINE          ((1<<28)|(0<<16)|8)
81 #define KEY_NS_INSERT_WORKING_TEXT     ((1<<28)|(0<<16)|9)
82 #define KEY_NS_DELETE_WORKING_TEXT     ((1<<28)|(0<<16)|10)
83 #define KEY_NS_SPI_SERVICE_CALL        ((1<<28)|(0<<16)|11)
84 #define KEY_NS_NEW_FRAME               ((1<<28)|(0<<16)|12)
86 /* Convert a symbol indexed with an NSxxx value to a value as defined
87    in keyboard.c (lispy_function_key). I hope this is a correct way
88    of doing things... */
89 static unsigned convert_ns_to_X_keysym[] =
91   NSHomeFunctionKey,            0x50,
92   NSLeftArrowFunctionKey,       0x51,
93   NSUpArrowFunctionKey,         0x52,
94   NSRightArrowFunctionKey,      0x53,
95   NSDownArrowFunctionKey,       0x54,
96   NSPageUpFunctionKey,          0x55,
97   NSPageDownFunctionKey,        0x56,
98   NSEndFunctionKey,             0x57,
99   NSBeginFunctionKey,           0x58,
100   NSSelectFunctionKey,          0x60,
101   NSPrintFunctionKey,           0x61,
102   NSExecuteFunctionKey,         0x62,
103   NSInsertFunctionKey,          0x63,
104   NSUndoFunctionKey,            0x65,
105   NSRedoFunctionKey,            0x66,
106   NSMenuFunctionKey,            0x67,
107   NSFindFunctionKey,            0x68,
108   NSHelpFunctionKey,            0x6A,
109   NSBreakFunctionKey,           0x6B,
111   NSF1FunctionKey,              0xBE,
112   NSF2FunctionKey,              0xBF,
113   NSF3FunctionKey,              0xC0,
114   NSF4FunctionKey,              0xC1,
115   NSF5FunctionKey,              0xC2,
116   NSF6FunctionKey,              0xC3,
117   NSF7FunctionKey,              0xC4,
118   NSF8FunctionKey,              0xC5,
119   NSF9FunctionKey,              0xC6,
120   NSF10FunctionKey,             0xC7,
121   NSF11FunctionKey,             0xC8,
122   NSF12FunctionKey,             0xC9,
123   NSF13FunctionKey,             0xCA,
124   NSF14FunctionKey,             0xCB,
125   NSF15FunctionKey,             0xCC,
127   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
128   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
129   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
131   NSTabCharacter,               0x09,
132   0x19,                         0x09,  /* left tab->regular since pass shift */
133   NSCarriageReturnCharacter,    0x0D,
134   NSNewlineCharacter,           0x0D,
135   NSEnterCharacter,             0x8D,
137   0x1B,                         0x1B   /* escape */
141 /* Lisp communications */
142 Lisp_Object ns_input_file, ns_input_font, ns_input_fontsize, ns_input_line;
143 Lisp_Object ns_input_color, ns_input_text, ns_working_text;
144 Lisp_Object ns_input_spi_name, ns_input_spi_arg;
145 Lisp_Object Vx_toolkit_scroll_bars;
146 static Lisp_Object Qmodifier_value;
147 /* TODO: unsure why these defined in term files, anyway we need in keymap.c */
148 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper;
149 extern Lisp_Object Qcursor_color, Qcursor_type, Qns;
152 EmacsPrefsController *prefsController;
154 /* Defaults managed through the OpenStep defaults system.  These pertain to
155    the NS interface specifically.  Although a customization group could be
156    created, it's more natural to manage them via defaults. */
158 /* Specifies which emacs modifier should be generated when NS receives
159    the Alternate modifer.  May be Qnone or any of the modifier lisp symbols. */
160 Lisp_Object ns_alternate_modifier;
162 /* Specifies which emacs modifier should be generated when NS receives
163    the Command modifer.  May be any of the modifier lisp symbols. */
164 Lisp_Object ns_command_modifier;
166 /* Specifies which emacs modifier should be generated when NS receives
167    the Control modifer.  May be any of the modifier lisp symbols. */
168 Lisp_Object ns_control_modifier;
170 /* Specifies which emacs modifier should be generated when NS receives
171    the Function modifer (laptops).  May be any of the modifier lisp symbols. */
172 Lisp_Object ns_function_modifier;
174 /* A floating point value specifying vertical stretch (positive) or shrink
175   (negative) of text line spacing.  Zero means default spacing.
176   YES indicates 0.5, NO indicates 0.0. */
177 Lisp_Object ns_expand_space;
179 /* Control via default 'GSFontAntiAlias' on OS X and GNUstep. */
180 Lisp_Object ns_antialias_text;
182 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
183    the maximum font size to NOT antialias.  On GNUstep there is currently
184    no way to control this behavior. */
185 float ns_antialias_threshold;
187 /* Controls use of an undocumented CG function to do Quickdraw-style font
188    smoothing (less heavy) instead of regular Quartz smoothing. */
189 Lisp_Object ns_use_qd_smoothing;
191 /* Used to pick up AppleHighlightColor on OS X */
192 Lisp_Object ns_use_system_highlight_color;
193 NSString *ns_selection_color;
196 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
198 /* Display variables */
199 struct ns_display_info *x_display_list; /* Chain of existing displays */
200 Lisp_Object ns_display_name_list;
201 long context_menu_value = 0;
203 /* display update */
204 NSPoint last_mouse_motion_position;
205 static NSRect last_mouse_glyph;
206 static unsigned long last_mouse_movement_time = 0;
207 static Lisp_Object last_mouse_motion_frame;
208 static EmacsScroller *last_mouse_scroll_bar = nil;
209 static struct frame *ns_updating_frame;
210 static NSView *focus_view = NULL;
211 static int ns_window_num =0;
212 static NSRect uRect;
213 static BOOL gsaved = NO;
214 BOOL ns_in_resize = NO;
215 static BOOL ns_fake_keydown = NO;
216 int ns_tmp_flags; /* FIXME */
217 struct nsfont_info *ns_tmp_font; /* FIXME */
218 /*static int debug_lock = 0; */
220 #ifdef NS_IMPL_COCOA
221 /* This undocumented Quartz function controls how fonts are anti-aliased.
222    (Found from code in Mac wxWindows impl, discovered by running `nm' on
223    the "QD" framework.)
224    Mode 0 is normal anti-aliasing, mode 1 is no anti-aliasing, and mode 2 is
225    4-bit pixel-aligned anti-aliasing (the old QuickDraw standard). */
226 extern void CGContextSetFontRenderingMode (CGContextRef cg, int v);
227 #endif
230 /* event loop */
231 static BOOL send_appdefined = YES;
232 static NSEvent *last_appdefined_event = 0;
233 static NSTimer *timed_entry = 0;
234 static NSTimer *fd_entry = nil;
235 static NSTimer *scroll_repeat_entry = nil;
236 static fd_set select_readfds, t_readfds;
237 static struct timeval select_timeout;
238 static int select_nfds;
239 static NSAutoreleasePool *outerpool;
240 static BOOL ns_shutdown_properly = NO;
241 static struct input_event *emacs_event = NULL;
242 static struct input_event *q_event_ptr = NULL;
243 static int n_emacs_events_pending = 0;
244 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
245   *ns_pending_service_args;
246 static BOOL inNsSelect = 0;
248 /* Convert modifiers in a NeXTSTEP event to emacs style modifiers.  */
249 #define NS_FUNCTION_KEY_MASK 0x800000
250 #define EV_MODIFIERS(e)                               \
251     ((([e modifierFlags] & NSHelpKeyMask) ?           \
252            hyper_modifier : 0)                        \
253      | (([e modifierFlags] & NSAlternateKeyMask) ?    \
254            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
255      | (([e modifierFlags] & NSShiftKeyMask) ?        \
256            shift_modifier : 0)                        \
257      | (([e modifierFlags] & NSControlKeyMask) ?      \
258            parse_solitary_modifier (ns_control_modifier) : 0)     \
259      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
260            parse_solitary_modifier (ns_function_modifier) : 0)    \
261      | (([e modifierFlags] & NSCommandKeyMask) ?      \
262            parse_solitary_modifier (ns_command_modifier):0))
264 #define EV_UDMODIFIERS(e)                                      \
265     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
266      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
267      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
268      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
269      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
270      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
271      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
272      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
273      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
275 #define EV_BUTTON(e)                                                         \
276     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
277       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
278      [e buttonNumber] - 1)
280 /* Convert the time field to a timestamp in milliseconds. */
281 #ifdef NS_IMPL_GNUSTEP
282 /* Apple says timestamp is in seconds, but GNUstep seems to be returning msec */
283 #define EV_TIMESTAMP(e) ([e timestamp])
284 #else
285 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
286 #endif /* not gnustep */
288 /* This is a piece of code which is common to all the event handling
289    methods.  Maybe it should even be a function.  */
290 #define EV_TRAILER(e)                                         \
291   {                                                           \
292   XSETFRAME (emacs_event->frame_or_window, emacsframe);       \
293   if (e) emacs_event->timestamp = EV_TIMESTAMP (e);           \
294   n_emacs_events_pending++;                                   \
295   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);     \
296   EVENT_INIT (*emacs_event);                                  \
297   ns_send_appdefined (-1);                                    \
298   }
300 void x_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
302 /* TODO: get rid of need for these forward declarations */
303 static void ns_condemn_scroll_bars (struct frame *f);
304 static void ns_judge_scroll_bars (struct frame *f);
305 void x_set_frame_alpha (struct frame *f);
307 /* unused variables needed for compatibility reasons */
308 int x_use_underline_position_properties, x_underline_at_descent_line;
309 /* FIXME: figure out what to do with underline_minimum_offset. */
312 /* ==========================================================================
314     Utilities
316    ========================================================================== */
319 static Lisp_Object
320 append2 (Lisp_Object list, Lisp_Object item)
321 /* --------------------------------------------------------------------------
322    Utility to append to a list
323    -------------------------------------------------------------------------- */
325   Lisp_Object array[2];
326   array[0] = list;
327   array[1] = Fcons (item, Qnil);
328   return Fnconc (2, &array[0]);
332 void
333 ns_init_paths ()
334 /* --------------------------------------------------------------------------
335    Used to allow emacs to find its resources under Emacs.app
336    Called from emacs.c at startup.
337    -------------------------------------------------------------------------- */
339   NSBundle *bundle = [NSBundle mainBundle];
340   NSString *binDir = [bundle bundlePath], *resourceDir = [bundle resourcePath];
341   NSString *resourcePath, *resourcePaths;
342   NSRange range;
343   BOOL onWindows = NO; /* how do I determine this? */
344   NSString *pathSeparator = onWindows ? @";" : @":";
345   NSFileManager *fileManager = [NSFileManager defaultManager];
346   BOOL isDir;
347 /*NSLog (@"ns_init_paths: '%@'\n%@\n", [[NSBundle mainBundle] bundlePath], [[NSBundle mainBundle] resourcePath]); */
349   /* get bindir from base */
350   range = [resourceDir rangeOfString: @"Contents"];
351   if (range.location != NSNotFound)
352     {
353       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
354 #ifdef NS_IMPL_COCOA
355       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
356 #endif
357     }
359   /* the following based on Andrew Choi's init_mac_osx_environment () */
360   if (!getenv ("EMACSLOADPATH"))
361     {
362       NSArray *paths = [resourceDir stringsByAppendingPaths:
363                                   [NSArray arrayWithObjects:
364                                          @"site-lisp", @"lisp", @"leim", nil]];
365       NSEnumerator *pathEnum = [paths objectEnumerator];
366       resourcePaths = @"";
367       while (resourcePath = [pathEnum nextObject])
368         {
369           if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
370             if (isDir)
371               {
372                 if ([resourcePaths length] > 0)
373                   resourcePaths
374                     = [resourcePaths stringByAppendingString: pathSeparator];
375                 resourcePaths
376                   = [resourcePaths stringByAppendingString: resourcePath];
377               }
378         }
379       if ([resourcePaths length] > 0)
380         setenv ("EMACSLOADPATH", [resourcePaths UTF8String], 1);
381 /*NSLog (@"loadPath: '%s'\n", resourcePaths); */
382     }
384   if (!getenv ("EMACSPATH"))
385     {
386       NSArray *paths = [binDir stringsByAppendingPaths:
387                                   [NSArray arrayWithObjects: @"bin",
388                                                              @"lib-exec", nil]];
389       NSEnumerator *pathEnum = [paths objectEnumerator];
390       resourcePaths = @"";
391       while (resourcePath = [pathEnum nextObject])
392         {
393           if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
394             if (isDir)
395               {
396                 if ([resourcePaths length] > 0)
397                   resourcePaths
398                     = [resourcePaths stringByAppendingString: pathSeparator];
399                 resourcePaths
400                   = [resourcePaths stringByAppendingString: resourcePath];
401               }
402         }
403       if ([resourcePaths length] > 0)
404         setenv ("EMACSPATH", [resourcePaths UTF8String], 1);
405     }
407   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
408   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
409     {
410       if (isDir)
411         {
412           if (!getenv ("EMACSDATA"))
413             setenv ("EMACSDATA", [resourcePath UTF8String], 1);
414           if (!getenv ("EMACSDOC"))
415             setenv ("EMACSDOC", [resourcePath UTF8String], 1);
416         }
417     }
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);
561   ns_updating_frame = f;
562   [view lockFocus];
564 #ifdef NS_IMPL_GNUSTEP
565   uRect = NSMakeRect (0, 0, 0, 0);
566 #endif
570 static void
571 ns_update_window_begin (struct window *w)
572 /* --------------------------------------------------------------------------
573    Prepare for a grouped sequence of drawing calls
574    23: external (RIF) call; now split with and called after update_begin
575    -------------------------------------------------------------------------- */
577   struct frame *f = XFRAME (WINDOW_FRAME (w));
578   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
579   NSTRACE (ns_update_window_begin);
581   updated_window = w;
582   set_output_cursor (&w->cursor);
584   BLOCK_INPUT;
586   if (f == dpyinfo->mouse_face_mouse_frame)
587     {
588       /* Don't do highlighting for mouse motion during the update.  */
589       dpyinfo->mouse_face_defer = 1;
591         /* If the frame needs to be redrawn,
592            simply forget about any prior mouse highlighting.  */
593       if (FRAME_GARBAGED_P (f))
594         dpyinfo->mouse_face_window = Qnil;
596       /* (further code for mouse faces ifdef'd out in other terms elided) */
597     }
599   UNBLOCK_INPUT;
603 static void
604 ns_update_window_end (struct window *w, int cursor_on_p,
605                       int mouse_face_overwritten_p)
606 /* --------------------------------------------------------------------------
607    Finished a grouped sequence of drawing calls
608    23: external (RIF) call; now split with and called before update_window_end
609    -------------------------------------------------------------------------- */
611   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (XFRAME (w->frame));
613   /* note: this fn is nearly identical in all terms */
614   if (!w->pseudo_window_p)
615     {
616       BLOCK_INPUT;
618       if (cursor_on_p)
619         display_and_set_cursor (w, 1,
620                                 output_cursor.hpos, output_cursor.vpos,
621                                 output_cursor.x, output_cursor.y);
623       if (draw_window_fringes (w, 1))
624         x_draw_vertical_border (w);
626       UNBLOCK_INPUT;
627     }
629   /* If a row with mouse-face was overwritten, arrange for
630      frame_up_to_date to redisplay the mouse highlight.  */
631   if (mouse_face_overwritten_p)
632     {
633       dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
634       dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
635       dpyinfo->mouse_face_window = Qnil;
636     }
638   updated_window = NULL;
639   NSTRACE (update_window_end);
643 static void
644 ns_update_end (struct frame *f)
645 /* --------------------------------------------------------------------------
646    Finished a grouped sequence of drawing calls
647    23: external (RIF) call; now split with and called after update_window_end
648    -------------------------------------------------------------------------- */
650   NSView *view = FRAME_NS_VIEW (f);
652 /*   if (f == FRAME_NS_DISPLAY_INFO (f)->mouse_face_mouse_frame) */
653     FRAME_NS_DISPLAY_INFO (f)->mouse_face_defer = 0;
655   BLOCK_INPUT;
657 #ifdef NS_IMPL_GNUSTEP
658   /* trigger flush only in the rectangle we tracked as being drawn */
659   [view unlockFocusNeedsFlush: NO];
660 /*fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", uRect.origin.x, uRect.origin.y, uRect.size.width, uRect.size.height); */
661   [view lockFocusInRect: uRect];
662 #endif
664   [view unlockFocus];
665   [[view window] flushWindow];
667   UNBLOCK_INPUT;
668   ns_updating_frame = NULL;
669   NSTRACE (ns_update_end);
673 static void
674 ns_flush (struct frame *f)
675 /* --------------------------------------------------------------------------
676    23: external (RIF) call
677    NS impl is no-op since currently we flush in ns_update_end and elsewhere
678    -------------------------------------------------------------------------- */
680     NSTRACE (ns_flush);
684 static void
685 ns_focus (struct frame *f, NSRect *r, int n)
686 /* --------------------------------------------------------------------------
687    Internal: Focus on given frame.  During small local updates this is used to
688      draw, however during large updates, ns_update_begin and ns_update_end are
689      called to wrap the whole thing, in which case these calls are stubbed out.
690      Except, on GNUstep, we accumulate the rectangle being drawn into, because
691      the back end won't do this automatically, and will just end up flushing
692      the entire window.
693    -------------------------------------------------------------------------- */
695 //  NSTRACE (ns_focus);
696 #ifdef NS_IMPL_GNUSTEP
697   NSRect u;
698     if (n == 2)
699       u = NSUnionRect (r[0], r[1]);
700     else if (r)
701       u = *r;
702 #endif
703 /* static int c =0;
704    fprintf (stderr, "focus: %d", c++);
705    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
706    fprintf (stderr, "\n"); */
708   if (f != ns_updating_frame)
709     {
710       NSView *view = FRAME_NS_VIEW (f);
711       if (view != focus_view)
712         {
713           if (focus_view != NULL)
714             {
715               [focus_view unlockFocus];
716               [[focus_view window] flushWindow];
717 /*debug_lock--; */
718             }
720           if (view)
721 #ifdef NS_IMPL_GNUSTEP
722             r ? [view lockFocusInRect: u] : [view lockFocus];
723 #else
724             [view lockFocus];
725 #endif
726           focus_view = view;
727 /*if (view) debug_lock++; */
728         }
729 #ifdef NS_IMPL_GNUSTEP
730       else
731         {
732           /* more than one rect being drawn into */
733           if (view && r)
734             {
735               [view unlockFocus]; /* add prev rect to redraw list */
736               [view lockFocusInRect: u]; /* focus for draw in new rect */
737             }
738         }
739 #endif
740     }
741 #ifdef NS_IMPL_GNUSTEP
742   else
743     {
744       /* in batch mode, but in GNUstep must still track rectangles explicitly */
745       uRect = (r ? NSUnionRect (uRect, u) : [FRAME_NS_VIEW (f) visibleRect]);
746     }
747 #endif
749   /*23: clipping */
750   if (r)
751     {
752       [[NSGraphicsContext currentContext] saveGraphicsState];
753       if (n == 2)
754         NSRectClipList (r, 2);
755       else
756         NSRectClip (*r);
757       gsaved = YES;
758     }
762 static void
763 ns_unfocus (struct frame *f)
764 /* --------------------------------------------------------------------------
765      Internal: Remove focus on given frame
766    -------------------------------------------------------------------------- */
768 //  NSTRACE (ns_unfocus);
770   if (gsaved)
771     {
772       [[NSGraphicsContext currentContext] restoreGraphicsState];
773       gsaved = NO;
774     }
776   if (f != ns_updating_frame)
777     {
778       if (focus_view != NULL)
779         {
780           [focus_view unlockFocus];
781           [[focus_view window] flushWindow];
782           focus_view = NULL;
783 /*debug_lock--; */
784         }
785     }
789 static void
790 ns_clip_to_row (struct window *w, struct glyph_row *row, int area, BOOL gc)
791 /* --------------------------------------------------------------------------
792      23: Internal (but parallels other terms): Focus drawing on given row
793    -------------------------------------------------------------------------- */
795   struct frame *f = XFRAME (WINDOW_FRAME (w));
796   NSRect clip_rect;
797   int window_x, window_y, window_width;
799   window_box (w, area, &window_x, &window_y, &window_width, 0);
801   clip_rect.origin.x = window_x - FRAME_INTERNAL_BORDER_WIDTH (f);
802   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
803   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
804   clip_rect.size.width = window_width + 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
805   clip_rect.size.height = row->visible_height;
807   /* allow a full-height row at the top when requested
808      (used to draw fringe all the way through internal border area) */
809   if (gc && clip_rect.origin.y < 5)
810     {
811       clip_rect.origin.y -= FRAME_INTERNAL_BORDER_WIDTH (f);
812       clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
813     }
815   /* likewise at bottom */
816   if (gc &&
817       FRAME_PIXEL_HEIGHT (f) - (clip_rect.origin.y + clip_rect.size.height) < 5)
818     clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
820   ns_focus (f, &clip_rect, 1);
824 static void
825 ns_ring_bell ()
826 /* --------------------------------------------------------------------------
827      "Beep" routine
828    -------------------------------------------------------------------------- */
830   NSTRACE (ns_ring_bell);
831   if (visible_bell)
832     {
833       NSAutoreleasePool *pool;
834       struct frame *frame = SELECTED_FRAME ();
835       NSView *view;
837       BLOCK_INPUT;
838       pool = [[NSAutoreleasePool alloc] init];
840       view = FRAME_NS_VIEW (frame);
841       if (view != nil)
842         {
843           NSRect r, surr;
844           NSPoint dim = NSMakePoint (128, 128);
846           r = [view bounds];
847           r.origin.x += (r.size.width - dim.x) / 2;
848           r.origin.y += (r.size.height - dim.y) / 2;
849           r.size.width = dim.x;
850           r.size.height = dim.y;
851           /* XXX: cacheImageInRect under GNUstep does not account for
852              offset in x_set_window_size, so overestimate (4 fine on Cocoa) */
853           surr = NSInsetRect (r, -10, -10);
854           ns_focus (frame, &surr, 1);
855           [[view window] cacheImageInRect: surr];
856           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
857                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
858           NSRectFill (r);
859           [[view window] flushWindow];
860           ns_timeout (150000);
861           [[view window] restoreCachedImage];
862           [[view window] flushWindow];
863           ns_unfocus (frame);
864         }
865       [pool release];
866       UNBLOCK_INPUT;
867     }
868   else
869     {
870       NSBeep ();
871     }
875 static void
876 ns_reset_terminal_modes (struct terminal *terminal)
877 /*  Externally called as hook */
879   NSTRACE (ns_reset_terminal_modes);
882 static void
883 ns_set_terminal_modes (struct terminal *terminal)
884 /*  Externally called as hook */
886   NSTRACE (ns_set_terminal_modes);
891 /* ==========================================================================
893     Frame / window manager related functions
895    ========================================================================== */
898 static void
899 ns_raise_frame (struct frame *f)
900 /* --------------------------------------------------------------------------
901      Bring window to foreground and make it active
902    -------------------------------------------------------------------------- */
904   NSView *view = FRAME_NS_VIEW (f);
905   check_ns ();
906   BLOCK_INPUT;
907   [[view window] makeKeyAndOrderFront: NSApp];
908   UNBLOCK_INPUT;
912 static void
913 ns_lower_frame (struct frame *f)
914 /* --------------------------------------------------------------------------
915      Send window to back
916    -------------------------------------------------------------------------- */
918   NSView *view = FRAME_NS_VIEW (f);
919   check_ns ();
920   BLOCK_INPUT;
921   [[view window] orderBack: NSApp];
922   UNBLOCK_INPUT;
926 static void
927 ns_frame_raise_lower (struct frame *f, int raise)
928 /* --------------------------------------------------------------------------
929      External (hook)
930    -------------------------------------------------------------------------- */
932   NSTRACE (ns_frame_raise_lower);
934   if (raise)
935     ns_raise_frame (f);
936   else
937     ns_lower_frame (f);
941 static void
942 ns_frame_rehighlight (struct frame *frame)
943 /* --------------------------------------------------------------------------
944      External (hook): called on things like window switching within frame
945    -------------------------------------------------------------------------- */
947   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
948   struct frame *old_highlight = dpyinfo->x_highlight_frame;
950   NSTRACE (ns_frame_rehighlight);
951   if (dpyinfo->x_focus_frame)
952     {
953       dpyinfo->x_highlight_frame
954         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
955            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
956            : dpyinfo->x_focus_frame);
957       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
958         {
959           FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
960           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
961         }
962     }
963   else
964       dpyinfo->x_highlight_frame = 0;
966   if (dpyinfo->x_highlight_frame &&
967          dpyinfo->x_highlight_frame != old_highlight)
968     {
969       if (old_highlight)
970         {
971           x_update_cursor (old_highlight, 1);
972           x_set_frame_alpha (old_highlight);
973         }
974       if (dpyinfo->x_highlight_frame)
975         {
976           x_update_cursor (dpyinfo->x_highlight_frame, 1);
977           x_set_frame_alpha (dpyinfo->x_highlight_frame);
978         }
979     }
983 void
984 x_make_frame_visible (struct frame *f)
985 /* --------------------------------------------------------------------------
986      External: Show the window (X11 semantics)
987    -------------------------------------------------------------------------- */
989   NSTRACE (x_make_frame_visible);
990   /* XXX: at some points in past this was not needed, as the only place that
991      called this (frame.c:Fraise_frame ()) also called raise_lower;
992      if this ends up the case again, comment this out again. */
993   if (!FRAME_VISIBLE_P (f))
994     ns_raise_frame (f);
998 void
999 x_make_frame_invisible (struct frame *f)
1000 /* --------------------------------------------------------------------------
1001      External: Hide the window (X11 semantics)
1002    -------------------------------------------------------------------------- */
1004   NSView * view = FRAME_NS_VIEW (f);
1005   NSTRACE (x_make_frame_invisible);
1006   check_ns ();
1007   [[view window] orderOut: NSApp];
1011 void
1012 x_iconify_frame (struct frame *f)
1013 /* --------------------------------------------------------------------------
1014      External: Iconify window
1015    -------------------------------------------------------------------------- */
1017   NSView * view = FRAME_NS_VIEW (f);
1018   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1019   NSTRACE (x_iconify_frame);
1020   check_ns ();
1022   if (dpyinfo->x_highlight_frame == f)
1023     dpyinfo->x_highlight_frame = 0;
1025   if ([[view window] windowNumber] <= 0)
1026     {
1027       /* the window is still deferred.  Make it very small, bring it
1028          on screen and order it out. */
1029       NSRect s = { { 100, 100}, {0, 0} };
1030       NSRect t;
1031       t = [[view window] frame];
1032       [[view window] setFrame: s display: NO];
1033       [[view window] orderBack: NSApp];
1034       [[view window] orderOut: NSApp];
1035       [[view window] setFrame: t display: NO];
1036     }
1037   [[view window] miniaturize: NSApp];
1041 void
1042 x_destroy_window (struct frame *f)
1043 /* --------------------------------------------------------------------------
1044      External: Delete the window
1045    -------------------------------------------------------------------------- */
1047   NSView *view = FRAME_NS_VIEW (f);
1048   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1049   NSTRACE (x_destroy_window);
1050   check_ns ();
1052   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1054   BLOCK_INPUT;
1056   free_frame_menubar (f);
1058   if (FRAME_FACE_CACHE (f))
1059     free_frame_faces (f);
1061   if (f == dpyinfo->x_focus_frame)
1062     dpyinfo->x_focus_frame = 0;
1063   if (f == dpyinfo->x_highlight_frame)
1064     dpyinfo->x_highlight_frame = 0;
1065   if (f == dpyinfo->mouse_face_mouse_frame)
1066     {
1067       dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
1068       dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
1069       dpyinfo->mouse_face_window = Qnil;
1070       dpyinfo->mouse_face_deferred_gc = 0;
1071       dpyinfo->mouse_face_mouse_frame = 0;
1072     }
1074   xfree (f->output_data.ns);
1076   [[view window] close];
1077   [view release];
1079   ns_window_num--;
1080   UNBLOCK_INPUT;
1084 void
1085 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1086 /* --------------------------------------------------------------------------
1087      External: Position the window
1088    -------------------------------------------------------------------------- */
1090   NSScreen *screen;
1091   NSView *view = FRAME_NS_VIEW (f);
1093   NSTRACE (x_set_offset);
1095   BLOCK_INPUT;
1097   f->left_pos = xoff;
1098   f->top_pos = yoff;
1099 #ifdef NS_IMPL_GNUSTEP
1100   if (xoff < 100)
1101     f->left_pos = 100;  /* don't overlap menu */
1102 #endif
1103   if (view != nil && (screen = [[view window] screen]))
1104     [[view window] setFrameTopLeftPoint:
1105         NSMakePoint (SCREENMAXBOUND (f->left_pos),
1106                      SCREENMAXBOUND ([screen frame].size.height
1107                                      - NS_TOP_POS (f)))];
1108   UNBLOCK_INPUT;
1112 void
1113 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1114 /* --------------------------------------------------------------------------
1115      Adjust window pixel size based on given character grid size
1116      Impl is a bit more complex than other terms, need to do some
1117      internal clipping and also pay attention to screen constraints.
1118    -------------------------------------------------------------------------- */
1120   EmacsView *view = FRAME_NS_VIEW (f);
1121   EmacsToolbar *toolbar = [view toolbar];
1122   NSWindow *window = [view window];
1123   NSScreen *screen = [window screen];
1124   NSRect wr = [window frame];
1125   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1126   int pixelwidth, pixelheight;
1127   static int oldRows, oldCols, oldFontWidth, oldFontHeight;
1128   static int oldTB;
1129   static struct frame *oldF;
1131   NSTRACE (x_set_window_size);
1133   if (view == nil ||
1134       (f == oldF
1135        && rows == oldRows && cols == oldCols
1136        && oldFontWidth == FRAME_COLUMN_WIDTH (f)
1137        && oldFontHeight == FRAME_LINE_HEIGHT (f)
1138        && oldTB == tb))
1139     return;
1141 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1143   BLOCK_INPUT;
1145   check_frame_size (f, &rows, &cols);
1146   oldF = f;
1147   oldRows = rows;
1148   oldCols = cols;
1149   oldFontWidth = FRAME_COLUMN_WIDTH (f);
1150   oldFontHeight = FRAME_LINE_HEIGHT (f);
1151   oldTB = tb;
1153   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1154   compute_fringe_widths (f, 0);
1156   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1157   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1159   /* If we have a change in toolbar display, calculate height */
1160   if (tb)
1161     /* XXX: GNUstep has not yet implemented the first method below, added
1162            in Panther, however the second is incorrect under Cocoa. */
1163 #ifdef NS_IMPL_GNUSTEP
1164     FRAME_NS_TOOLBAR_HEIGHT (f)
1165       = NSHeight ([NSWindow frameRectForContentRect: NSMakeRect (0, 0, 0, 0)
1166                             styleMask: [window styleMask]])
1167         - FRAME_NS_TITLEBAR_HEIGHT (f);
1168 #else
1169     FRAME_NS_TOOLBAR_HEIGHT (f) = 32;
1170       /* actually get wrong result here if toolbar not yet displayed
1171          NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1172          - FRAME_NS_TITLEBAR_HEIGHT (f); */
1173 #endif
1174   else
1175     FRAME_NS_TOOLBAR_HEIGHT (f) = 0;
1177   wr.size.width = pixelwidth + f->border_width;
1178   wr.size.height = pixelheight + FRAME_NS_TITLEBAR_HEIGHT (f) 
1179                   + FRAME_NS_TOOLBAR_HEIGHT (f);
1181   /* constrain to screen if we can */
1182   if (screen)
1183     {
1184       NSSize sz = [screen visibleFrame].size;
1185       NSSize ez = { wr.size.width - sz.width, wr.size.height - sz.height };
1186       if (ez.width > 0)
1187         {
1188           int cr = ez.width / FRAME_COLUMN_WIDTH (f) + 1;
1189           cols -= cr;
1190           oldCols = cols;
1191           wr.size.width -= cr * FRAME_COLUMN_WIDTH (f);
1192           pixelwidth -= cr * FRAME_COLUMN_WIDTH (f);
1193         }
1194       if (ez.height > 0)
1195         {
1196           int rr = ez.height / FRAME_LINE_HEIGHT (f) + 1;
1197           rows -= rr;
1198           oldRows = rows;
1199           wr.size.height -= rr * FRAME_LINE_HEIGHT (f);
1200           pixelheight -= rr * FRAME_LINE_HEIGHT (f);
1201         }
1202       wr.origin.x = f->left_pos;
1203       wr.origin.y = [screen frame].size.height - NS_TOP_POS (f)
1204         - wr.size.height;
1205     }
1207   [view setRows: rows andColumns: cols];
1208   [window setFrame: wr display: YES];
1210 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1212   /* This is a trick to compensate for Emacs' managing the scrollbar area
1213      as a fixed number of standard character columns.  Instead of leaving
1214      blank space for the extra, we chopped it off above.  Now for
1215      left-hand scrollbars, we shift all rendering to the left by the
1216      difference between the real width and Emacs' imagined one.  For
1217      right-hand bars, don't worry about it since the extra is never used.
1218      (Obviously doesn't work for vertically split windows tho..) */
1219   NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1220     ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1221                   - NS_SCROLL_BAR_WIDTH (f), 0)
1222     : NSMakePoint (0, 0);
1223   [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1224   [view setBoundsOrigin: origin];
1226   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1227   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1228   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1229 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1231   mark_window_cursors_off (XWINDOW (f->root_window));
1232   cancel_mouse_face (f);
1234   UNBLOCK_INPUT;
1239 /* ==========================================================================
1241     Color management
1243    ========================================================================== */
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     }
1301   color_table->colors[idx] = color;
1302   [color retain];
1303 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1304   return idx;
1308 void
1309 ns_free_indexed_color (unsigned long idx, struct frame *f)
1311   struct ns_color_table *color_table;
1312   NSColor *color;
1313   NSNumber *index;
1315   if (!f)
1316     return;
1318   color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1320   if (idx <= 0 || idx >= color_table->size) {
1321     message1("ns_free_indexed_color: Color index out of range.\n");
1322     return;
1323   }
1325   index = [NSNumber numberWithUnsignedInt: idx];
1326   if ([color_table->empty_indices containsObject: index]) {
1327     message1("ns_free_indexed_color: attempt to free already freed color.\n");
1328     return;
1329   }
1331   color = color_table->colors[idx];
1332   [color release];
1333   color_table->colors[idx] = nil;
1334   [color_table->empty_indices addObject: [NSNumber numberWithUnsignedInt: idx]];
1335 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1339 static int
1340 ns_get_color (const char *name, NSColor **col)
1341 /* --------------------------------------------------------------------------
1342      Parse a color name
1343 /* --------------------------------------------------------------------------
1344 /* On *Step, we recognize several color formats, in addition to a catalog
1345    of colors found in the file Emacs.clr. Color formats include:
1346    - #rrggbb or RGBrrggbb where rr, gg, bb specify red, green and blue in hex
1347    - ARGBaarrggbb is similar, with aa being the alpha channel (FF = opaque)
1348    - HSVhhssvv and AHSVaahhssvv (or HSB/AHSB) are similar for hue, saturation,
1349      value;
1350    - CMYKccmmyykk is similar for cyan, magenta, yellow, black. */
1352   NSColor * new = nil;
1353   const char *hex = NULL;
1354   enum { rgb, argb, hsv, ahsv, cmyk, gray } color_space;
1355   NSString *nsname = [NSString stringWithUTF8String: name];
1357 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1358   BLOCK_INPUT;
1360   if ([nsname isEqualToString: @"ns_selection_color"])
1361     {
1362       nsname = ns_selection_color;
1363       name = [ns_selection_color UTF8String];
1364     }
1366   if (name[0] == '0' || name[0] == '1' || name[0] == '.')
1367     {
1368       /* RGB decimal */
1369       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1370       float r, g, b;
1371       [scanner scanFloat: &r];
1372       [scanner scanFloat: &g];
1373       [scanner scanFloat: &b];
1374       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1375       UNBLOCK_INPUT;
1376       return 0;
1377     }
1379   /* 23: FIXME: emacs seems to downcase everything before passing it here,
1380       which we can work around, except for GRAY, since gray##, where ## is
1381       decimal between 0 and 99, is also an X11 colorname. */
1382   if (name[0] == '#')             /* X11 format */
1383     {
1384       hex = name + 1;
1385       color_space = rgb;
1386     }
1387   else if (!memcmp (name, "RGB", 3) || !memcmp (name, "rgb", 3))
1388     {
1389       hex = name + 3;
1390       color_space = rgb;
1391     }
1392   else if (!memcmp (name, "ARGB", 4) || !memcmp (name, "argb", 4))
1393     {
1394       hex = name + 4;
1395       color_space = argb;
1396     }
1397   else if (!memcmp (name, "HSV", 3) || !memcmp (name, "hsv", 3) || 
1398            !memcmp (name, "HSB", 3) || !memcmp (name, "hsb", 3))
1399     {
1400       hex = name + 3;
1401       color_space = hsv;
1402     }
1403   else if (!memcmp (name, "AHSV", 4) || !memcmp (name, "ahsv", 4) ||
1404            !memcmp (name, "AHSB", 4) || !memcmp (name, "ahsb", 4))
1405     {
1406       hex = name + 4;
1407       color_space = ahsv;
1408     }
1409   else if (!memcmp (name, "CMYK", 4) || !memcmp (name, "cmyk", 4))
1410     {
1411       hex = name + 4;
1412       color_space = cmyk;
1413     }
1414   else if (!memcmp (name, "GRAY", 4) /*|| !memcmp (name, "gray", 4)*/)
1415     {
1416       hex = name + 4;
1417       color_space = gray;
1418     }
1420   /* Direct colors (hex values) */
1421   if (hex)
1422     {
1423       unsigned long long color = 0;
1424       if (sscanf (hex, "%x", &color))
1425         {
1426           float f1, f2, f3, f4;
1427           /* Assume it's either 1 byte or 2 per channel... */
1428           if (strlen(hex) > 8) {
1429             f1 = ((color >> 48) & 0xffff) / 65535.0;
1430             f2 = ((color >> 32) & 0xffff) / 65535.0;
1431             f3 = ((color >> 16) & 0xffff) / 65535.0;
1432             f4 = ((color      ) & 0xffff) / 65535.0;
1433           } else {
1434             f1 = ((color >> 24) & 0xff) / 255.0;
1435             f2 = ((color >> 16) & 0xff) / 255.0;
1436             f3 = ((color >>  8) & 0xff) / 255.0;
1437             f4 = ((color      ) & 0xff) / 255.0;
1438           }
1440           switch (color_space)
1441             {
1442             case rgb:
1443               *col = [NSColor colorWithCalibratedRed: f2
1444                                                green: f3
1445                                                 blue: f4
1446                                                alpha: 1.0];
1447               break;
1448             case argb:
1449               *col = [NSColor colorWithCalibratedRed: f2
1450                                                green: f3
1451                                                 blue: f4
1452                                                alpha: f1];
1453               break;
1454             case hsv:
1455               *col = [NSColor colorWithCalibratedHue: f2
1456                                           saturation: f3
1457                                           brightness: f4
1458                                                alpha: 1.0];
1459               break;
1460             case ahsv:
1461               *col = [NSColor colorWithCalibratedHue: f2
1462                                           saturation: f3
1463                                           brightness: f4
1464                                                alpha: f1];
1465               break;
1466             case gray:
1467               *col = [NSColor colorWithCalibratedWhite: f3 alpha: f4];
1468               break;
1469             case cmyk:
1470               *col = [NSColor colorWithDeviceCyan: f1
1471                                           magenta: f2
1472                                            yellow: f3
1473                                             black: f4
1474                                             alpha: 1.0];
1475               break;
1476             }
1477           *col = [*col colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1478           UNBLOCK_INPUT;
1479           return 0;
1480         }
1481     }
1483   /* Otherwise, color is expected to be from a list */
1484   {
1485     NSEnumerator *lenum, *cenum;
1486     NSString *name;
1487     NSColorList *clist;
1489 #ifdef NS_IMPL_GNUSTEP
1490     /* XXX: who is wrong, the requestor or the implementation? */
1491     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1492         == NSOrderedSame)
1493       nsname = @"highlightColor";
1494 #endif
1496     lenum = [[NSColorList availableColorLists] objectEnumerator];
1497     while ( (clist = [lenum nextObject]) && new == nil)
1498       {
1499         cenum = [[clist allKeys] objectEnumerator];
1500         while ( (name = [cenum nextObject]) && new == nil )
1501           {
1502             if ([name compare: nsname
1503                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1504               new = [clist colorWithKey: name];
1505           }
1506       }
1507   }
1509   if ( new )
1510     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1511 /*     else
1512        NSLog (@"Failed to find color '%@'", nsname); */
1513   UNBLOCK_INPUT;
1514   return new ? 0 : 1;
1518 static NSColor *
1519 ns_get_color_default (const char *name, NSColor *dflt)
1520 /* --------------------------------------------------------------------------
1521      Parse a color or use a default value
1522    -------------------------------------------------------------------------- */
1524   NSColor * col;
1526   if (ns_get_color (name, &col))
1527     return dflt;
1528   else
1529     return col;
1534 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1535 /* --------------------------------------------------------------------------
1536      Convert a Lisp string object to a NS color
1537    -------------------------------------------------------------------------- */
1539   NSTRACE (ns_lisp_to_color);
1540   if (STRINGP (color))
1541     return ns_get_color (SDATA (color), col);
1542   else if (SYMBOLP (color))
1543     return ns_get_color (SDATA (SYMBOL_NAME (color)), col);
1544   return 1;
1548 Lisp_Object
1549 ns_color_to_lisp (NSColor *col)
1550 /* --------------------------------------------------------------------------
1551      Convert a color to a lisp string with the RGB equivalent
1552    -------------------------------------------------------------------------- */
1554   float red, green, blue, alpha, gray;
1555   char buf[1024];
1556   const char *str;
1557   NSTRACE (ns_color_to_lisp);
1559   BLOCK_INPUT;
1560   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1562       if ((str =[[col colorNameComponent] UTF8String]))
1563         {
1564           UNBLOCK_INPUT;
1565           return build_string ((char *)str);
1566         }
1568     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1569         getRed: &red green: &green blue: &blue alpha: &alpha];
1570   if (red ==green && red ==blue)
1571     {
1572       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1573             getWhite: &gray alpha: &alpha];
1574       snprintf (buf, sizeof (buf), "GRAY%02.2lx%02.2lx",
1575                lrint (gray * 0xff), lrint (alpha * 0xff));
1576       UNBLOCK_INPUT;
1577       return build_string (buf);
1578     }
1580   snprintf (buf, sizeof (buf), "ARGB%02.2lx%02.2lx%02.2lx%02.2lx",
1581             lrint (alpha*0xff),
1582             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1584   UNBLOCK_INPUT;
1585   return build_string (buf);
1590 ns_defined_color (struct frame *f, char *name, XColor *color_def, int alloc,
1591                   char makeIndex)
1592 /* --------------------------------------------------------------------------
1593    23:   Return 1 if named color found, and set color_def rgb accordingly.
1594          If makeIndex and alloc are nonzero put the color in the color_table,
1595          and set color_def pixel to the resulting index.
1596          If makeIndex is zero, set color_def pixel to ARGB.
1597          Return 0 if not found
1598    -------------------------------------------------------------------------- */
1600   NSColor *temp;
1601   float r, g, b, a;
1602   int notFound = ns_get_color (name, &temp);
1604   NSTRACE (ns_defined_color);
1606   if (notFound)
1607     return 0;
1609   if (makeIndex && alloc)
1610       color_def->pixel = ns_index_color(temp, f); /* [temp retain]; */
1612   [temp getRed: &r green: &g blue: &b alpha: &a];
1613   color_def->red   = r * 256;
1614   color_def->green = g * 256;
1615   color_def->blue  = b * 256;
1617   if (!makeIndex)
1618     color_def->pixel
1619       = ARGB_TO_ULONG((int)(a*256),
1620                       color_def->red, color_def->green, color_def->blue);
1622   return 1;
1626 unsigned long
1627 ns_get_rgb_color (struct frame *f, float r, float g, float b, float a)
1628 /* --------------------------------------------------------------------------
1629     return an autoreleased RGB color
1630    -------------------------------------------------------------------------- */
1632 /*static int c = 1; fprintf (stderr, "color request %d\n", c++); */
1633   if (r < 0.0) r = 0.0;
1634   else if (r > 1.0) r = 1.0;
1635   if (g < 0.0) g = 0.0;
1636   else if (g > 1.0) g = 1.0;
1637   if (b < 0.0) b = 0.0;
1638   else if (b > 1.0) b = 1.0;
1639   if (a < 0.0) a = 0.0;
1640   else if (a > 1.0) a = 1.0;
1641   return (unsigned long) ns_index_color(
1642     [NSColor colorWithCalibratedRed: r green: g blue: b alpha: a], f);
1646 void
1647 x_set_frame_alpha (struct frame *f)
1648 /* --------------------------------------------------------------------------
1649      change the entire-frame transparency
1650    -------------------------------------------------------------------------- */
1652   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1653   EmacsView *view = FRAME_NS_VIEW (f);
1654   double alpha = 1.0;
1655   double alpha_min = 1.0;
1657   if (dpyinfo->x_highlight_frame == f)
1658     alpha = f->alpha[0];
1659   else
1660     alpha = f->alpha[1];
1662   if (FLOATP (Vframe_alpha_lower_limit))
1663     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1664   else if (INTEGERP (Vframe_alpha_lower_limit))
1665     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1667   if (alpha < 0.0)
1668     return;
1669   else if (1.0 < alpha)
1670     alpha = 1.0;
1671   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1672     alpha = alpha_min;
1674 #ifdef NS_IMPL_COCOA
1675   [[view window] setAlphaValue: alpha];
1676 #endif
1680 /* ==========================================================================
1682     Mouse handling
1684    ========================================================================== */
1687 void
1688 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1689 /* --------------------------------------------------------------------------
1690      Programmatically reposition mouse pointer in pixel coordinates
1691    -------------------------------------------------------------------------- */
1693   NSTRACE (x_set_mouse_pixel_position);
1694   ns_raise_frame (f);
1695 #if 0
1696   /* FIXME: this does not work, and what about GNUstep? */
1697 #ifdef NS_IMPL_COCOA
1698   [FRAME_NS_VIEW (f) lockFocus];
1699   PSsetmouse ((float)pix_x, (float)pix_y);
1700   [FRAME_NS_VIEW (f) unlockFocus];
1701 #endif
1702 #endif
1706 void
1707 x_set_mouse_position (struct frame *f, int h, int v)
1708 /* --------------------------------------------------------------------------
1709      Programmatically reposition mouse pointer in character coordinates
1710    -------------------------------------------------------------------------- */
1712   int pix_x, pix_y;
1714   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1715   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1717   if (pix_x < 0) pix_x = 0;
1718   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1720   if (pix_y < 0) pix_y = 0;
1721   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1723   x_set_mouse_pixel_position (f, pix_x, pix_y);
1727 static int
1728 note_mouse_movement (struct frame *frame, float x, float y)
1729 /*   ------------------------------------------------------------------------
1730      Called by EmacsView on mouseMovement events.  Passes on
1731      to emacs mainstream code if we moved off of a rect of interest
1732      known as last_mouse_glyph.
1733      ------------------------------------------------------------------------ */
1735 //  NSTRACE (note_mouse_movement);
1737   XSETFRAME (last_mouse_motion_frame, frame);
1739   /* Note, this doesn't get called for enter/leave, since we don't have a
1740      position.  Those are taken care of in the corresponding NSView methods. */
1742   /* has movement gone beyond last rect we were tracking? */
1743   if (x < last_mouse_glyph.origin.x ||
1744       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1745       y < last_mouse_glyph.origin.y ||
1746       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1747     {
1748       frame->mouse_moved = 1;
1749       note_mouse_highlight (frame, x, y);
1750       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1751       return 1;
1752     }
1754   return 0;
1758 static void
1759 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1760                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1761                    unsigned long *time)
1762 /* --------------------------------------------------------------------------
1763     External (hook): inform emacs about mouse position and hit parts.
1764     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1765     x & y should be position in the scrollbar (the whole bar, not the handle)
1766     and length of scrollbar respectively
1767    -------------------------------------------------------------------------- */
1769   id view;
1770   NSPoint position;
1771   int xchar, ychar;
1772   Lisp_Object frame, tail;
1773   struct frame *f;
1774   struct ns_display_info *dpyinfo;
1776   NSTRACE (ns_mouse_position);
1778   if (*fp == NULL)
1779     {
1780       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1781       return;
1782     }
1784   dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1786   BLOCK_INPUT;
1788   if (last_mouse_scroll_bar != nil && insist == 0)
1789     {
1790       /* TODO: we do not use this path at the moment because drag events will
1791            go directly to the EmacsScroller.  Leaving code in for now. */
1792       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1793                                               x: x y: y];
1794       if (time) *time = last_mouse_movement_time;
1795       last_mouse_scroll_bar = nil;
1796     }
1797   else
1798     {
1799       /* Clear the mouse-moved flag for every frame on this display.  */
1800       FOR_EACH_FRAME (tail, frame)
1801         if (FRAME_NS_P (XFRAME (frame))
1802             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1803           XFRAME (frame)->mouse_moved = 0;
1805       last_mouse_scroll_bar = nil;
1806       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1807         f = last_mouse_frame;
1808       else
1809         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1810                                     : SELECTED_FRAME ();
1812       if (f && f->output_data.ns)  /* TODO: 2nd check no longer needed? */
1813         {
1814           view = FRAME_NS_VIEW (*fp);
1816           position = [[view window] mouseLocationOutsideOfEventStream];
1817           position = [view convertPoint: position fromView: nil];
1818           remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1819 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1821           if (bar_window) *bar_window = Qnil;
1822           if (part) *part = 0; /*scroll_bar_handle; */
1824           if (x) XSETINT (*x, lrint (position.x));
1825           if (y) XSETINT (*y, lrint (position.y));
1826           if (time) *time = last_mouse_movement_time;
1827           *fp = f;
1828         }
1829     }
1831   UNBLOCK_INPUT;
1835 static void
1836 ns_frame_up_to_date (struct frame *f)
1837 /* --------------------------------------------------------------------------
1838     External (hook): Fix up mouse highlighting right after a full update.
1839     Some highlighting was deferred if GC was happening during
1840     note_mouse_highlight (), while other highlighting was deferred for update.
1841    -------------------------------------------------------------------------- */
1843   NSTRACE (ns_frame_up_to_date);
1845   if (FRAME_NS_P (f))
1846     {
1847       struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1848       if ((dpyinfo->mouse_face_deferred_gc||f ==dpyinfo->mouse_face_mouse_frame)
1849       /*&& dpyinfo->mouse_face_mouse_frame*/)
1850         {
1851           BLOCK_INPUT;
1852           if (dpyinfo->mouse_face_mouse_frame)
1853             note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
1854                                   dpyinfo->mouse_face_mouse_x,
1855                                   dpyinfo->mouse_face_mouse_y);
1856           dpyinfo->mouse_face_deferred_gc = 0;
1857           UNBLOCK_INPUT;
1858         }
1859     }
1863 void
1864 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1865 /* --------------------------------------------------------------------------
1866     External (RIF): set frame mouse pointer type.
1867    -------------------------------------------------------------------------- */
1869   NSTRACE (ns_define_frame_cursor);
1870   if (FRAME_POINTER_TYPE (f) != cursor)
1871     {
1872       EmacsView *view = FRAME_NS_VIEW (f);
1873       FRAME_POINTER_TYPE (f) = cursor;
1874       [[view window] invalidateCursorRectsForView: view];
1875     }
1880 /* ==========================================================================
1882     Keyboard handling
1884    ========================================================================== */
1887 static unsigned
1888 ns_convert_key (unsigned code)
1889 /* --------------------------------------------------------------------------
1890     Internal call used by NSView-keyDown.
1891    -------------------------------------------------------------------------- */
1893   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1894                                 / sizeof (convert_ns_to_X_keysym[0]));
1895   unsigned keysym;
1896   /* An array would be faster, but less easy to read. */
1897   for (keysym = 0; keysym < last_keysym; keysym += 2)
1898     if (code == convert_ns_to_X_keysym[keysym])
1899       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1900   return 0;
1901 /* if decide to use keyCode and Carbon table, use this line:
1902      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1906 char *
1907 x_get_keysym_name (int keysym)
1908 /* --------------------------------------------------------------------------
1909     Called by keyboard.c.  Not sure if the return val is important, except
1910     that it be unique.
1911    -------------------------------------------------------------------------- */
1913   static char value[16];
1914   NSTRACE (x_get_keysym_name);
1915   sprintf (value, "%d", keysym);
1916   return value;
1921 /* ==========================================================================
1923     Block drawing operations
1925    ========================================================================== */
1928 static void
1929 ns_redraw_scroll_bars (struct frame *f)
1931   int i;
1932   id view;
1933   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1934   NSTRACE (ns_judge_scroll_bars);
1935   for (i =[subviews count]-1; i >= 0; i--)
1936     {
1937       view = [subviews objectAtIndex: i];
1938       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1939       [view display];
1940     }
1944 void
1945 ns_clear_frame (struct frame *f)
1946 /* --------------------------------------------------------------------------
1947       External (hook): Erase the entire frame
1948    -------------------------------------------------------------------------- */
1950   NSView *view = FRAME_NS_VIEW (f);
1951   NSRect r;
1953   NSTRACE (ns_clear_frame);
1954   if (ns_in_resize)
1955     return;
1957  /* comes on initial frame because we have
1958     after-make-frame-functions = select-frame */
1959  if (!FRAME_DEFAULT_FACE (f))
1960    return;
1962   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
1964   output_cursor.hpos = output_cursor.vpos = 0;
1965   output_cursor.x = -1;
1967   r = [view bounds];
1969   BLOCK_INPUT;
1970   ns_focus (f, &r, 1);
1971   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
1972   NSRectFill (r);
1973   ns_unfocus (f);
1975 #ifdef NS_IMPL_COCOA
1976   [[view window] display];  /* redraw resize handle */
1977 #endif
1979   /* as of 2006/11 or so this is now needed */
1980   ns_redraw_scroll_bars (f);
1981   UNBLOCK_INPUT;
1985 void
1986 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
1987 /* --------------------------------------------------------------------------
1988    23: External (RIF):  Clear section of frame
1989    -------------------------------------------------------------------------- */
1991   NSRect r = NSMakeRect (x, y, width, height);
1992   NSView *view = FRAME_NS_VIEW (f);
1993   struct face *face = FRAME_DEFAULT_FACE (f);
1995   if (!view || !face)
1996     return;
1998   NSTRACE (ns_clear_frame_area);
2000   r = NSIntersectionRect (r, [view frame]);
2001   ns_focus (f, &r, 1);
2002   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2004 #ifdef NS_IMPL_COCOA
2005   {
2006     /* clip out the resize handle */
2007     NSWindow *window = [FRAME_NS_VIEW (f) window];
2008     NSRect ir
2009       = [view convertRect: ns_resize_handle_rect (window) fromView: nil];
2011     ir = NSIntersectionRect (r, ir);
2012     if (NSIsEmptyRect (ir))
2013       {
2014 #endif
2016   NSRectFill (r);
2018 #ifdef NS_IMPL_COCOA
2019       }
2020     else
2021       {
2022         NSRect r1 = r, r2 = r; /* upper and lower non-intersecting */
2023         r1.size.height -= ir.size.height;
2024         r2.origin.y += r1.size.height;
2025         r2.size.width -= ir.size.width;
2026         r2.size.height = ir.size.height;
2027         NSRectFill (r1);
2028         NSRectFill (r2);
2029       }
2030   }
2031 #endif
2033   ns_unfocus (f);
2034   return;
2038 static void
2039 ns_scroll_run (struct window *w, struct run *run)
2040 /* --------------------------------------------------------------------------
2041    23: External (RIF):  Insert or delete n lines at line vpos
2042    -------------------------------------------------------------------------- */
2044   struct frame *f = XFRAME (w->frame);
2045   int x, y, width, height, from_y, to_y, bottom_y;
2047   NSTRACE (ns_scroll_run);
2049   /* begin copy from other terms */
2050   /* Get frame-relative bounding box of the text display area of W,
2051      without mode lines.  Include in this box the left and right
2052      fringe of W.  */
2053   window_box (w, -1, &x, &y, &width, &height);
2055   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2056   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2057   bottom_y = y + height;
2059   if (to_y < from_y)
2060     {
2061       /* Scrolling up.  Make sure we don't copy part of the mode
2062          line at the bottom.  */
2063       if (from_y + run->height > bottom_y)
2064         height = bottom_y - from_y;
2065       else
2066         height = run->height;
2067     }
2068   else
2069     {
2070       /* Scolling down.  Make sure we don't copy over the mode line.
2071          at the bottom.  */
2072       if (to_y + run->height > bottom_y)
2073         height = bottom_y - to_y;
2074       else
2075         height = run->height;
2076     }
2077   /* end copy from other terms */
2079   if (height == 0)
2080       return;
2082   BLOCK_INPUT;
2084   updated_window = w;
2085   x_clear_cursor (w);
2087   {
2088     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2089     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2090     NSPoint dstOrigin = NSMakePoint (x, to_y);
2092     ns_focus (f, &dstRect, 1);
2093     NSCopyBits (0, srcRect , dstOrigin);
2094     ns_unfocus (f);
2095   }
2097   UNBLOCK_INPUT;
2101 static void
2102 ns_after_update_window_line (struct glyph_row *desired_row)
2103 /* --------------------------------------------------------------------------
2104    23: External (RIF): preparatory to fringe update after text was updated
2105    -------------------------------------------------------------------------- */
2107   struct window *w = updated_window;
2108   struct frame *f;
2109   int width, height;
2111   NSTRACE (ns_after_update_window_line);
2113   /* begin copy from other terms */
2114   xassert (w);
2116   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2117     desired_row->redraw_fringe_bitmaps_p = 1;
2119   /* When a window has disappeared, make sure that no rest of
2120      full-width rows stays visible in the internal border.
2121      Under NS this is drawn inside the fringes. */
2122   if (windows_or_buffers_changed
2123       && (f = XFRAME (w->frame),
2124           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2125           width != 0)
2126       && (height = desired_row->visible_height,
2127           height > 0))
2128     {
2129       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2131       /* Internal border is drawn below the tool bar.  */
2132       if (WINDOWP (f->tool_bar_window)
2133           && w == XWINDOW (f->tool_bar_window))
2134         y -= width;
2135       /* end copy from other terms */
2137       BLOCK_INPUT;
2138       if (!desired_row->full_width_p)
2139         {
2140           int x1 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2141             + WINDOW_LEFT_FRINGE_WIDTH (w);
2142           int x2 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2143             + FRAME_PIXEL_WIDTH (f) - NS_SCROLL_BAR_WIDTH (f)
2144             - WINDOW_RIGHT_FRINGE_WIDTH (w)
2145             - FRAME_INTERNAL_BORDER_WIDTH (f);
2146           ns_clear_frame_area (f, x1, y, width, height);
2147           ns_clear_frame_area (f, x2, y, width, height);
2148         }
2149       UNBLOCK_INPUT;
2150     }
2154 static void
2155 ns_shift_glyphs_for_insert (struct frame *f,
2156                            int x, int y, int width, int height,
2157                            int shift_by)
2158 /* --------------------------------------------------------------------------
2159    23: External (RIF): copy an area horizontally, don't worry about clearing src
2160    -------------------------------------------------------------------------- */
2162   NSRect srcRect = NSMakeRect (x, y, width, height);
2163   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2164   NSPoint dstOrigin = dstRect.origin;
2166   NSTRACE (ns_shift_glyphs_for_insert);
2168   ns_focus (f, &dstRect, 1);
2169   NSCopyBits (0, srcRect, dstOrigin);
2170   ns_unfocus (f);
2175 /* ==========================================================================
2177     Character encoding and metrics
2179    ========================================================================== */
2182 static inline void
2183 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2184 /* --------------------------------------------------------------------------
2185    23:  External (RIF); compute left/right overhang of whole string and set in s
2186    -------------------------------------------------------------------------- */
2188   struct face *face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2189   struct font *font = s->font; /*face->font; */
2191   if (s->char2b)
2192     {
2193       struct font_metrics metrics;
2194       unsigned int codes[2];
2195       codes[0] = *(s->char2b);
2196       codes[1] = *(s->char2b + s->nchars - 1);
2198       font->driver->text_extents (font, codes, 2, &metrics);
2199       s->left_overhang = -metrics.lbearing;
2200       s->right_overhang
2201         = metrics.rbearing > metrics.width
2202         ? metrics.rbearing - metrics.width : 0;
2203     }
2204   else
2205     {
2206       s->left_overhang = 0;
2207       s->right_overhang = ((struct nsfont_info *)font)->ital ?
2208         FONT_HEIGHT (font) * 0.2 : 0;
2209     }
2214 /* ==========================================================================
2216     Fringe and cursor drawing
2218    ========================================================================== */
2221 extern int max_used_fringe_bitmap;
2222 static void
2223 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2224                       struct draw_fringe_bitmap_params *p)
2225 /* --------------------------------------------------------------------------
2226    23: External (RIF); fringe-related
2227    -------------------------------------------------------------------------- */
2229   struct frame *f = XFRAME (WINDOW_FRAME (w));
2230   struct face *face = p->face;
2231   int rowY;
2232   static EmacsImage **bimgs = NULL;
2233   static int nBimgs = 0;
2234   /* NS-specific: move internal border inside fringe */
2235   int x = p->bx < 0 ? p->x : p->bx;
2236   int wd = p->bx < 0 ? p->wd : p->nx;
2237   BOOL fringeOnVeryLeft
2238     = x - WINDOW_LEFT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w)
2239       - FRAME_INTERNAL_BORDER_WIDTH (f) < 10;
2240   BOOL fringeOnVeryRight
2241     = FRAME_PIXEL_WIDTH (f) - x - wd - FRAME_INTERNAL_BORDER_WIDTH (f)
2242       - WINDOW_RIGHT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w) < 10;
2243   int xAdjust = FRAME_INTERNAL_BORDER_WIDTH (f) *
2244     (fringeOnVeryLeft ? -1 : (fringeOnVeryRight ? 1 : 0));
2246   /* grow bimgs if needed */
2247   if (nBimgs < max_used_fringe_bitmap)
2248     {
2249       EmacsImage **newBimgs
2250         = xmalloc (max_used_fringe_bitmap * sizeof (EmacsImage *));
2251       bzero (newBimgs, max_used_fringe_bitmap * sizeof (EmacsImage *));
2253       if (nBimgs)
2254         {
2255           bcopy (bimgs, newBimgs, nBimgs * sizeof (EmacsImage *));
2256           xfree (bimgs);
2257         }
2259       bimgs = newBimgs;
2260       nBimgs = max_used_fringe_bitmap;
2261     }
2263   /* Must clip because of partially visible lines.  */
2264   rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2265   if (p->y < rowY)
2266     {
2267       /* Adjust position of "bottom aligned" bitmap on partially
2268          visible last row.  */
2269       int oldY = row->y;
2270       int oldVH = row->visible_height;
2271       row->visible_height = p->h;
2272       row->y -= rowY - p->y;
2273       ns_clip_to_row (w, row, -1, NO);
2274       row->y = oldY;
2275       row->visible_height = oldVH;
2276     }
2277   else
2278     ns_clip_to_row (w, row, -1, YES);
2280   if (p->bx >= 0 && !p->overlay_p)
2281     {
2282       int yAdjust = rowY - FRAME_INTERNAL_BORDER_WIDTH (f) < 5 ?
2283         -FRAME_INTERNAL_BORDER_WIDTH (f) : 0;
2284       int yIncr = FRAME_PIXEL_HEIGHT (f) - (p->by+yAdjust + p->ny) < 5 ?
2285         FRAME_INTERNAL_BORDER_WIDTH (f) : 0;
2286       if (yAdjust)
2287         yIncr += FRAME_INTERNAL_BORDER_WIDTH (f);
2288       NSRect r = NSMakeRect (p->bx+xAdjust, p->by+yAdjust, p->nx, p->ny+yIncr);
2289       NSRectClip (r);
2290       [ns_lookup_indexed_color(face->background, f) set];
2291       NSRectFill (r);
2292     }
2294   if (p->which)
2295     {
2296       NSRect r = NSMakeRect (p->x+xAdjust, p->y, p->wd, p->h);
2297       NSPoint pt = r.origin;
2298       EmacsImage *img = bimgs[p->which - 1];
2300       if (!img)
2301         {
2302           unsigned short *bits = p->bits + p->dh;
2303           int len = 8 * p->h/8;
2304           int i;
2305           unsigned char *cbits = xmalloc (len);
2307           for (i =0; i<len; i++)
2308             cbits[i] = ~(bits[i] & 0xff);
2309           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2310                                            flip: NO];
2311           bimgs[p->which - 1] = img;
2312           xfree (cbits);
2313         }
2315       NSRectClip (r);
2316       /* Since we composite the bitmap instead of just blitting it, we need
2317          to erase the whole background. */
2318       [ns_lookup_indexed_color(face->background, f) set];
2319       NSRectFill (r);
2320       pt.y += p->h;
2321       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2322       [img compositeToPoint: pt operation: NSCompositeSourceOver];
2323     }
2324   ns_unfocus (f);
2328 void
2329 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2330                        int x, int y, int cursor_type, int cursor_width,
2331                        int on_p, int active_p)
2332 /* --------------------------------------------------------------------------
2333      External call (RIF): draw cursor
2334      (modeled after x_draw_window_cursor
2335      FIXME: cursor_width is effectively bogus -- it sometimes gets set
2336      in xdisp.c set_frame_cursor_types, sometimes left uninitialized;
2337      DON'T USE IT (no other terms do)
2338    -------------------------------------------------------------------------- */
2340   NSRect r, s;
2341   int fx, fy, h;
2342   struct frame *f = WINDOW_XFRAME (w);
2343   struct glyph *phys_cursor_glyph;
2344   int overspill, cursorToDraw;
2346   NSTRACE (dumpcursor);
2347 //fprintf(stderr, "drawcursor (%d,%d) activep = %d\tonp = %d\tc_type = %d\twidth = %d\n",x,y, active_p,on_p,cursor_type,cursor_width);
2349   if (!on_p)
2350         return;
2352   w->phys_cursor_type = cursor_type;
2353   w->phys_cursor_on_p = on_p;
2355   if (cursor_type == NO_CURSOR)
2356     {
2357       w->phys_cursor_width = 0;
2358       return;
2359     }
2361   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2362     {
2363       if (glyph_row->exact_window_width_line_p
2364           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2365         {
2366           glyph_row->cursor_in_fringe_p = 1;
2367           draw_fringe_bitmap (w, glyph_row, 0);
2368         }
2369       return;
2370     }
2372   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2374   r.origin.x = fx, r.origin.y = fy;
2375   r.size.height = h;
2376   r.size.width = w->phys_cursor_width;
2378   /* FIXME: if we overwrite the internal border area, it does not get erased;
2379      fix by truncating cursor, but better would be to erase properly */
2380   overspill = r.origin.x + r.size.width -
2381     WINDOW_TEXT_TO_FRAME_PIXEL_X (w, WINDOW_BOX_RIGHT_EDGE_X (w) 
2382       - WINDOW_TOTAL_FRINGE_WIDTH (w) - FRAME_INTERNAL_BORDER_WIDTH (f));
2383   if (overspill > 0)
2384     r.size.width -= overspill;
2386   /* TODO: only needed in rare cases with last-resort font in HELLO..
2387      should we do this more efficiently? */
2388   ns_clip_to_row (w, glyph_row, -1, NO); /* do ns_focus(f, &r, 1); if remove */
2389   [FRAME_CURSOR_COLOR (f) set];
2391 #ifdef NS_IMPL_COCOA
2392   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2393            atomic.  Cleaner ways of doing this should be investigated.
2394            One way would be to set a global variable DRAWING_CURSOR
2395            when making the call to draw_phys..(), don't focus in that
2396            case, then move the ns_unfocus() here after that call. */
2397   NSDisableScreenUpdates ();
2398 #endif
2400   cursorToDraw = active_p ? cursor_type : HOLLOW_BOX_CURSOR;
2401   switch (cursorToDraw)
2402     {
2403     case NO_CURSOR:
2404       break;
2405     case FILLED_BOX_CURSOR:
2406       NSRectFill (r);
2407       break;
2408     case HOLLOW_BOX_CURSOR:
2409       NSRectFill (r);
2410       [FRAME_BACKGROUND_COLOR (f) set];
2411       NSRectFill (NSInsetRect (r, 1, 1));
2412       [FRAME_CURSOR_COLOR (f) set];
2413       break;
2414     case HBAR_CURSOR:
2415       s = r;
2416       s.origin.y += lrint (0.75 * s.size.height);
2417       s.size.width = min (FRAME_COLUMN_WIDTH (f), s.size.width);
2418       s.size.height = lrint (s.size.height * 0.25);
2419       NSRectFill (s);
2420       break;
2421     case BAR_CURSOR:
2422       s = r;
2423       s.size.width = min (cursor_width, 2); //FIXME(see above)
2424       NSRectFill (s);
2425       break;
2426     }
2427   ns_unfocus (f);
2429   /* draw the character under the cursor */
2430   if (cursorToDraw != NO_CURSOR)
2431     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2433 #ifdef NS_IMPL_COCOA
2434   NSEnableScreenUpdates ();
2435 #endif
2440 static void
2441 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2442 /* --------------------------------------------------------------------------
2443      External (RIF): Draw a vertical line.
2444    -------------------------------------------------------------------------- */
2446   struct frame *f = XFRAME (WINDOW_FRAME (w));
2447   struct face *face;
2448   NSRect r = NSMakeRect (x, y0, 2, y1-y0);
2450   NSTRACE (ns_draw_vertical_window_border);
2452   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2453   if (face)
2454       [ns_lookup_indexed_color(face->foreground, f) set];
2456   ns_focus (f, &r, 1);
2457   NSDrawGroove (r, r);
2458   ns_unfocus (f);
2462 void
2463 show_hourglass (struct atimer *timer)
2465   if (hourglass_shown_p)
2466     return;
2468   BLOCK_INPUT;
2470   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2472   hourglass_shown_p = 1;
2473   UNBLOCK_INPUT;
2477 void
2478 hide_hourglass ()
2480   if (!hourglass_shown_p)
2481     return;
2483   BLOCK_INPUT;
2485   /* TODO: remove NSProgressIndicator from all frames */
2487   hourglass_shown_p = 0;
2488   UNBLOCK_INPUT;
2493 /* ==========================================================================
2495     Glyph drawing operations
2497    ========================================================================== */
2500 static inline NSRect
2501 ns_fix_rect_ibw (NSRect r, int fibw, int frame_pixel_width)
2502 /* --------------------------------------------------------------------------
2503     Under NS we draw internal borders inside fringes, and want full-width
2504     rendering to go all the way to edge.  This function makes that correction.
2505    -------------------------------------------------------------------------- */
2507   if (r.origin.y <= fibw+1)
2508     {
2509       r.size.height += r.origin.y;
2510       r.origin.y = 0;
2511     }
2512   if (r.origin.x <= fibw+1)
2513     {
2514       r.size.width += r.origin.x;
2515       r.origin.x = 0;
2516     }
2517   if (frame_pixel_width - (r.origin.x+r.size.width) <= fibw+1)
2518     r.size.width += fibw;
2520   return r;
2524 static int
2525 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2526 /* --------------------------------------------------------------------------
2527     Wrapper utility to account for internal border width on full-width lines,
2528     and allow top full-width rows to hit the frame top.  nr should be pointer
2529     to two successive NSRects.  Number of rects actually used is returned.
2530    -------------------------------------------------------------------------- */
2532   int n = get_glyph_string_clip_rects (s, nr, 2);
2533   if (s->row->full_width_p)
2534     {
2535       *nr = ns_fix_rect_ibw (*nr, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2536                             FRAME_PIXEL_WIDTH (s->f));
2537       if (n == 2)
2538         *nr = ns_fix_rect_ibw (*(nr+1), FRAME_INTERNAL_BORDER_WIDTH (s->f),
2539                               FRAME_PIXEL_WIDTH (s->f));
2540     }
2541   return n;
2545 static void
2546 ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char right_p)
2547 /* --------------------------------------------------------------------------
2548     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2549     Note we can't just use an NSDrawRect command, because of the possibility
2550     of some sides not being drawn, and because the rect will be filled.
2551    -------------------------------------------------------------------------- */
2553   NSRect s = r;
2554   [col set];
2556   /* top, bottom */
2557   s.size.height = thickness;
2558   NSRectFill (s);
2559   s.origin.y += r.size.height - thickness;
2560   NSRectFill (s);
2562   s.size.height = r.size.height;
2563   s.origin.y = r.origin.y;
2565   /* left, right (optional) */
2566   s.size.width = thickness;
2567   if (left_p)
2568     NSRectFill (s);
2569   if (right_p)
2570     {
2571       s.origin.x += r.size.width - thickness;
2572       NSRectFill (s);
2573     }
2577 static void
2578 ns_draw_relief (NSRect r, int thickness, char raised_p,
2579                char top_p, char bottom_p, char left_p, char right_p,
2580                struct glyph_string *s)
2581 /* --------------------------------------------------------------------------
2582     Draw a relief rect inside r, optionally leaving some sides open.
2583     Note we can't just use an NSDrawBezel command, because of the possibility
2584     of some sides not being drawn, and because the rect will be filled.
2585    -------------------------------------------------------------------------- */
2587   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2588   NSColor *newBaseCol = nil;
2589   NSRect sr = r;
2591   NSTRACE (ns_draw_relief);
2593   /* set up colors */
2595   if (s->face->use_box_color_for_shadows_p)
2596     {
2597       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2598     }
2599 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2600            && s->img->pixmap
2601            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2602        {
2603          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2604        } */
2605   else
2606     {
2607       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2608     }
2610   if (newBaseCol == nil)
2611     newBaseCol = [NSColor grayColor];
2613   if (newBaseCol != baseCol)  /* TODO: better check */
2614     {
2615       [baseCol release];
2616       baseCol = [newBaseCol retain];
2617       [lightCol release];
2618       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2619       [darkCol release];
2620       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2621     }
2623   [(raised_p ? lightCol : darkCol) set];
2625   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2627   /* top */
2628   sr.size.height = thickness;
2629   if (top_p) NSRectFill (sr);
2631   /* left */
2632   sr.size.height = r.size.height;
2633   sr.size.width = thickness;
2634   if (left_p) NSRectFill (sr);
2636   [(raised_p ? darkCol : lightCol) set];
2638   /* bottom */
2639   sr.size.width = r.size.width;
2640   sr.size.height = thickness;
2641   sr.origin.y += r.size.height - thickness;
2642   if (bottom_p) NSRectFill (sr);
2644   /* right */
2645   sr.size.height = r.size.height;
2646   sr.origin.y = r.origin.y;
2647   sr.size.width = thickness;
2648   sr.origin.x += r.size.width - thickness;
2649   if (right_p) NSRectFill (sr);
2653 static void
2654 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2655 /* --------------------------------------------------------------------------
2656       Function modeled after x_draw_glyph_string_box ().
2657       Sets up parameters for drawing.
2658    -------------------------------------------------------------------------- */
2660   int right_x, last_x;
2661   char left_p, right_p;
2662   struct glyph *last_glyph;
2663   NSRect r;
2664   int thickness;
2665   struct face *face;
2667   if (s->hl == DRAW_MOUSE_FACE)
2668     {
2669       face = FACE_FROM_ID
2670         (s->f, FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
2671       if (!face)
2672         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2673     }
2674   else
2675     face = s->face;
2677   thickness = face->box_line_width;
2679   NSTRACE (ns_dumpglyphs_box_or_relief);
2681   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2682             ? WINDOW_RIGHT_EDGE_X (s->w)
2683             : window_box_right (s->w, s->area));
2684   last_glyph = (s->cmp || s->img
2685                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2687   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2688               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2690   left_p = (s->first_glyph->left_box_line_p
2691             || (s->hl == DRAW_MOUSE_FACE
2692                 && (s->prev == NULL || s->prev->hl != s->hl)));
2693   right_p = (last_glyph->right_box_line_p
2694              || (s->hl == DRAW_MOUSE_FACE
2695                  && (s->next == NULL || s->next->hl != s->hl)));
2697   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2699   /* expand full-width row over internal borders */
2700   if (s->row->full_width_p)
2701     r = ns_fix_rect_ibw (r, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2702                         FRAME_PIXEL_WIDTH (s->f));
2704   if (s->face->box == FACE_SIMPLE_BOX)
2705     {
2706       xassert (s->face->box_color != nil);
2707       ns_draw_box (r, abs (thickness),
2708                    ns_lookup_indexed_color (face->box_color, s->f),
2709                   left_p, right_p);
2710     }
2711   else
2712     {
2713       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2714                      1, 1, left_p, right_p, s);
2715     }
2719 static void
2720 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2721 /* --------------------------------------------------------------------------
2722       Modeled after x_draw_glyph_string_background, which draws BG in
2723       certain cases.  Others are left to the text rendering routine.
2724    -------------------------------------------------------------------------- */
2726   NSTRACE (ns_maybe_dumpglyphs_background);
2728   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2729     {
2730       int box_line_width = max (s->face->box_line_width, 0);
2731       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2732           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2733         {
2734           struct face *face;
2735           if (s->hl == DRAW_MOUSE_FACE)
2736             {
2737               face = FACE_FROM_ID
2738                 (s->f, FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
2739               if (!face)
2740                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2741             }
2742           else
2743             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2744           if (!face->stipple)
2745             [(NS_FACE_BACKGROUND (face) != 0
2746               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2747               : FRAME_BACKGROUND_COLOR (s->f)) set];
2748           else
2749             {
2750               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2751               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2752             }
2754           if (s->hl != DRAW_CURSOR)
2755             {
2756               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2757                                     s->background_width,
2758                                     s->height-2*box_line_width);
2760               /* expand full-width row over internal borders */
2761               if (s->row->full_width_p)
2762                 {
2763                   int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2764                   if (r.origin.y <= fibw+1 + box_line_width)
2765                     {
2766                       r.size.height += r.origin.y;
2767                       r.origin.y = 0;
2768                     }
2769                   if (r.origin.x <= fibw+1)
2770                     {
2771                       r.size.width += 2*r.origin.x;
2772                       r.origin.x = 0;
2773                     }
2774                   if (FRAME_PIXEL_WIDTH (s->f) - (r.origin.x + r.size.width)
2775                       <= fibw+1)
2776                     r.size.width += fibw;
2777                 }
2779               NSRectFill (r);
2780             }
2782           s->background_filled_p = 1;
2783         }
2784     }
2788 static void
2789 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2790 /* --------------------------------------------------------------------------
2791       Renders an image and associated borders.
2792    -------------------------------------------------------------------------- */
2794   EmacsImage *img = s->img->pixmap;
2795   int box_line_vwidth = max (s->face->box_line_width, 0);
2796   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2797   int bg_x, bg_y, bg_height;
2798   int th;
2799   char raised_p;
2800   NSRect br;
2802   NSTRACE (ns_dumpglyphs_image);
2804   if (s->face->box != FACE_NO_BOX
2805       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2806     x += abs (s->face->box_line_width);
2808   bg_x = x;
2809   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2810   bg_height = s->height;
2811   /* other terms have this, but was causing problems w/tabbar mode */
2812   /* - 2 * box_line_vwidth; */
2814   if (s->slice.x == 0) x += s->img->hmargin;
2815   if (s->slice.y == 0) y += s->img->vmargin;
2817   /* Draw BG: if we need larger area than image itself cleared, do that,
2818      otherwise, since we composite the image under NS (instead of mucking
2819      with its background color), we must clear just the image area. */
2820   [ns_lookup_indexed_color (NS_FACE_BACKGROUND
2821             (FACE_FROM_ID (s->f, s->first_glyph->face_id)), s->f) set];
2823   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2824       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2825     {
2826       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
2827       s->background_filled_p = 1;
2828     }
2829   else
2830     {
2831       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
2832     }
2834   /* expand full-width row over internal borders */
2835   if (s->row->full_width_p)
2836     {
2837       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2838       if (br.origin.y <= fibw+1 + box_line_vwidth)
2839         {
2840           br.size.height += br.origin.y;
2841           br.origin.y = 0;
2842         }
2843       if (br.origin.x <= fibw+1 + box_line_vwidth)
2844         {
2845           br.size.width += br.origin.x;
2846           br.origin.x = 0;
2847         }
2848       if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) <= fibw+1)
2849         br.size.width += fibw;
2850     }
2852   NSRectFill (br);
2854   /* Draw the image.. do we need to draw placeholder if img ==nil? */
2855   if (img != nil)
2856     [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
2857                 operation: NSCompositeSourceOver];
2859   /* Draw relief, if requested */
2860   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
2861     {
2862       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
2863         {
2864           th = tool_bar_button_relief >= 0 ?
2865             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
2866           raised_p = (s->hl == DRAW_IMAGE_RAISED);
2867         }
2868       else
2869         {
2870           th = abs (s->img->relief);
2871           raised_p = (s->img->relief > 0);
2872         }
2874       r.origin.x = x - th;
2875       r.origin.y = y - th;
2876       r.size.width = s->slice.width + 2*th-1;
2877       r.size.height = s->slice.height + 2*th-1;
2878       ns_draw_relief (r, th, raised_p,
2879                      s->slice.y == 0,
2880                      s->slice.y + s->slice.height == s->img->height,
2881                      s->slice.x == 0,
2882                      s->slice.x + s->slice.width == s->img->width, s);
2883     }
2887 static void
2888 ns_draw_glyph_string (struct glyph_string *s)
2889 /* --------------------------------------------------------------------------
2890       External (RIF): Main draw-text call.
2891    -------------------------------------------------------------------------- */
2893   /* TODO (optimize): focus for box and contents draw */
2894   NSRect r[2];
2895   int n;
2896   char box_drawn_p = 0;
2898   NSTRACE (ns_draw_glyph_string);
2900   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
2901     {
2902       int width;
2903       struct glyph_string *next;
2905       for (width = 0, next = s->next;
2906            next && width < s->right_overhang;
2907            width += next->width, next = next->next)
2908         if (next->first_glyph->type != IMAGE_GLYPH)
2909           {
2910             n = ns_get_glyph_string_clip_rect (s->next, r);
2911             ns_focus (s->f, r, n);
2912             ns_maybe_dumpglyphs_background (s->next, 1);
2913             ns_unfocus (s->f);
2914             next->num_clips = 0;
2915           }
2916     }
2918   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
2919         && (s->first_glyph->type == CHAR_GLYPH
2920             || s->first_glyph->type == COMPOSITE_GLYPH))
2921     {
2922       n = ns_get_glyph_string_clip_rect (s, r);
2923       ns_focus (s->f, r, n);
2924       ns_maybe_dumpglyphs_background (s, 1);
2925       ns_dumpglyphs_box_or_relief (s);
2926       ns_unfocus (s->f);
2927       box_drawn_p = 1;
2928     }
2930   switch (s->first_glyph->type)
2931     {
2933     case IMAGE_GLYPH:
2934       n = ns_get_glyph_string_clip_rect (s, r);
2935       ns_focus (s->f, r, n);
2936       ns_dumpglyphs_image (s, r[0]);
2937       ns_unfocus (s->f);
2938       break;
2940     case STRETCH_GLYPH:
2941       if (!s->background_filled_p)
2942         {
2943           *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
2945           if (!s->row->full_width_p)
2946             {
2947               /* truncate to avoid overwriting fringe and/or scrollbar */
2948               int overrun = max (0, (s->x + s->background_width)
2949                                  - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
2950                                     - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
2951               r[0].size.width -= overrun;
2953               /* XXX: Try to work between problem where a stretch glyph on
2954                   a partially-visible bottom row will clear part of the
2955                   modeline, and another where list-buffers headers and similar
2956                   rows erroneously have visible_height set to 0.  Not sure
2957                   where this is coming from as other terms seem not to show. */
2958               r[0].size.height = min (s->height, s->row->visible_height);
2959             }
2961           /* expand full-width rows over internal borders */
2962           else
2963             {
2964               r[0] = ns_fix_rect_ibw (r[0], FRAME_INTERNAL_BORDER_WIDTH (s->f),
2965                                      FRAME_PIXEL_WIDTH (s->f));
2966             }
2968           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
2969              overwriting cursor (usually when cursor on a tab) */
2970           if (s->hl == DRAW_CURSOR)
2971             {
2972               r[0].origin.x += s->width;
2973               r[0].size.width -= s->width;
2974             }
2976           ns_focus (s->f, r, 1);
2977           [ns_lookup_indexed_color (NS_FACE_BACKGROUND
2978                (FACE_FROM_ID (s->f, s->first_glyph->face_id)), s->f) set];
2979           NSRectFill (r[0]);
2980           ns_unfocus (s->f);
2981           s->background_filled_p = 1;
2982         }
2983       break;
2985     case CHAR_GLYPH:
2986     case COMPOSITE_GLYPH:
2987       n = ns_get_glyph_string_clip_rect (s, r);
2988       ns_focus (s->f, r, n);
2990       if (s->for_overlaps || (s->cmp_from > 0
2991                               && ! s->first_glyph->u.cmp.automatic))
2992         s->background_filled_p = 1;
2993       else      /* 1 */
2994         ns_maybe_dumpglyphs_background
2995           (s, s->first_glyph->type == COMPOSITE_GLYPH);
2997       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
2998                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
2999                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3000                       NS_DUMPGLYPH_NORMAL));
3001       ns_tmp_font = (struct nsfont_info *)s->face->font;
3002       if (ns_tmp_font == NULL)
3003           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
3005       ns_tmp_font->font.driver->draw
3006         (s, 0, s->nchars, s->x, s->y,
3007          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3008          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
3010       ns_unfocus (s->f);
3011       break;
3013     default:
3014       abort ();
3015     }
3017   /* Draw box if not done already. */
3018   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3019     {
3020       n = ns_get_glyph_string_clip_rect (s, r);
3021       ns_focus (s->f, r, n);
3022       ns_dumpglyphs_box_or_relief (s);
3023       ns_unfocus (s->f);
3024     }
3026   s->num_clips = 0;
3031 /* ==========================================================================
3033     Event loop
3035    ========================================================================== */
3038 static void
3039 ns_send_appdefined (int value)
3040 /* --------------------------------------------------------------------------
3041     Internal: post an appdefined event which EmacsApp-sendEvent will
3042               recognize and take as a command to halt the event loop.
3043    -------------------------------------------------------------------------- */
3045   /*NSTRACE (ns_send_appdefined); */
3047   /* Only post this event if we haven't already posted one.  This will end
3048        the [NXApp run] main loop after having processed all events queued at
3049        this moment.  */
3050   if (send_appdefined)
3051     {
3052       NSEvent *nxev;
3054       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3055       send_appdefined = NO;
3057       /* Don't need wakeup timer any more */
3058       if (timed_entry)
3059         {
3060           [timed_entry invalidate];
3061           [timed_entry release];
3062           timed_entry = nil;
3063         }
3065       /* Ditto for file descriptor poller */
3066       if (fd_entry)
3067         {
3068           [fd_entry invalidate];
3069           [fd_entry release];
3070           fd_entry = nil;
3071         }
3073       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3074                                 location: NSMakePoint (0, 0)
3075                            modifierFlags: 0
3076                                timestamp: 0
3077                             windowNumber: [[NSApp mainWindow] windowNumber]
3078                                  context: [NSApp context]
3079                                  subtype: 0
3080                                    data1: value
3081                                    data2: 0];
3083       /* Post an application defined event on the event queue.  When this is
3084          received the [NXApp run] will return, thus having processed all
3085          events which are currently queued.  */
3086       [NSApp postEvent: nxev atStart: NO];
3087     }
3091 static int
3092 ns_read_socket (struct terminal *terminal, int expected,
3093                 struct input_event *hold_quit)
3094 /* --------------------------------------------------------------------------
3095      External (hook): Post an event to ourself and keep reading events until
3096      we read it back again.  In effect process all events which were waiting.
3097    23: Now we have to manage the event buffer ourselves.
3098    -------------------------------------------------------------------------- */
3100   struct input_event ev;
3101   int nevents;
3102   static NSDate *lastCheck = nil;
3103 /*  NSTRACE (ns_read_socket); */
3105   if (interrupt_input_blocked)
3106     {
3107       interrupt_input_pending = 1;
3108       return -1;
3109     }
3111   interrupt_input_pending = 0;
3112   BLOCK_INPUT;
3114 #ifdef COCOA_EXPERIMENTAL_CTRL_G
3115   /* causes Feval to abort; unclear on why this isn't in calling code */
3116   ++handling_signal;
3117 #endif
3119   n_emacs_events_pending = 0;
3120   EVENT_INIT (ev);
3121   emacs_event = &ev;
3122   q_event_ptr = hold_quit;
3124   /* we manage autorelease pools by allocate/reallocate each time around
3125      the loop; strict nesting is occasionally violated but seems not to
3126      matter.. earlier methods using full nesting caused major memory leaks */
3127   [outerpool release];
3128   outerpool = [[NSAutoreleasePool alloc] init];
3130   /* If have pending open-file requests, attend to the next one of those. */
3131   if (ns_pending_files && [ns_pending_files count] != 0
3132       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3133     {
3134       [ns_pending_files removeObjectAtIndex: 0];
3135     }
3136   /* Deal with pending service requests. */
3137   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3138     && [(EmacsApp *)
3139          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3140                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3141     {
3142       [ns_pending_service_names removeObjectAtIndex: 0];
3143       [ns_pending_service_args removeObjectAtIndex: 0];
3144     }
3145   else
3146     {
3147       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3148          to ourself, otherwise [NXApp run] will never exit.  */
3149       send_appdefined = YES;
3151       /* TODO: from termhooks.h: */
3152       /* XXX Please note that a non-zero value of EXPECTED only means that
3153      there is available input on at least one of the currently opened
3154      terminal devices -- but not necessarily on this device.
3155      Therefore, in most cases EXPECTED should be simply ignored. */
3156       /* However, if in ns_select, this is called from gobble_input, which
3157          appears to set it correctly for our purposes, and always assuming
3158          !expected causes 100% CPU usage. */
3159       if (!inNsSelect || !expected)
3160         {
3161           /* Post an application defined event on the event queue.  When this is
3162              received the [NXApp run] will return, thus having processed all
3163              events which are currently queued, if any.  */
3164           ns_send_appdefined (-1);
3165         }
3167       [NSApp run];
3168     }
3170   nevents = n_emacs_events_pending;
3171   n_emacs_events_pending = 0;
3172   emacs_event = q_event_ptr = NULL;
3174 #ifdef COCOA_EXPERIMENTAL_CTRL_G
3175   --handling_signal;
3176 #endif
3177   UNBLOCK_INPUT;
3178   return nevents;
3183 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3184            fd_set *exceptfds, struct timeval *timeout)
3185 /* --------------------------------------------------------------------------
3186      Replacement for select, checking for events
3187    -------------------------------------------------------------------------- */
3189   int result;
3190   double time;
3191   NSEvent *ev;
3192 /*  NSTRACE (ns_select); */
3194   if (NSApp == nil /* || ([NSApp isActive] == NO &&
3195                       [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil
3196  inMode:NSDefaultRunLoopMode dequeue:NO] == nil) */)
3197     return select (nfds, readfds, writefds, exceptfds, timeout);
3199   /* Save file descriptor set, which gets overwritten in calls to select ()
3200      Note, this is called from process.c, and only readfds is ever set */
3201   if (readfds)
3202     {
3203       memcpy (&select_readfds, readfds, sizeof (fd_set));
3204       select_nfds = nfds;
3205     }
3206   else
3207     select_nfds = 0;
3209     /* Try an initial select for pending data on input files */
3210   select_timeout.tv_sec = select_timeout.tv_usec = 0;
3211   result = select (nfds, readfds, writefds, exceptfds, &select_timeout);
3212   if (result)
3213     return result;
3215   /* if (!timeout || timed_entry || fd_entry)
3216        fprintf (stderr, "assertion failed: timeout null or timed_entry/fd_entry non-null in ns_select\n"); */
3218     /* set a timeout and run the main AppKit event loop while continuing
3219        to monitor the files */
3220   time = ((double) timeout->tv_sec) + ((double) timeout->tv_usec)/1000000.0;
3221   timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3222                                            target: NSApp
3223                                          selector: @selector (timeout_handler:)
3224                                          userInfo: 0
3225                                           repeats: YES] /* for safe removal */
3226                                                          retain];
3228   /* set a periodic task to try the select () again */
3229   fd_entry = [[NSTimer scheduledTimerWithTimeInterval: 0.1
3230                                                target: NSApp
3231                                              selector: @selector (fd_handler:)
3232                                              userInfo: 0
3233                                               repeats: YES]
3234                retain];
3236   /* Let Application dispatch events until it receives an event of the type
3237        NX_APPDEFINED, which should only be sent by timeout_handler.  */
3238   inNsSelect = 1;
3239   gobble_input (timeout ? 1 : 0);
3240   ev = last_appdefined_event;
3241   inNsSelect = 0;
3243   if (ev)
3244     {
3245       int t;
3246       if ([ev type] != NSApplicationDefined)
3247         abort ();
3249       t = [ev data1];
3250       last_appdefined_event = 0;
3252       if (t == -2)
3253         {
3254           /* The NX_APPDEFINED event we received was a timeout. */
3255           return 0;
3256         }
3257       else if (t == -1)
3258         {
3259           /* The NX_APPDEFINED event we received was the result of
3260              at least one real input event arriving.  */
3261           errno = EINTR;
3262           return -1;
3263         }
3264       else
3265         {
3266           /* Received back from select () in fd_handler; copy the results */
3267           if (readfds)
3268             memcpy (readfds, &select_readfds, sizeof (fd_set));
3269           return t;
3270         }
3271     }
3272   /* never reached, shut compiler up */
3273   return 0;
3278 /* ==========================================================================
3280     Scrollbar handling
3282    ========================================================================== */
3285 static void
3286 ns_set_vertical_scroll_bar (struct window *window,
3287                            int portion, int whole, int position)
3288 /* --------------------------------------------------------------------------
3289       External (hook): Update or add scrollbar
3290    -------------------------------------------------------------------------- */
3292   Lisp_Object win;
3293   NSRect r, v;
3294   struct frame *f = XFRAME (WINDOW_FRAME (window));
3295   EmacsView *view = FRAME_NS_VIEW (f);
3296   int window_y, window_height;
3297   BOOL barOnVeryLeft, barOnVeryRight;
3298   int top, left, height, width, sb_width, sb_left;
3299   EmacsScroller *bar;
3300 static int count = 0;
3302   /* optimization; display engine sends WAY too many of these.. */
3303   if (!NILP (window->vertical_scroll_bar))
3304     {
3305       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3306       if ([bar checkSamePosition: position portion: portion whole: whole])
3307         {
3308           if (view->scrollbarsNeedingUpdate == 0)
3309             {
3310               if (!windows_or_buffers_changed)
3311                   return;
3312             }
3313           else
3314             view->scrollbarsNeedingUpdate--;
3315         }
3316     }
3318   NSTRACE (ns_set_vertical_scroll_bar);
3320   /* Get dimensions.  */
3321   window_box (window, -1, 0, &window_y, 0, &window_height);
3322   top = window_y;
3323   height = window_height;
3324   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3325   left = WINDOW_SCROLL_BAR_AREA_X (window);
3327   if (top < 5) /* top scrollbar adjustment */
3328     {
3329       top -= FRAME_INTERNAL_BORDER_WIDTH (f);
3330       height += FRAME_INTERNAL_BORDER_WIDTH (f);
3331     }
3333   /* allow for displaying a skinnier scrollbar than char area allotted */
3334   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3335     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3337   barOnVeryLeft = left < 5;
3338   barOnVeryRight = FRAME_PIXEL_WIDTH (f) - left - width < 5;
3339   sb_left = left + FRAME_INTERNAL_BORDER_WIDTH (f)
3340       * (barOnVeryLeft ? -1 : (barOnVeryRight ? 1 : 0));
3342   r = NSMakeRect (sb_left, top, sb_width, height);
3343   /* the parent view is flipped, so we need to flip y value */
3344   v = [view frame];
3345   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3347   XSETWINDOW (win, window);
3348   BLOCK_INPUT;
3350   /* we want at least 5 lines to display a scrollbar */
3351   if (WINDOW_TOTAL_LINES (window) < 5)
3352     {
3353       if (!NILP (window->vertical_scroll_bar))
3354         {
3355           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3356           [bar removeFromSuperview];
3357           window->vertical_scroll_bar = Qnil;
3358         }
3359       ns_clear_frame_area (f, sb_left, top, width, height);
3360       UNBLOCK_INPUT;
3361       return;
3362     }
3364   if (NILP (window->vertical_scroll_bar))
3365     {
3366       ns_clear_frame_area (f, sb_left, top, width, height);
3367       bar = [[EmacsScroller alloc] initFrame: r window: win];
3368       window->vertical_scroll_bar = make_save_value (bar, 0);
3369     }
3370   else
3371     {
3372       NSRect oldRect;
3373       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3374       oldRect = [bar frame];
3375       r.size.width = oldRect.size.width;
3376       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3377         {
3378           if (oldRect.origin.x != r.origin.x)
3379               ns_clear_frame_area (f, sb_left, top, width, height);
3380           [bar setFrame: r];
3381         }
3382     }
3384   [bar setPosition: position portion: portion whole: whole];
3385   UNBLOCK_INPUT;
3389 static void
3390 ns_condemn_scroll_bars (struct frame *f)
3391 /* --------------------------------------------------------------------------
3392      External (hook): arrange for all frame's scrollbars to be removed
3393      at next call to judge_scroll_bars, except for those redeemed.
3394    -------------------------------------------------------------------------- */
3396   int i;
3397   id view;
3398   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3400   NSTRACE (ns_condemn_scroll_bars);
3402   for (i =[subviews count]-1; i >= 0; i--)
3403     {
3404       view = [subviews objectAtIndex: i];
3405       if ([view isKindOfClass: [EmacsScroller class]])
3406         [view condemn];
3407     }
3411 static void
3412 ns_redeem_scroll_bar (struct window *window)
3413 /* --------------------------------------------------------------------------
3414      External (hook): arrange to spare this window's scrollbar
3415      at next call to judge_scroll_bars.
3416    -------------------------------------------------------------------------- */
3418   id bar;
3419   NSTRACE (ns_redeem_scroll_bar);
3420   if (!NILP (window->vertical_scroll_bar))
3421     {
3422       bar =XNS_SCROLL_BAR (window->vertical_scroll_bar);
3423       [bar reprieve];
3424     }
3428 static void
3429 ns_judge_scroll_bars (struct frame *f)
3430 /* --------------------------------------------------------------------------
3431      External (hook): destroy all scrollbars on frame that weren't
3432      redeemed after call to condemn_scroll_bars.
3433    -------------------------------------------------------------------------- */
3435   int i;
3436   id view;
3437   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3438   NSTRACE (ns_judge_scroll_bars);
3439   for (i =[subviews count]-1; i >= 0; i--)
3440     {
3441       view = [subviews objectAtIndex: i];
3442       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3443       [view judge];
3444     }
3449 /* ==========================================================================
3451     Miscellaneous, mainly stubbed-out functions added in 23
3453    ========================================================================== */
3456 void
3457 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
3463 /* ==========================================================================
3465     Initialization
3467    ========================================================================== */
3470 x_display_pixel_height (dpyinfo)
3471      struct ns_display_info *dpyinfo;
3473   NSScreen *screen = [NSScreen mainScreen];
3474   return [screen frame].size.height;
3478 x_display_pixel_width (dpyinfo)
3479      struct ns_display_info *dpyinfo;
3481   NSScreen *screen = [NSScreen mainScreen];
3482   return [screen frame].size.width;
3486 static Lisp_Object ns_string_to_lispmod (const char *s)
3487 /* --------------------------------------------------------------------------
3488      Convert modifier name to lisp symbol
3489    -------------------------------------------------------------------------- */
3491   if (!strncmp (SDATA (SYMBOL_NAME (Qmeta)), s, 10))
3492     return Qmeta;
3493   else if (!strncmp (SDATA (SYMBOL_NAME (Qsuper)), s, 10))
3494     return Qsuper;
3495   else if (!strncmp (SDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3496     return Qcontrol;
3497   else if (!strncmp (SDATA (SYMBOL_NAME (Qalt)), s, 10))
3498     return Qalt;
3499   else if (!strncmp (SDATA (SYMBOL_NAME (Qhyper)), s, 10))
3500     return Qhyper;
3501   else if (!strncmp (SDATA (SYMBOL_NAME (Qnone)), s, 10))
3502     return Qnone;
3503   else
3504     return Qnil;
3508 static Lisp_Object ns_mod_to_lisp (int m)
3509 /* --------------------------------------------------------------------------
3510      Convert modifier code (see lisp.h) to lisp symbol
3511    -------------------------------------------------------------------------- */
3513   if (m == CHAR_META)
3514     return Qmeta;
3515   else if (m == CHAR_SUPER)
3516     return Qsuper;
3517   else if (m == CHAR_CTL)
3518     return Qcontrol;
3519   else if (m == CHAR_ALT)
3520     return Qalt;
3521   else if (m == CHAR_HYPER)
3522     return Qhyper;
3523   else /* if (m == 0) */
3524     return Qnone;
3528 static void
3529 ns_set_default_prefs ()
3530 /* --------------------------------------------------------------------------
3531       Initialize preference variables to defaults
3532    -------------------------------------------------------------------------- */
3534   ns_alternate_modifier = Qmeta;
3535   ns_command_modifier = Qsuper;
3536   ns_control_modifier = Qcontrol;
3537   ns_function_modifier = Qnone;
3538   ns_expand_space = make_float (0.0);
3539   ns_antialias_text = Qt;
3540   ns_antialias_threshold = 10.0; /* not exposed to lisp side */
3541   ns_use_qd_smoothing = Qnil;
3542   ns_use_system_highlight_color = Qt;
3546 static void
3547 ns_default (const char *parameter, Lisp_Object *result,
3548            Lisp_Object yesval, Lisp_Object noval,
3549            BOOL is_float, BOOL is_modstring)
3550 /* --------------------------------------------------------------------------
3551       Check a parameter value in user's preferences
3552    -------------------------------------------------------------------------- */
3554   const char *value;
3556   if ( (value =[[[NSUserDefaults standardUserDefaults]
3557                    stringForKey: [NSString stringWithUTF8String: parameter]]
3558                 UTF8String]) )
3559     {
3560       double f;
3561       char *pos;
3562       if (strcasecmp (value, "YES") == 0)
3563         *result = yesval;
3564       else if (strcasecmp (value, "NO") == 0)
3565         *result = noval;
3566       else if (is_float && (f = strtod (value, &pos), pos != value))
3567         *result = make_float (f);
3568       else if (is_modstring && value)
3569         *result = ns_string_to_lispmod (value);
3570       else fprintf (stderr,
3571                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3572     }
3576 void
3577 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3578 /* --------------------------------------------------------------------------
3579       Initialize global info and storage for display.
3580    -------------------------------------------------------------------------- */
3582     NSScreen *screen = [NSScreen mainScreen];
3583     NSWindowDepth depth = [screen depth];
3585     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3586     dpyinfo->resy = 72.27;
3587     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3588                                                   NSColorSpaceFromDepth (depth)]
3589                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3590                                                  NSColorSpaceFromDepth (depth)];
3591     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3592     dpyinfo->image_cache = make_image_cache ();
3593     dpyinfo->color_table
3594       = (struct ns_color_table *)xmalloc (sizeof (struct ns_color_table));
3595     dpyinfo->color_table->colors = NULL;
3596     dpyinfo->root_window = 42; /* a placeholder.. */
3598     dpyinfo->mouse_face_mouse_frame = NULL;
3599     dpyinfo->mouse_face_deferred_gc = 0;
3600     dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
3601     dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
3602     dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
3603     dpyinfo->mouse_face_window = dpyinfo->mouse_face_overlay = Qnil;
3604     dpyinfo->mouse_face_hidden = 0;
3606     dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
3607     dpyinfo->mouse_face_defer = 0;
3609     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3611     dpyinfo->n_fonts = 0;
3612     dpyinfo->smallest_font_height = 1;
3613     dpyinfo->smallest_char_width = 1;
3617 /* 23: Needed as new part of display engine; this and next define public
3618       functions in this file (well, many of them, anyway). */
3619 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3620          with using despite presence in the "system dependent" redisplay
3621          interface.  In addition, many of the ns_ methods have code that is
3622          shared with all terms, indicating need for further refactoring. */
3623 extern frame_parm_handler ns_frame_parm_handlers[];
3624 static struct redisplay_interface ns_redisplay_interface =
3626   ns_frame_parm_handlers,
3627   x_produce_glyphs, /*generic OK */
3628   x_write_glyphs, /*generic OK */
3629   x_insert_glyphs, /*generic OK */
3630   x_clear_end_of_line, /*generic OK */
3631   ns_scroll_run, /*23 */
3632   ns_after_update_window_line, /*23: added */
3633   ns_update_window_begin, /*23: split from update_begin */
3634   ns_update_window_end, /*23: split from update_end */
3635   x_cursor_to, /*generic OK */
3636   ns_flush,
3637   0, /* flush_display_optional */
3638   x_clear_window_mouse_face, /*generic OK */
3639   x_get_glyph_overhangs, /*23: generic OK */
3640   x_fix_overlapping_area, /*generic OK */
3641   ns_draw_fringe_bitmap, /*23 */
3642   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3643   0, /* destroy_fringe_bitmap */
3644   ns_compute_glyph_string_overhangs, /*23 */
3645   ns_draw_glyph_string, /*23: interface to nsfont.m */
3646   ns_define_frame_cursor, /*23 */
3647   ns_clear_frame_area, /*23 */
3648   ns_draw_window_cursor, /*23: revamped ns_dumpcursor */
3649   ns_draw_vertical_window_border,
3650   ns_shift_glyphs_for_insert
3654 static void
3655 ns_delete_display (struct ns_display_info *dpyinfo)
3657   /* TODO... */
3661 /* This function is called when the last frame on a display is deleted. */
3662 static void
3663 ns_delete_terminal (struct terminal *terminal)
3665   struct ns_display_info *dpyinfo = terminal->display_info.ns;
3666   int i;
3668   /* Protect against recursive calls.  delete_frame in
3669      delete_terminal calls us back when it deletes our last frame.  */
3670   if (!terminal->name)
3671     return;
3673   BLOCK_INPUT;
3675   x_destroy_all_bitmaps (dpyinfo);
3676   ns_delete_display (dpyinfo);
3677   UNBLOCK_INPUT;
3681 static struct terminal *
3682 ns_create_terminal (struct ns_display_info *dpyinfo)
3683 /* --------------------------------------------------------------------------
3684       Set up use of NS before we make the first connection.
3685    -------------------------------------------------------------------------- */
3687   struct terminal *terminal;
3689   NSTRACE (ns_create_terminal);
3691   terminal = create_terminal ();
3693   terminal->type = output_ns;
3694   terminal->display_info.ns = dpyinfo;
3695   dpyinfo->terminal = terminal;
3697   terminal->rif = &ns_redisplay_interface;
3699   terminal->clear_frame_hook = ns_clear_frame;
3700   terminal->ins_del_lines_hook = 0; /* 23: vestigial? */
3701   terminal->delete_glyphs_hook = 0; /* 23: vestigial? */
3702   terminal->ring_bell_hook = ns_ring_bell;
3703   terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
3704   terminal->set_terminal_modes_hook = ns_set_terminal_modes;
3705   terminal->update_begin_hook = ns_update_begin;
3706   terminal->update_end_hook = ns_update_end;
3707   terminal->set_terminal_window_hook = NULL; /* 23: vestigial? */
3708   terminal->read_socket_hook = ns_read_socket;
3709   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
3710   terminal->mouse_position_hook = ns_mouse_position;
3711   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
3712   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
3714   terminal->fullscreen_hook = 0; /*XTfullscreen_hook;//23.50 */
3716   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
3717   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
3718   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
3719   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
3721   terminal->delete_frame_hook = x_destroy_window;
3722   terminal->delete_terminal_hook = ns_delete_terminal;
3724   terminal->scroll_region_ok = 1;
3725   terminal->char_ins_del_ok = 1;
3726   terminal->line_ins_del_ok = 1;
3727   terminal->fast_clear_end_of_line = 1;
3728   terminal->memory_below_frame = 0;
3730   return terminal;
3734 void
3735 ns_initialize ()
3736 /* --------------------------------------------------------------------------
3737    Mainly vestigial under NS now that ns_create_terminal () does most things.
3738    -------------------------------------------------------------------------- */
3740   baud_rate = 38400;
3741   Fset_input_interrupt_mode (Qt);
3745 struct ns_display_info *
3746 ns_term_init (Lisp_Object display_name)
3747 /* --------------------------------------------------------------------------
3748      Start the Application and get things rolling.
3749    -------------------------------------------------------------------------- */
3751   extern Lisp_Object Fset_input_mode (Lisp_Object, Lisp_Object,
3752                                      Lisp_Object, Lisp_Object);
3753   struct terminal *terminal;
3754   struct ns_display_info *dpyinfo;
3755   static int ns_initialized = 0;
3756   Lisp_Object tmp;
3758   NSTRACE (ns_term_init);
3760   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
3761   /*GSDebugAllocationActive (YES); */
3762   BLOCK_INPUT;
3763   handling_signal = 0;
3765   if (!ns_initialized)
3766     {
3767       ns_initialize ();
3768       ns_initialized = 1;
3769     }
3771   ns_pending_files = [[NSMutableArray alloc] init];
3772   ns_pending_service_names = [[NSMutableArray alloc] init];
3773   ns_pending_service_args = [[NSMutableArray alloc] init];
3775   /* Start app and create the main menu, window, view.
3776      Needs to be here because ns_initialize_display_info () uses AppKit classes.
3777      The view will then ask the NSApp to stop and return to Emacs. */
3778   [EmacsApp sharedApplication];
3779   if (NSApp == nil)
3780     return NULL;
3781   [NSApp setDelegate: NSApp];
3783   /* debugging: log all notifications */
3784   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
3785                                          selector: @selector (logNotification:)
3786                                              name: nil object: nil]; */
3788   dpyinfo = (struct ns_display_info *)xmalloc (sizeof (struct ns_display_info));
3789   bzero (dpyinfo, sizeof (struct ns_display_info));
3791   ns_initialize_display_info (dpyinfo);
3792   terminal = ns_create_terminal (dpyinfo);
3794   terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
3795   init_kboard (terminal->kboard);
3796   terminal->kboard->Vwindow_system = Qns;
3797   terminal->kboard->next_kboard = all_kboards;
3798   all_kboards = terminal->kboard;
3799   /* Don't let the initial kboard remain current longer than necessary.
3800      That would cause problems if a file loaded on startup tries to
3801      prompt in the mini-buffer.  */
3802   if (current_kboard == initial_kboard)
3803     current_kboard = terminal->kboard;
3804   terminal->kboard->reference_count++;
3806   dpyinfo->next = x_display_list;
3807   x_display_list = dpyinfo;
3809   /* Put it on ns_display_name_list */
3810   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
3811                                 ns_display_name_list);
3812 /*      ns_display_name_list = Fcons (Fcons (display_name,
3813                                            Fcons (Qnil, dpyinfo->xrdb)),
3814                                     ns_display_name_list); */
3815   dpyinfo->name_list_element = XCAR (ns_display_name_list);
3817   /* Set the name of the terminal. */
3818   terminal->name = (char *) xmalloc (SBYTES (display_name) + 1);
3819   strncpy (terminal->name, SDATA (display_name), SBYTES (display_name));
3820   terminal->name[SBYTES (display_name)] = 0;
3822   UNBLOCK_INPUT; 
3824   /* Read various user defaults. */
3825   ns_set_default_prefs ();
3826   ns_default ("AlternateModifier", &ns_alternate_modifier,
3827              Qnil, Qnil, NO, YES);
3828   if (NILP (ns_alternate_modifier))
3829     ns_alternate_modifier = Qmeta;
3830   ns_default ("CommandModifier", &ns_command_modifier,
3831              Qnil, Qnil, NO, YES);
3832   if (NILP (ns_command_modifier))
3833     ns_command_modifier = Qsuper;
3834   ns_default ("ControlModifier", &ns_control_modifier,
3835              Qnil, Qnil, NO, YES);
3836   if (NILP (ns_control_modifier))
3837     ns_control_modifier = Qcontrol;
3838   ns_default ("FunctionModifier", &ns_function_modifier,
3839              Qnil, Qnil, NO, YES);
3840   if (NILP (ns_function_modifier))
3841     ns_function_modifier = Qnone;
3842   ns_default ("ExpandSpace", &ns_expand_space,
3843              make_float (0.5), make_float (0.0), YES, NO);
3844   ns_default ("GSFontAntiAlias", &ns_antialias_text,
3845              Qt, Qnil, NO, NO);
3846   tmp = Qnil;
3847   ns_default ("AppleAntiAliasingThreshold", &tmp,
3848              make_float (10.0), make_float (6.0), YES, NO);
3849   ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
3850   ns_default ("UseQuickdrawSmoothing", &ns_use_qd_smoothing,
3851              Qt, Qnil, NO, NO);
3852   ns_default ("UseSystemHighlightColor", &ns_use_system_highlight_color,
3853              Qt, Qnil, NO, NO);
3854   if (EQ (ns_use_system_highlight_color, Qt))
3855     {
3856       ns_selection_color = [[NSUserDefaults standardUserDefaults]
3857                                stringForKey: @"AppleHighlightColor"];
3858       if (ns_selection_color == nil)
3859         ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
3860     }
3861   else
3862     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
3864   {
3865     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
3867     if ( cl == nil )
3868       {
3869         Lisp_Object color_file, color_map, color;
3870         int r,g,b;
3871         unsigned long c;
3872         char *name;
3874         color_file = Fexpand_file_name (build_string ("rgb.txt"),
3875                          Fsymbol_value (intern ("data-directory")));
3876         if (NILP (Ffile_readable_p (color_file)))
3877           fatal ("Could not find %s.\n", SDATA (color_file));
3879         color_map = Fx_load_color_file (color_file);
3880         if (NILP (color_map))
3881           fatal ("Could not read %s.\n", SDATA (color_file));
3883         cl = [[NSColorList alloc] initWithName: @"Emacs"];
3884         for ( ; CONSP (color_map); color_map = XCDR (color_map))
3885           {
3886             color = XCAR (color_map);
3887             name = SDATA (XCAR (color));
3888             c = XINT (XCDR (color));
3889             [cl setColor:
3890                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
3891                                             green: GREEN_FROM_ULONG (c) / 255.0
3892                                              blue: BLUE_FROM_ULONG (c) / 255.0
3893                                             alpha: 1.0]
3894                   forKey: [NSString stringWithUTF8String: name]];
3895           }
3896         [cl writeToFile: nil];
3897       }
3898   }
3900   {
3901     char c[128];
3902 #ifdef NS_IMPL_GNUSTEP
3903     strncpy (c, gnustep_base_version, sizeof (c));
3904 #else
3905     /*PSnextrelease (128, c); */
3906     snprintf (c, sizeof (c), "%g", NSAppKitVersionNumber);
3907 #endif
3908     Vwindow_system_version = build_string (c);
3909   }
3911   delete_keyboard_wait_descriptor (0);
3913 /* Set up OS X app menu */
3914 #ifdef NS_IMPL_COCOA
3915   {
3916     NSMenu *appMenu;
3917     NSMenuItem *item;
3918     /* set up the application menu */
3919     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
3920     [svcsMenu setAutoenablesItems: NO];
3921     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
3922     [appMenu setAutoenablesItems: NO];
3923     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
3924     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
3926     [appMenu insertItemWithTitle: @"About Emacs"
3927                           action: @selector (orderFrontStandardAboutPanel:)
3928                    keyEquivalent: @""
3929                          atIndex: 0];
3930     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
3931     [appMenu insertItemWithTitle: @"Preferences..."
3932                           action: @selector (showPreferencesWindow:)
3933                    keyEquivalent: @","
3934                          atIndex: 2];
3935     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
3936     item = [appMenu insertItemWithTitle: @"Services"
3937                                  action: @selector (menuDown:)
3938                           keyEquivalent: @""
3939                                 atIndex: 4];
3940     [appMenu setSubmenu: svcsMenu forItem: item];
3941 /*    [svcsMenu setSupercell: item]; */
3942     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
3943     [appMenu insertItemWithTitle: @"Hide Emacs"
3944                           action: @selector (hide:)
3945                    keyEquivalent: @"h"
3946                          atIndex: 6];
3947     item =  [appMenu insertItemWithTitle: @"Hide Others"
3948                           action: @selector (hideOtherApplications:)
3949                    keyEquivalent: @"h"
3950                          atIndex: 7];
3951     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
3952     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
3953     [appMenu insertItemWithTitle: @"Quit Emacs"
3954                           action: @selector (terminate:)
3955                    keyEquivalent: @"q"
3956                          atIndex: 9];
3958     item = [mainMenu insertItemWithTitle: @"Emacs"
3959                                   action: @selector (menuDown:)
3960                            keyEquivalent: @""
3961                                  atIndex: 0];
3962     [mainMenu setSubmenu: appMenu forItem: item];
3963     [dockMenu insertItemWithTitle: @"New Frame"
3964                            action: @selector (newFrame:)
3965                     keyEquivalent: @""
3966                           atIndex: 0];
3968     [NSApp setMainMenu: mainMenu];
3969     [NSApp setAppleMenu: appMenu];
3970     [NSApp setServicesMenu: svcsMenu];
3971     /* Needed at least on Cocoa, to get dock menu to show windows */
3972     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
3973   }
3974 #endif /* MAC OS X menu setup */
3976   [NSApp run];
3978   return dpyinfo;
3982 extern Lisp_Object Vauto_save_list_file_name;
3983 void
3984 ns_term_shutdown (int sig)
3986   /* code not reached in emacs.c after this is called by shut_down_emacs: */
3987   if (STRINGP (Vauto_save_list_file_name))
3988     unlink (SDATA (Vauto_save_list_file_name));
3990   if (sig == 0 || sig == SIGTERM)
3991     {
3992       ns_shutdown_properly = YES;
3993       [NSApp terminate: NSApp];
3994     }
3995   else // force a stack trace to happen
3996     {
3997       abort();
3998     }
4002 /* ==========================================================================
4004     EmacsApp implementation
4006    ========================================================================== */
4009 @implementation EmacsApp
4011 - (void)logNotification: (NSNotification *)notification
4013   const char *name = [[notification name] UTF8String];
4014   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4015       && !strstr (name, "WindowNumber"))
4016     NSLog (@"notification: '%@'", [notification name]);
4020 - (void)sendEvent: (NSEvent *)theEvent
4021 /* --------------------------------------------------------------------------
4022      Events posted by ns_send_appdefined interrupt the run loop here
4023    -------------------------------------------------------------------------- */
4025   int type = [theEvent type];
4026   NSWindow *window = [theEvent window];
4027 /*  NSTRACE (sendEvent); */
4028 /*fprintf (stderr, "received event of type %d\n", [theEvent type]); */
4030   if (type == NSCursorUpdate && window == nil)
4031     {
4032       fprintf (stderr, "Dropping external cursor update event.\n");
4033       return;
4034     }
4036 #ifdef NS_IMPL_COCOA
4037   /* pass mouse down in resize handle and subsequent drags directly to
4038      EmacsWindow so we can generate continuous redisplays */
4039   if (ns_in_resize)
4040     {
4041       if (type == NSLeftMouseDragged)
4042         {
4043           [window mouseDragged: theEvent];
4044           return;
4045         }
4046       else if (type == NSLeftMouseUp)
4047         {
4048           [window mouseUp: theEvent];
4049           return;
4050         }
4051     }
4052   else if (type == NSLeftMouseDown)
4053     {
4054       NSRect r = ns_resize_handle_rect (window);
4055       if (NSPointInRect ([theEvent locationInWindow], r))
4056         {
4057           ns_in_resize = YES;
4058           [window mouseDown: theEvent];
4059           return;
4060         }
4061     }
4062 #endif
4064   if (type == NSApplicationDefined)
4065     {
4066       last_appdefined_event = theEvent;
4067       [self stop: self];
4068     }
4070   [super sendEvent: theEvent];
4074 - (void)showPreferencesWindow: (id)sender
4076   if (prefsController == nil)
4077     prefsController = [[EmacsPrefsController alloc] init];
4078   [prefsController showForFrame: SELECTED_FRAME ()];
4082 - (void)newFrame: (id)sender
4084   struct frame *emacsframe = SELECTED_FRAME ();
4085   NSEvent *theEvent = [NSApp currentEvent];
4087   if (!emacs_event)
4088     return;
4089   emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4090   emacs_event->code = KEY_NS_NEW_FRAME;
4091   emacs_event->modifiers = 0;
4092   EV_TRAILER (theEvent);
4096 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4097 - (BOOL) openFile: (NSString *)fileName
4099   struct frame *emacsframe = SELECTED_FRAME ();
4100   NSEvent *theEvent = [NSApp currentEvent];
4102   if (!emacs_event)
4103     return NO;
4105   emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4106   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4107   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4108   ns_input_line = Qnil; /* can be start or cons start,end */
4109   emacs_event->modifiers =0;
4110   EV_TRAILER (theEvent);
4112   return YES;
4116 /* **************************************************************************
4118       EmacsApp delegate implementation
4120    ************************************************************************** */
4122 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4123 /* --------------------------------------------------------------------------
4124      When application is loaded, terminate event loop in ns_term_init
4125    -------------------------------------------------------------------------- */
4127   NSTRACE (applicationDidFinishLaunching);
4128   [NSApp setServicesProvider: NSApp];
4129   ns_send_appdefined (-2);
4133 - (void) terminate: (id)sender
4135   BLOCK_INPUT;
4136   if (ns_shutdown_properly)
4137     [super terminate: sender];
4138   else
4139     {
4140 /*    Fkill_emacs (Qnil); */
4141       ns_shutdown_properly = YES;
4142       Feval (Fcons (intern ("save-buffers-kill-emacs"), Qnil));
4143     }
4144   UNBLOCK_INPUT;
4148 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4150   if (ns_shutdown_properly)
4151     return NSTerminateNow;
4153   Lisp_Object contents = list3 (build_string ("Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?"),
4154       Fcons (build_string ("Cancel"), Qnil),
4155       Fcons (build_string ("Save and Exit"), Qt));
4156   Lisp_Object res = ns_popup_dialog (Qt, contents, Qnil);
4157 fprintf (stderr, "res = %d\n", EQ (res, Qt)); /* FIXME */
4158   if (EQ (res, Qt))
4159     {
4160       Feval (Fcons (intern ("save-buffers-kill-emacs"), Qnil));
4161       return NSTerminateNow;
4162     }
4163   return NSTerminateCancel;
4167 /*   Notification from the Workspace to open a file */
4168 - (BOOL)application: sender openFile: (NSString *)file
4170   [ns_pending_files addObject: file];
4171   return YES;
4175 /*   Open a file as a temporary file */
4176 - (BOOL)application: sender openTempFile: (NSString *)file
4178   [ns_pending_files addObject: file];
4179   return YES;
4183 /*   Notification from the Workspace to open a file noninteractively (?) */
4184 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4186   [ns_pending_files addObject: file];
4187   return YES;
4191 /*   Notification from the Workspace to open multiple files */
4192 - (void)application: sender openFiles: (NSArray *)fileList
4194   NSEnumerator *files = [fileList objectEnumerator];
4195   NSString *file;
4196   while ((file = [files nextObject]) != nil)
4197     [ns_pending_files addObject: file];
4199 /* TODO: when GNUstep implements this (and we require that version of
4200          GNUstep), remove. */
4201 #ifndef NS_IMPL_GNUSTEP
4202   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4203 #endif /* !NS_IMPL_GNUSTEP */
4208 /* Handle dock menu requests.  */
4209 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4211   return dockMenu;
4215 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4216 - (void)applicationDidBecomeActive: (NSNotification *)notification
4219 - (void)applicationDidResignActive: (NSNotification *)notification
4221   ns_send_appdefined (-1);
4226 /* ==========================================================================
4228     EmacsApp aux handlers for managing event loop
4230    ========================================================================== */
4233 - (void)timeout_handler: (NSTimer *)timedEntry
4234 /* --------------------------------------------------------------------------
4235      The timeout specified to ns_select has passed.
4236    -------------------------------------------------------------------------- */
4238   /*NSTRACE (timeout_handler); */
4239   ns_send_appdefined (-2);
4242 extern void update_window_cursor (struct window *w, int on);
4244 - (void)fd_handler: (NSTimer *) fdEntry
4245 /* --------------------------------------------------------------------------
4246      Check data waiting on file descriptors and terminate if so
4247    -------------------------------------------------------------------------- */
4249   int result;
4250   /* NSTRACE (fd_handler); */
4252   if (select_nfds == 0)
4253     return;
4255   memcpy (&t_readfds, &select_readfds, sizeof (fd_set));
4257   select_timeout.tv_sec = select_timeout.tv_usec = 0;
4258   result = select (select_nfds, &t_readfds, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
4259                   &select_timeout);
4260   if (result)
4261     {
4262       memcpy (&select_readfds, &t_readfds, sizeof (fd_set));
4263       ns_send_appdefined (result);
4264     }
4269 /* ==========================================================================
4271     Service provision
4273    ========================================================================== */
4275 /* called from system: queue for next pass through event loop */
4276 - (void)requestService: (NSPasteboard *)pboard
4277               userData: (NSString *)userData
4278                  error: (NSString **)error
4280   [ns_pending_service_names addObject: userData];
4281   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4282       SDATA (ns_string_from_pasteboard (pboard))]];
4286 /* called from ns_read_socket to clear queue */
4287 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4289   struct frame *emacsframe = SELECTED_FRAME ();
4290   NSEvent *theEvent = [NSApp currentEvent];
4292   if (!emacs_event)
4293     return NO;
4295   emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4296   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4297   ns_input_spi_name = build_string ([name UTF8String]);
4298   ns_input_spi_arg = build_string ([arg UTF8String]);
4299   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4300   EV_TRAILER (theEvent);
4302   return YES;
4306 @end  /* EmacsApp */
4310 /* ==========================================================================
4312     EmacsView implementation
4314    ========================================================================== */
4317 @implementation EmacsView
4319 /* needed to inform when window closed from LISP */
4320 - (void) setWindowClosing: (BOOL)closing
4322   windowClosing = closing;
4326 - (void)dealloc
4328   NSTRACE (EmacsView_dealloc);
4329   [toolbar release];
4330   [super dealloc];
4334 /* called on font panel selection */
4335 - (void)changeFont: (id)sender
4337   NSEvent *e =[[self window] currentEvent];
4338   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4339   id newFont;
4340   float size;
4342   NSTRACE (changeFont);
4343   if (!emacs_event)
4344     return;
4346   if (newFont = [sender convertFont:
4347                            ((struct nsfont_info *)face->font)->nsfont])
4348     {
4349       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4351       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4352       emacs_event->modifiers = 0;
4353       emacs_event->code = KEY_NS_CHANGE_FONT;
4355       size = [newFont pointSize];
4356       ns_input_fontsize = make_number (lrint (size));
4357       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4358       EV_TRAILER (e);
4359     }
4363 - (BOOL)acceptsFirstResponder
4365   NSTRACE (acceptsFirstResponder);
4366   return YES;
4370 - (void)resetCursorRects
4372   NSRect visible = [self visibleRect];
4373   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4374   NSTRACE (resetCursorRects);
4376   if (currentCursor == nil)
4377     currentCursor = [NSCursor arrowCursor];
4379   if (!NSIsEmptyRect (visible))
4380     [self addCursorRect: visible cursor: currentCursor];
4381   [currentCursor setOnMouseEntered: YES];
4386 /*****************************************************************************/
4387 /* Keyboard handling. */
4388 #define NS_KEYLOG 0
4390 - (void)keyDown: (NSEvent *)theEvent
4392   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
4393   int code;
4394   unsigned fnKeysym = 0;
4395   int flags;
4396   static NSMutableArray *nsEvArray;
4397   static BOOL firstTime = YES;
4399   NSTRACE (keyDown);
4401   /* Rhapsody and OS X give up and down events for the arrow keys */
4402   if (ns_fake_keydown == YES)
4403     ns_fake_keydown = NO;
4404   else if ([theEvent type] != NSKeyDown)
4405     return;
4407   if (!emacs_event)
4408     return;
4410  if (![[self window] isKeyWindow])
4411    {
4412      /* XXX: Using NO_SOCK_SIGIO like Carbon causes a condition in which,
4413          when Emacs display updates a different frame from the current one,
4414          and temporarily selects it, then processes some interrupt-driven
4415          input (dispnew.c:3878), OS will send the event to the correct NSWindow,
4416          but for some reason that window has its first responder set to the
4417          NSView most recently updated (I guess), which is not the correct one.
4418          UPDATE: After multi-TTY merge this happens even w/o NO_SOCK_SIGIO */
4419      if ([[theEvent window] isKindOfClass: [EmacsWindow class]])
4420          [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4421      return;
4422    }
4424   if (nsEvArray == nil)
4425     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4427   [NSCursor setHiddenUntilMouseMoves: YES];
4429   if (dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4430     {
4431       clear_mouse_face (dpyinfo);
4432       dpyinfo->mouse_face_hidden = 1;
4433     }
4435   if (!processingCompose)
4436     {
4437       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4438         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4439       /* (Carbon way: [theEvent keyCode]) */
4441       /* is it a "function key"? */
4442       fnKeysym = ns_convert_key (code);
4443       if (fnKeysym)
4444         {
4445           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4446              because Emacs treats Delete and KP-Delete same (in simple.el). */
4447           if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4448             code = 0xFF08; /* backspace */
4449           else
4450             code = fnKeysym;
4451         }
4453       /* are there modifiers? */
4454       emacs_event->modifiers = 0;
4455       flags = [theEvent modifierFlags];
4457       if (flags & NSHelpKeyMask)
4458           emacs_event->modifiers |= hyper_modifier;
4460       if (flags & NSShiftKeyMask)
4461         emacs_event->modifiers |= shift_modifier;
4463       if (flags & NSCommandKeyMask)
4464         {
4465           emacs_event->modifiers |= parse_solitary_modifier (ns_command_modifier);
4466           /* if super (default), take input manager's word so things like
4467              dvorak / qwerty layout work */
4468           if (EQ (ns_command_modifier, Qsuper)
4469               && !fnKeysym
4470               && [[theEvent characters] length] != 0)
4471             {
4472               /* XXX: the code we get will be unshifted, so if we have
4473                  a shift modifier, must convert ourselves */
4474               if (!(flags & NSShiftKeyMask))
4475                 code = [[theEvent characters] characterAtIndex: 0];
4476 #if 0
4477               /* this is ugly and also requires linking w/Carbon framework
4478                  (for LMGetKbdType) so for now leave this rare (?) case
4479                  undealt with.. in future look into CGEvent methods */
4480               else
4481                 {
4482                   long smv = GetScriptManagerVariable (smKeyScript);
4483                   Handle uchrHandle = GetResource
4484                     ('uchr', GetScriptVariable (smv, smScriptKeys));
4485                   UInt32 dummy = 0;
4486                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
4487                                  [[theEvent characters] characterAtIndex: 0],
4488                                  kUCKeyActionDisplay,
4489                                  (flags & ~NSCommandKeyMask) >> 8,
4490                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
4491                                  &dummy, 1, &dummy, &code);
4492                   code &= 0xFF;
4493                 }
4494 #endif
4495             }
4496         }
4498       if (flags & NSControlKeyMask)
4499           emacs_event->modifiers |=
4500             parse_solitary_modifier (ns_control_modifier);
4502       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
4503           emacs_event->modifiers |=
4504             parse_solitary_modifier (ns_function_modifier);
4506       if (flags & NSAlternateKeyMask) /* default = meta */
4507         {
4508           if (EQ (ns_alternate_modifier, Qnone) && !fnKeysym)
4509             {   /* accept pre-interp alt comb */
4510               if ([[theEvent characters] length] > 0)
4511                 code = [[theEvent characters] characterAtIndex: 0];
4512               /*HACK: clear lone shift modifier to stop next if from firing */
4513               if (emacs_event->modifiers == shift_modifier)
4514                 emacs_event->modifiers = 0;
4515             }
4516           else
4517               emacs_event->modifiers |=
4518                 parse_solitary_modifier (ns_alternate_modifier);
4519         }
4521   if (NS_KEYLOG)
4522     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
4523              code, fnKeysym, flags, emacs_event->modifiers);
4525       /* if it was a function key or had modifiers, pass it directly to emacs */
4526       if (fnKeysym || (emacs_event->modifiers
4527                        && [[theEvent charactersIgnoringModifiers] length] > 0))
4528 /*[[theEvent characters] length] */
4529         {
4530           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4531           if (code < 0x20)
4532             code |= (1<<28)|(3<<16);
4533           else if (code == 0x7f)
4534             code |= (1<<28)|(3<<16);
4535           else if (!fnKeysym)
4536             emacs_event->kind = code > 0xFF
4537               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4539           emacs_event->code = code;
4540           EV_TRAILER (theEvent);
4541           return;
4542         }
4543     }
4545   /* if we get here we should send the key for input manager processing */
4546   if (firstTime && [[NSInputManager currentInputManager]
4547                      wantsToDelayTextChangeNotifications] == NO)
4548     fprintf (stderr,
4549           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
4550   firstTime = NO;
4552   if (NS_KEYLOG && !processingCompose)
4553     fprintf (stderr, "keyDown: Begin compose sequence.\n");
4555   processingCompose = YES;
4556   [nsEvArray addObject: theEvent];
4557   [self interpretKeyEvents: nsEvArray];
4558   [nsEvArray removeObject: theEvent];
4562 #ifdef NS_IMPL_COCOA
4563 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
4564    decided not to send key-down for.
4565    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
4566    If it matches one of these, send it on to keyDown. */
4567 -(void)keyUp: (NSEvent *)theEvent
4569   int flags = [theEvent modifierFlags];
4570   int code = [theEvent keyCode];
4571   if (code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
4572     {
4573       if (NS_KEYLOG)
4574         fprintf (stderr, "keyUp: passed test");
4575       ns_fake_keydown = YES;
4576       [self keyDown: theEvent];
4577     }
4579 #endif
4582 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
4585 /* <NSTextInput>: called through when done composing */
4586 - (void)insertText: (id)aString
4588   int code;
4589   int len = [(NSString *)aString length];
4590   int i;
4592   if (NS_KEYLOG)
4593     NSLog (@"insertText '%@'\tlen = %d", aString, len);
4594   processingCompose = NO;
4596   if (!emacs_event)
4597     return;
4599   /* first, clear any working text */
4600   if (workingText != nil)
4601     [self deleteWorkingText];
4603   /* now insert the string as keystrokes */
4604   for (i =0; i<len; i++)
4605     {
4606       code = [aString characterAtIndex: i];
4607       /* TODO: still need this? */
4608       if (code == 0x2DC)
4609         code = '~'; /* 0x7E */
4610       emacs_event->modifiers = 0;
4611       emacs_event->kind
4612         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4613       emacs_event->code = code;
4614       EV_TRAILER ((id)nil);
4615     }
4619 /* <NSTextInput>: inserts display of composing characters */
4620 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
4622   NSString *str = [aString respondsToSelector: @selector (string)] ?
4623     [aString string] : aString;
4624   if (NS_KEYLOG)
4625     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
4626            selRange.length, selRange.location);
4628   if (workingText != nil)
4629     [self deleteWorkingText];
4630   if ([str length] == 0)
4631     return;
4633   if (!emacs_event)
4634     return;
4636   processingCompose = YES;
4637   workingText = [str copy];
4638   ns_working_text = build_string ([workingText UTF8String]);
4640   /* if in "echo area", not true minibuffer, can't show chars in interactive
4641      mode, so call using eval; otherwise we send a key event, which was the
4642      original way this was done */
4643   if (!EQ (Feval (Fcons (intern ("ns-in-echo-area"), Qnil)), Qnil))
4644     {
4645       Feval (Fcons (intern ("ns-echo-working-text"), Qnil));
4646       ns_send_appdefined (-1);
4647     }
4648   else
4649     {
4650       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4651       emacs_event->code = KEY_NS_INSERT_WORKING_TEXT;
4652       EV_TRAILER ((id)nil);
4653     }
4657 /* delete display of composing characters [not in <NSTextInput>] */
4658 - (void)deleteWorkingText
4660   if (workingText == nil)
4661     return;
4662   if (NS_KEYLOG)
4663     fprintf (stderr, "deleteWorkingText len =%d\n", [workingText length]);
4664   [workingText release];
4665   workingText = nil;
4666   processingCompose = NO;
4668   if (!emacs_event)
4669     return;
4671   if (!EQ (Feval (Fcons (intern ("ns-in-echo-area"), Qnil)), Qnil))
4672     {
4673       Feval (Fcons (intern ("ns-unecho-working-text"), Qnil));
4674       ns_send_appdefined (-1);
4675     }
4676   else
4677     {
4678       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4679       emacs_event->code = KEY_NS_DELETE_WORKING_TEXT;
4680       EV_TRAILER ((id)nil);
4681     }
4685 - (BOOL)hasMarkedText
4687   return workingText != nil;
4690 - (NSRange)markedRange
4692   NSRange rng = workingText != nil
4693     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
4694   if (NS_KEYLOG)
4695     NSLog (@"markedRange request");
4696   return rng;
4699 - (void)unmarkText
4701   if (NS_KEYLOG)
4702     NSLog (@"unmark (accept) text");
4703   [self deleteWorkingText];
4704   processingCompose = NO;
4707 /* used to position char selection windows, etc. */
4708 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
4710   NSRect rect;
4711   NSPoint pt;
4712   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
4713   if (NS_KEYLOG)
4714     NSLog (@"firstRectForCharRange request");
4716   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
4717   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
4718   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
4719   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
4720                                        +FRAME_LINE_HEIGHT (emacsframe));
4722   pt = [self convertPoint: pt toView: nil];
4723   pt = [[self window] convertBaseToScreen: pt];
4724   rect.origin = pt;
4725   return rect;
4728 - (NSInteger)conversationIdentifier
4730   return (NSInteger)self;
4733 /* TODO: below here not yet implemented correctly, but may not be needed */
4735 - (void)doCommandBySelector: (SEL)aSelector
4737   if (NS_KEYLOG)
4738     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
4740   if (aSelector == @selector (deleteBackward:))
4741     {
4742       /* happens when user backspaces over an ongoing composition:
4743          throw a 'delete' into the event queue */
4744       if (!emacs_event)
4745         return;
4746       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4747       emacs_event->code = 0xFF08;
4748       EV_TRAILER ((id)nil);
4749     }
4752 - (NSArray *)validAttributesForMarkedText
4754   static NSArray *arr = nil;
4755   if (arr == nil) arr = [NSArray new];
4756  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
4757   return arr;
4760 - (NSRange)selectedRange
4762   if (NS_KEYLOG)
4763     NSLog (@"selectedRange request");
4764   return NSMakeRange (NSNotFound, 0);
4767 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
4769   if (NS_KEYLOG)
4770     NSLog (@"characterIndexForPoint request");
4771   return 0;
4774 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
4776   static NSAttributedString *str = nil;
4777   if (str == nil) str = [NSAttributedString new];
4778   if (NS_KEYLOG)
4779     NSLog (@"attributedSubstringFromRange request");
4780   return str;
4783 /* End <NSTextInput> impl. */
4784 /*****************************************************************************/
4787 /* This is what happens when the user presses a mouse button.  */
4788 - (void)mouseDown: (NSEvent *)theEvent
4790   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
4791   Lisp_Object window;
4793   NSTRACE (mouseDown);
4795   [self deleteWorkingText];
4797   if (!emacs_event)
4798     return;
4800   last_mouse_frame = emacsframe;
4801   /* appears to be needed to prevent spurious movement events generated on
4802      button clicks */
4803   last_mouse_frame->mouse_moved = 0;
4805   if ([theEvent type] == NSScrollWheel)
4806     {
4807       float delta = [theEvent deltaY];
4808       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
4809       if (delta == 0)
4810         return;
4811       emacs_event->kind = WHEEL_EVENT;
4812       emacs_event->code = 0;
4813       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
4814         ((delta > 0) ? up_modifier : down_modifier);
4815     }
4816   else
4817     {
4818       emacs_event->kind = MOUSE_CLICK_EVENT;
4819       emacs_event->code = EV_BUTTON (theEvent);
4820       emacs_event->modifiers = EV_MODIFIERS (theEvent)
4821                              | EV_UDMODIFIERS (theEvent);
4822     }
4823   XSETINT (emacs_event->x, lrint (p.x));
4824   XSETINT (emacs_event->y, lrint (p.y));
4825   EV_TRAILER (theEvent);
4829 - (void)rightMouseDown: (NSEvent *)theEvent
4831   NSTRACE (rightMouseDown);
4832   [self mouseDown: theEvent];
4836 - (void)otherMouseDown: (NSEvent *)theEvent
4838   NSTRACE (otherMouseDown);
4839   [self mouseDown: theEvent];
4843 - (void)mouseUp: (NSEvent *)theEvent
4845   NSTRACE (mouseUp);
4846   [self mouseDown: theEvent];
4850 - (void)rightMouseUp: (NSEvent *)theEvent
4852   NSTRACE (rightMouseUp);
4853   [self mouseDown: theEvent];
4857 - (void)otherMouseUp: (NSEvent *)theEvent
4859   NSTRACE (otherMouseUp);
4860   [self mouseDown: theEvent];
4864 - (void) scrollWheel: (NSEvent *)theEvent
4866   NSTRACE (scrollWheel);
4867   [self mouseDown: theEvent];
4871 /* Tell emacs the mouse has moved. */
4872 - (void)mouseMoved: (NSEvent *)e
4874   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
4875   Lisp_Object frame;
4877 //  NSTRACE (mouseMoved);
4879   last_mouse_movement_time = EV_TIMESTAMP (e);
4880   last_mouse_motion_position
4881     = [self convertPoint: [e locationInWindow] fromView: nil];
4883   /* update any mouse face */
4884   if (dpyinfo->mouse_face_hidden)
4885     {
4886       dpyinfo->mouse_face_hidden = 0;
4887       clear_mouse_face (dpyinfo);
4888     }
4890   /* tooltip handling */
4891   previous_help_echo_string = help_echo_string;
4892   help_echo_string = Qnil;
4894   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
4895                             last_mouse_motion_position.y))
4896     help_echo_string = previous_help_echo_string;
4898   XSETFRAME (frame, emacsframe);
4899   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
4900     {
4901       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
4902          (note_mouse_highlight), which is called through the
4903          note_mouse_movement () call above */
4904       gen_help_event (help_echo_string, frame, help_echo_window,
4905                       help_echo_object, help_echo_pos);
4906     }
4907   else
4908     {
4909       help_echo_string = Qnil;
4910       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
4911     }
4913   if (emacsframe->mouse_moved && send_appdefined)
4914     ns_send_appdefined (-1);
4918 - (void)mouseDragged: (NSEvent *)e
4920   NSTRACE (mouseDragged);
4921   [self mouseMoved: e];
4925 - (void)rightMouseDragged: (NSEvent *)e
4927   NSTRACE (rightMouseDragged);
4928   [self mouseMoved: e];
4932 - (void)otherMouseDragged: (NSEvent *)e
4934   NSTRACE (otherMouseDragged);
4935   [self mouseMoved: e];
4939 - (BOOL)windowShouldClose: (id)sender
4941   NSEvent *e =[[self window] currentEvent];
4943   NSTRACE (windowShouldClose);
4944   windowClosing = YES;
4945   if (!emacs_event)
4946     return NO;
4947   emacs_event->kind = DELETE_WINDOW_EVENT;
4948   emacs_event->modifiers = 0;
4949   emacs_event->code = 0;
4950   EV_TRAILER (e);
4951   /* Don't close this window, let this be done from lisp code.  */
4952   return NO;
4956 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
4957 /* normalize frame to gridded text size */
4959   NSTRACE (windowWillResize);
4960 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
4962   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
4963 #ifdef NS_IMPL_GNUSTEP
4964                                         frameSize.width + 3);
4965 #else
4966                                         frameSize.width);
4967 #endif
4968   if (cols < MINWIDTH)
4969     cols = MINWIDTH;
4970   frameSize.width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (emacsframe, cols);
4972   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, frameSize.height
4973 #ifdef NS_IMPL_GNUSTEP
4974       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + 3
4975         - FRAME_NS_TOOLBAR_HEIGHT (emacsframe));
4976 #else
4977       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
4978         - FRAME_NS_TOOLBAR_HEIGHT (emacsframe));
4979 #endif
4980   if (rows < MINHEIGHT)
4981     rows = MINHEIGHT;
4982   frameSize.height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows)
4983                        + FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
4984                        + FRAME_NS_TOOLBAR_HEIGHT (emacsframe);
4985 #ifdef NS_IMPL_COCOA
4986   {
4987     /* this sets window title to have size in it; the wm does this under GS */
4988     NSRect r = [[self window] frame];
4989     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
4990       {
4991         if (old_title != 0)
4992           {
4993             xfree (old_title);
4994             old_title = 0;
4995           }
4996       }
4997     else
4998       {
4999         char *size_title;
5000         NSWindow *window = [self window];
5001         if (old_title == 0)
5002           {
5003             const char *t = [[[self window] title] UTF8String];
5004             char *pos = strstr (t, "  â€”  ");
5005             if (pos)
5006               *pos = '\0';
5007             old_title = (char *) xmalloc (strlen (t) + 1);
5008             strcpy (old_title, t);
5009           }
5010         size_title = xmalloc (strlen (old_title) + 40);
5011         sprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5012         [window setTitle: [NSString stringWithUTF8String: size_title]];
5013         [window display];
5014         xfree (size_title);
5015       }
5016   }
5017 #endif /* NS_IMPL_COCOA */
5018 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5020   return frameSize;
5024 - (void)windowDidResize: (NSNotification *)notification
5026   NSWindow *theWindow = [notification object];
5028 #ifdef NS_IMPL_GNUSTEP
5029    /* in GNUstep, at least currently, it's possible to get a didResize
5030       without getting a willResize.. therefore we need to act as if we got
5031       the willResize now */
5032   NSSize sz = [theWindow frame].size;
5033   sz = [self windowWillResize: theWindow toSize: sz];
5034 #endif /* NS_IMPL_GNUSTEP */
5036   NSTRACE (windowDidResize);
5037 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5039 #ifdef NS_IMPL_COCOA
5040   if (old_title != 0)
5041     {
5042       xfree (old_title);
5043       old_title = 0;
5044     }
5045 #endif /* NS_IMPL_COCOA */
5047   if (cols > 0 && rows > 0)
5048     x_set_window_size (emacsframe, 0, cols, rows);
5050   ns_send_appdefined (-1);
5052   /* The following line causes a crash on GNUstep.  Adrian Robert
5053      says he doesn't remember why he added this line, but removing it
5054      doesn't seem to cause problems on OSX, either.  */
5055 #if 0
5056   [NSApp stopModal];
5057 #endif
5061 - (void)windowDidBecomeKey: (NSNotification *)notification
5062 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5064   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5065   struct frame *old_focus = dpyinfo->x_focus_frame;
5067   NSTRACE (windowDidBecomeKey);
5069   if (emacsframe != old_focus)
5070     dpyinfo->x_focus_frame = emacsframe;
5072   ns_frame_rehighlight (emacsframe);
5074   if (emacs_event)
5075     {
5076       emacs_event->kind = FOCUS_IN_EVENT;
5077       EV_TRAILER ((id)nil);
5078     }
5082 - (void)windowDidResignKey: (NSNotification *)notification
5083 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5085   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5086   NSTRACE (windowDidResignKey);
5088   if (dpyinfo->x_focus_frame == emacsframe)
5089     dpyinfo->x_focus_frame = 0;
5091   ns_frame_rehighlight (emacsframe);
5093   /* FIXME: for some reason needed on second and subsequent clicks away
5094             from sole-frame Emacs to get hollow box to show */
5095   if (!windowClosing && [[self window] isVisible] == YES)
5096     {
5097       x_update_cursor (emacsframe, 1);
5098       x_set_frame_alpha (emacsframe);
5099     }
5101   if (emacs_event)
5102     {
5103       [self deleteWorkingText];
5104       emacs_event->kind = FOCUS_IN_EVENT;
5105       EV_TRAILER ((id)nil);
5106     }
5110 - (void)windowWillMiniaturize: sender
5112   NSTRACE (windowWillMiniaturize);
5116 - (BOOL)isFlipped
5118   return YES;
5122 - (BOOL)isOpaque
5124   return NO;
5128 - initFrameFromEmacs: (struct frame *)f
5130   NSRect r, wr;
5131   Lisp_Object tem;
5132   NSWindow *win;
5133   NSButton *toggleButton;
5134   int vbextra = NS_SCROLL_BAR_WIDTH (f);
5135   NSSize sz;
5136   NSColor *col;
5137   NSString *name;
5139   NSTRACE (initFrameFromEmacs);
5141   windowClosing = NO;
5142   processingCompose = NO;
5143   scrollbarsNeedingUpdate = 0;
5145 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5147   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5148                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5149   [self initWithFrame: r];
5151   FRAME_NS_VIEW (f) = self;
5152   emacsframe = f;
5153   old_title = 0;
5155   win = [[EmacsWindow alloc]
5156             initWithContentRect: r
5157                       styleMask: (NSResizableWindowMask |
5158                                   NSMiniaturizableWindowMask |
5159                                   NSClosableWindowMask)
5160                         backing: NSBackingStoreBuffered
5161                           defer: YES];
5163   wr = [win frame];
5164   f->border_width = wr.size.width - r.size.width;
5165   FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5167   [win setAcceptsMouseMovedEvents: YES];
5168   [win setDelegate: self];
5169   [win useOptimizedDrawing: YES];
5171   sz.width = FRAME_COLUMN_WIDTH (f);
5172   sz.height = FRAME_LINE_HEIGHT (f);
5173   [win setResizeIncrements: sz];
5175   [[win contentView] addSubview: self];
5177   if (ns_drag_types)
5178     [self registerForDraggedTypes: ns_drag_types];
5180   tem = f->name;
5181   name = [NSString stringWithUTF8String:
5182                    NILP (tem) ? (unsigned char *)"Emacs" : SDATA (tem)];
5183   [win setTitle: name];
5185   /* toolbar support */
5186   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5187                          [NSString stringWithFormat: @"Emacs Frame %d",
5188                                    ns_window_num]];
5189   [win setToolbar: toolbar];
5190   [toolbar setVisible: NO];
5191 #ifdef NS_IMPL_COCOA
5192   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5193   [toggleButton setTarget: self];
5194   [toggleButton setAction: @selector (toggleToolbar: )];
5195 #endif
5196   FRAME_NS_TOOLBAR_HEIGHT (f) = 0;
5198   tem = f->icon_name;
5199   if (!NILP (tem))
5200     [win setMiniwindowTitle:
5201            [NSString stringWithUTF8String: SDATA (tem)]];
5203   {
5204     NSScreen *screen = [win screen];
5206     if (screen != 0)
5207       [win setFrameTopLeftPoint: NSMakePoint
5208            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5209             IN_BOUND (-SCREENMAX,
5210                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5211   }
5213   [win makeFirstResponder: self];
5215   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5216                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5217   [win setBackgroundColor: col];
5218   if ([col alphaComponent] != 1.0)
5219     [win setOpaque: NO];
5221   [self allocateGState];
5223   ns_window_num++;
5224   return self;
5228 - (void)windowDidMove: sender
5230   NSWindow *win = [self window];
5231   NSRect r = [win frame];
5232   NSScreen *screen = [win screen];
5233   NSRect sr = [screen frame];
5235   NSTRACE (windowDidMove);
5237   if (!emacsframe->output_data.ns)
5238     return;
5239   if (screen != nil)
5240     {
5241       emacsframe->left_pos = r.origin.x; /* - sr.origin.x; */
5242       emacsframe->top_pos = sr.size.height -
5243         (r.origin.y + r.size.height); /* + sr.origin.y; */
5244     }
5247 #ifdef NS_IMPL_COCOA
5248 /* if we don't do this manually, the window will resize but not move */
5249 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5251   [[self window] setFrame: newFrame display: NO];
5252   return YES;
5254 #endif
5256 /* Implement this to control size of frame on zoom.
5257 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5258                         defaultFrame:(NSRect)defaultFrame; */
5261 - (void)windowDidDeminiaturize: sender
5263   NSTRACE (windowDidDeminiaturize);
5264   if (!emacsframe->output_data.ns)
5265     return;
5266   emacsframe->async_visible   = 1;
5267   emacsframe->async_iconified = 0;
5268   windows_or_buffers_changed++;
5270   if (emacs_event)
5271     {
5272       emacs_event->kind = ICONIFY_EVENT;
5273       EV_TRAILER ((id)nil);
5274     }
5278 - (void)windowDidExpose: sender
5280   NSTRACE (windowDidExpose);
5281   if (!emacsframe->output_data.ns)
5282     return;
5283   emacsframe->async_visible = 1;
5284   SET_FRAME_GARBAGED (emacsframe);
5286   if (send_appdefined)
5287     ns_send_appdefined (-1);
5291 - (void)windowDidMiniaturize: sender
5293   NSTRACE (windowDidMiniaturize);
5294   if (!emacsframe->output_data.ns)
5295     return;
5297   emacsframe->async_iconified = 1;
5299   if (emacs_event)
5300     {
5301       emacs_event->kind = ICONIFY_EVENT;
5302       EV_TRAILER ((id)nil);
5303     }
5307 - (void)mouseEntered: (NSEvent *)theEvent
5309   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5310   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5311   NSTRACE (mouseEntered);
5313   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5317 - (void)mouseExited: (NSEvent *)theEvent
5319   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5320   NSRect r;
5321   struct ns_display_info *dpyinfo
5322     = emacsframe ? FRAME_NS_DISPLAY_INFO (emacsframe) : NULL;
5324   NSTRACE (mouseExited);
5326   if (dpyinfo || !emacsframe)
5327     return;
5329   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5331   if (emacsframe == dpyinfo->mouse_face_mouse_frame)
5332     {
5333       clear_mouse_face (dpyinfo);
5334       dpyinfo->mouse_face_mouse_frame = 0;
5335     }
5339 - menuDown: sender
5341   NSTRACE (menuDown);
5342   if (context_menu_value == -1)
5343     context_menu_value = [sender tag];
5344   else
5345     find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
5346                                   emacsframe->menu_bar_vector,
5347                                   (void *)[sender tag]);
5348   ns_send_appdefined (-1);
5349   return self;
5353 - (EmacsToolbar *)toolbar
5355   return toolbar;
5359 /* this gets called on toolbar button click */
5360 - toolbarClicked: (id)item
5362   NSEvent *theEvent;
5363   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
5365   NSTRACE (toolbarClicked);
5367   if (!emacs_event)
5368     return self;
5370   /* send first event (for some reason two needed) */
5371   theEvent =[[self window] currentEvent];
5372   emacs_event->kind = TOOL_BAR_EVENT;
5373   XSETFRAME (emacs_event->arg, emacsframe);
5374   EV_TRAILER (theEvent);
5376   emacs_event->kind = TOOL_BAR_EVENT;
5377 /*   XSETINT (emacs_event->code, 0); */
5378   emacs_event->arg = AREF (emacsframe->tool_bar_items,
5379                           idx + TOOL_BAR_ITEM_KEY);
5380   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5381   EV_TRAILER (theEvent);
5382   return self;
5386 - toggleToolbar: (id)sender
5388   Lisp_Object lispFrame;
5389   XSETFRAME (lispFrame, emacsframe);
5390   Feval (Fcons (intern ("ns-toggle-toolbar"), Fcons (lispFrame, Qnil)));
5391   SET_FRAME_GARBAGED (emacsframe);
5392   ns_send_appdefined (-1);
5396 - (void)drawRect: (NSRect)rect
5398   int x = NSMinX (rect), y = NSMinY (rect);
5399   int width = NSWidth (rect), height = NSHeight (rect);
5401   NSTRACE (drawRect);
5403   if (!emacsframe || !emacsframe->output_data.ns)
5404     return;
5406   if (!ns_in_resize)
5407     ns_clear_frame_area (emacsframe, x, y, width, height);
5408   expose_frame (emacsframe, x, y, width, height);
5410   emacsframe->async_visible = 1;
5411   emacsframe->async_iconified = 0;
5413 /*    SET_FRAME_GARBAGED (emacsframe);
5414       ns_send_appdefined (-1); */
5418 /* NSDraggingDestination protocol methods.  Actually this is not really a
5419    protocol, but a category of Object.  O well...  */
5421 -(unsigned int) draggingEntered: (id <NSDraggingInfo>) sender
5423   NSTRACE (draggingEntered);
5424   return NSDragOperationGeneric;
5428 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
5430   return YES;
5434 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
5436   id pb;
5437   int x, y;
5438   NSString *type;
5439   NSEvent *theEvent = [[self window] currentEvent];
5440   NSPoint position;
5442   NSTRACE (performDragOperation);
5444   if (!emacs_event)
5445     return;
5447   position = [self convertPoint: [sender draggingLocation] fromView: nil];
5448   x = lrint (position.x);  y = lrint (position.y);
5450   pb = [sender draggingPasteboard];
5451   type = [pb availableTypeFromArray: ns_drag_types];
5452   if (type == 0)
5453     {
5454       return NO;
5455     }
5456   else if ([type isEqualToString: NSFilenamesPboardType])
5457     {
5458       NSArray *files;
5459       NSEnumerator *fenum;
5460       NSString *file;
5462       if (!(files = [pb propertyListForType: type]))
5463         return NO;
5465       fenum = [files objectEnumerator];
5466       while ( (file = [fenum nextObject]) )
5467         {
5468           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5469           emacs_event->code = KEY_NS_DRAG_FILE;
5470           XSETINT (emacs_event->x, x);
5471           XSETINT (emacs_event->y, y);
5472           ns_input_file = append2 (ns_input_file,
5473                                    build_string ([file UTF8String]));
5474           emacs_event->modifiers = EV_MODIFIERS (theEvent);
5475           EV_TRAILER (theEvent);
5476         }
5477       return YES;
5478     }
5479   else if ([type isEqualToString: NSURLPboardType])
5480     {
5481       NSString *file;
5482       NSURL *fileURL;
5484       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
5485           [fileURL isFileURL] == NO)
5486         return NO;
5488       file = [fileURL path];
5489       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5490       emacs_event->code = KEY_NS_DRAG_FILE;
5491       XSETINT (emacs_event->x, x);
5492       XSETINT (emacs_event->y, y);
5493       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
5494       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5495       EV_TRAILER (theEvent);
5496       return YES;
5497     }
5498   else if ([type isEqualToString: NSStringPboardType]
5499            || [type isEqualToString: NSTabularTextPboardType])
5500     {
5501       NSString *data;
5503       if (! (data = [pb stringForType: type]))
5504         return NO;
5506       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5507       emacs_event->code = KEY_NS_DRAG_TEXT;
5508       XSETINT (emacs_event->x, x);
5509       XSETINT (emacs_event->y, y);
5510       ns_input_text = build_string ([data UTF8String]);
5511       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5512       EV_TRAILER (theEvent);
5513       return YES;
5514     }
5515   else if ([type isEqualToString: NSColorPboardType])
5516     {
5517       NSColor *c = [NSColor colorFromPasteboard: pb];
5518       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5519       emacs_event->code = KEY_NS_DRAG_COLOR;
5520       XSETINT (emacs_event->x, x);
5521       XSETINT (emacs_event->y, y);
5522       ns_input_color = ns_color_to_lisp (c);
5523       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5524       EV_TRAILER (theEvent);
5525       return YES;
5526     }
5527   else if ([type isEqualToString: NSFontPboardType])
5528     {
5529       /* impl based on GNUstep NSTextView.m */
5530       NSData *data = [pb dataForType: NSFontPboardType];
5531       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
5532       NSFont *font = [dict objectForKey: NSFontAttributeName];
5533       char fontSize[10];
5535       if (font == nil)
5536         return NO;
5538       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5539       emacs_event->code = KEY_NS_CHANGE_FONT;
5540       XSETINT (emacs_event->x, x);
5541       XSETINT (emacs_event->y, y);
5542       ns_input_font = build_string ([[font fontName] UTF8String]);
5543       snprintf (fontSize, 10, "%f", [font pointSize]);
5544       ns_input_fontsize = build_string (fontSize);
5545       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5546       EV_TRAILER (theEvent);
5547       return YES;
5548     }
5549   else
5550     {
5551       error ("Invalid data type in dragging pasteboard.");
5552       return NO;
5553     }
5557 - validRequestorForSendType: (NSString *)typeSent
5558                  returnType: (NSString *)typeReturned
5560   NSTRACE (validRequestorForSendType);
5561   if ([ns_send_types indexOfObjectIdenticalTo: typeSent] != NSNotFound &&
5562       [ns_return_types indexOfObjectIdenticalTo: typeSent] != NSNotFound)
5563     return self;
5565   return [super validRequestorForSendType: typeSent
5566                                returnType: typeReturned];
5570 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
5571    (gives a miniaturized version of the window); currently we use the latter for
5572    frames whose active buffer doesn't correspond to any file
5573    (e.g., '*scratch*') */
5574 - setMiniwindowImage: (BOOL) setMini
5576   id image = [[self window] miniwindowImage];
5577   NSTRACE (setMiniwindowImage);
5579   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
5580      about "AppleDockIconEnabled" notwithstanding, however the set message
5581      below has its effect nonetheless. */
5582   if (image != emacsframe->output_data.ns->miniimage)
5583     {
5584       if (image && [image isKindOfClass: [EmacsImage class]])
5585         [image release];
5586       [[self window] setMiniwindowImage:
5587                        setMini ? emacsframe->output_data.ns->miniimage : nil];
5588     }
5590   return self;
5594 - (void) setRows: (int) r andColumns: (int) c
5596   rows = r;
5597   cols = c;
5600 @end  /* EmacsView */
5604 /* ==========================================================================
5606     EmacsWindow implementation
5608    ========================================================================== */
5610 @implementation EmacsWindow
5612 /* called only on resize clicks by special case in EmacsApp-sendEvent */
5613 - (void)mouseDown: (NSEvent *)theEvent
5615   if (ns_in_resize)
5616     {
5617       NSSize size = [[theEvent window] frame].size;
5618       grabOffset = [theEvent locationInWindow];
5619       grabOffset.x = size.width - grabOffset.x;
5620     }
5621   else
5622     [super mouseDown: theEvent];
5626 /* stop resizing */
5627 - (void)mouseUp: (NSEvent *)theEvent
5629   if (ns_in_resize)
5630     {
5631       struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
5632       ns_in_resize = NO;
5633       ns_set_name_as_filename (f);
5634       [self display];
5635       ns_send_appdefined (-1);
5636     }
5637   else
5638     [super mouseUp: theEvent];
5642 /* send resize events */
5643 - (void)mouseDragged: (NSEvent *)theEvent
5645   if (ns_in_resize)
5646     {
5647       NSPoint p = [theEvent locationInWindow];
5648       NSSize size, vettedSize, origSize = [self frame].size;
5650       size.width = p.x + grabOffset.x;
5651       size.height = origSize.height - p.y + grabOffset.y;
5653       if (size.width == origSize.width && size.height == origSize.height)
5654         return;
5656       vettedSize = [[self delegate] windowWillResize: self toSize: size];
5657       if (vettedSize.width != size.width || vettedSize.height != size.height)
5658         {
5659           [[NSNotificationCenter defaultCenter]
5660             postNotificationName: NSWindowDidResizeNotification
5661                           object: self];
5662         }
5663     }
5664   else
5665     [super mouseDragged: theEvent];
5668 @end /* EmacsWindow */
5671 /* ==========================================================================
5673     EmacsScroller implementation
5675    ========================================================================== */
5678 @implementation EmacsScroller
5680 /* for repeat button push */
5681 #define SCROLL_BAR_FIRST_DELAY 0.5
5682 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
5684 + (float) scrollerWidth
5686   /* TODO: if we want to allow variable widths, this is the place to do it,
5687            however neither GNUstep nor Cocoa support it very well */
5688   return [NSScroller scrollerWidth];
5692 - initFrame: (NSRect )r window: (Lisp_Object)nwin
5694   NSTRACE (EmacsScroller_initFrame);
5696   r.size.width = [EmacsScroller scrollerWidth];
5697   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
5698   [self setContinuous: YES];
5699   [self setEnabled: YES];
5701   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
5702      locked against the right, top and bottom edges. */
5703   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
5705   win = nwin;
5706   condemned = NO;
5707   pixel_height = NSHeight (r);
5708   min_portion = 20 / pixel_height;
5710   frame = XFRAME (XWINDOW (win)->frame);
5711   if (FRAME_LIVE_P (frame))
5712     {
5713       int i;
5714       EmacsView *view = FRAME_NS_VIEW (frame);
5715       NSView *sview = [[view window] contentView];
5716       NSArray *subs = [sview subviews];
5718       /* disable optimization stopping redraw of other scrollbars */
5719       view->scrollbarsNeedingUpdate = 0;
5720       for (i =[subs count]-1; i >= 0; i--)
5721         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
5722           view->scrollbarsNeedingUpdate++;
5723       [sview addSubview: self];
5724     }
5726 /*  [self setFrame: r]; */
5728   return self;
5732 - (void)setFrame: (NSRect)newRect
5734   NSTRACE (EmacsScroller_setFrame);
5735 /*  BLOCK_INPUT; */
5736   pixel_height = NSHeight (newRect);
5737   min_portion = 20 / pixel_height;
5738   [super setFrame: newRect];
5739   [self display];
5740 /*  UNBLOCK_INPUT; */
5744 - (void)dealloc
5746   NSTRACE (EmacsScroller_dealloc);
5747   if (!NILP (win))
5748     XWINDOW (win)->vertical_scroll_bar = Qnil;
5749   [super dealloc];
5753 - condemn
5755   NSTRACE (condemn);
5756   condemned =YES;
5757   return self;
5761 - reprieve
5763   NSTRACE (reprieve);
5764   condemned =NO;
5765   return self;
5769 - judge
5771   NSTRACE (judge);
5772   if (condemned)
5773     {
5774       BLOCK_INPUT;
5775       /* ensure other scrollbar updates after deletion */
5776       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
5777       if (view != nil)
5778         view->scrollbarsNeedingUpdate++;
5779       [self removeFromSuperview];
5780       [self release];
5781       UNBLOCK_INPUT;
5782     }
5783   return self;
5787 - (void)resetCursorRects
5789   NSRect visible = [self visibleRect];
5790   NSTRACE (resetCursorRects);
5792   if (!NSIsEmptyRect (visible))
5793     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
5794   [[NSCursor arrowCursor] setOnMouseEntered: YES];
5798 - (int) checkSamePosition: (int) position portion: (int) portion
5799                     whole: (int) whole
5801   return em_position ==position && em_portion ==portion && em_whole ==whole
5802     && portion != whole; /* needed for resize empty buf */
5806 - setPosition: (int)position portion: (int)portion whole: (int)whole
5808   NSTRACE (setPosition);
5810   em_position = position;
5811   em_portion = portion;
5812   em_whole = whole;
5814   if (portion >= whole)
5815     [self setFloatValue: 0.0 knobProportion: 1.0];
5816   else
5817     {
5818       float pos, por;
5819       portion = max ((float)whole*min_portion/pixel_height, portion);
5820       pos = (float)position / (whole - portion);
5821       por = (float)portion/whole;
5822       [self setFloatValue: pos knobProportion: por];
5823     }
5824 #ifdef NS_IMPL_GNUSTEP
5825   [self display];
5826 #endif
5827   return self;
5830 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
5831      drag events will go directly to the EmacsScroller.  Leaving in for now. */
5832 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
5833                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
5835   *part = last_hit_part;
5836   *window = win;
5837   XSETINT (*y, pixel_height);
5838   if ([self floatValue] > 0.999)
5839     XSETINT (*x, pixel_height);
5840   else
5841     XSETINT (*x, pixel_height * [self floatValue]);
5845 /* set up emacs_event */
5846 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
5848   if (!emacs_event)
5849     return;
5851   emacs_event->part = last_hit_part;
5852   emacs_event->code = 0;
5853   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
5854   emacs_event->frame_or_window = win;
5855   emacs_event->timestamp = EV_TIMESTAMP (e);
5856   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
5857   emacs_event->arg = Qnil;
5858   XSETINT (emacs_event->x, loc * pixel_height);
5859   XSETINT (emacs_event->y, pixel_height-20);
5861   n_emacs_events_pending++;
5862   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
5863   EVENT_INIT (*emacs_event);
5864   ns_send_appdefined (-1);
5868 /* called manually thru timer to implement repeated button action w/hold-down */
5869 - repeatScroll: (NSTimer *)scrollEntry
5871   NSEvent *e = [[self window] currentEvent];
5872   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
5873   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
5875   /* clear timer if need be */
5876   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
5877     {
5878         [scroll_repeat_entry invalidate];
5879         [scroll_repeat_entry release];
5880         scroll_repeat_entry = nil;
5882         if (inKnob)
5883           return self;
5885         scroll_repeat_entry
5886           = [[NSTimer scheduledTimerWithTimeInterval:
5887                         SCROLL_BAR_CONTINUOUS_DELAY
5888                                             target: self
5889                                           selector: @selector (repeatScroll:)
5890                                           userInfo: 0
5891                                            repeats: YES]
5892               retain];
5893     }
5895   [self sendScrollEventAtLoc: 0 fromEvent: e];
5896   return self;
5900 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
5901    mouseDragged events without going into a modal loop. */
5902 - (void)mouseDown: (NSEvent *)e
5904   NSRect sr, kr;
5905   /* hitPart is only updated AFTER event is passed on */
5906   NSScrollerPart part = [self testPart: [e locationInWindow]];
5907   double inc = 0.0, loc, kloc, pos;
5908   int edge = 0;
5910   NSTRACE (EmacsScroller_mouseDown);
5912   switch (part)
5913     {
5914     case NSScrollerDecrementPage:
5915         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
5916     case NSScrollerIncrementPage:
5917         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
5918     case NSScrollerDecrementLine:
5919       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
5920     case NSScrollerIncrementLine:
5921       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
5922     case NSScrollerKnob:
5923       last_hit_part = scroll_bar_handle; break;
5924     case NSScrollerKnobSlot:  /* GNUstep-only */
5925       last_hit_part = scroll_bar_move_ratio; break;
5926     default:  /* NSScrollerNoPart? */
5927       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %d\n", part);
5928       return;
5929     }
5931   if (inc != 0.0)
5932     {
5933       pos = 0;      /* ignored */
5935       /* set a timer to repeat, as we can't let superclass do this modally */
5936       scroll_repeat_entry
5937         = [[NSTimer scheduledTimerWithTimeInterval: 0.5
5938                                             target: self
5939                                           selector: @selector (repeatScroll:)
5940                                           userInfo: 0
5941                                            repeats: YES]
5942             retain];
5943     }
5944   else
5945     {
5946       /* handle, or on GNUstep possibly slot */
5947       NSEvent *fake_event;
5949       /* compute float loc in slot and mouse offset on knob */
5950       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
5951                       toView: nil];
5952       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
5953       if (loc <= 0.0)
5954         {
5955           loc = 0.0;
5956           edge = -1;
5957         }
5958       else if (loc >= NSHeight (sr))
5959         {
5960           loc = NSHeight (sr);
5961           edge = 1;
5962         }
5964       if (edge)
5965         kloc = 0.5 * edge;
5966       else
5967         {
5968           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
5969                           toView: nil];
5970           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
5971         }
5972       last_mouse_offset = kloc;
5974       /* if knob, tell emacs a location offset by knob pos
5975          (to indicate top of handle) */
5976       if (part == NSScrollerKnob)
5977           pos = (loc - last_mouse_offset) / NSHeight (sr);
5978       else
5979         /* else this is a slot click on GNUstep: go straight there */
5980         pos = loc / NSHeight (sr);
5982       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
5983       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
5984                                       location: [e locationInWindow]
5985                                  modifierFlags: [e modifierFlags]
5986                                      timestamp: [e timestamp]
5987                                   windowNumber: [e windowNumber]
5988                                        context: [e context]
5989                                    eventNumber: [e eventNumber]
5990                                     clickCount: [e clickCount]
5991                                       pressure: [e pressure]];
5992       [super mouseUp: fake_event];
5993     }
5995   if (part != NSScrollerKnob)
5996     [self sendScrollEventAtLoc: pos fromEvent: e];
6000 /* Called as we manually track scroller drags, rather than superclass. */
6001 - (void)mouseDragged: (NSEvent *)e
6003     NSRect sr;
6004     double loc, pos;
6005     int edge = 0;
6007     NSTRACE (EmacsScroller_mouseDragged);
6009       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6010                       toView: nil];
6011       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6013       if (loc <= 0.0)
6014         {
6015           loc = 0.0;
6016           edge = -1;
6017         }
6018       else if (loc >= NSHeight (sr) + last_mouse_offset)
6019         {
6020           loc = NSHeight (sr) + last_mouse_offset;
6021           edge = 1;
6022         }
6024       pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
6025       [self sendScrollEventAtLoc: pos fromEvent: e];
6029 - (void)mouseUp: (NSEvent *)e
6031   if (scroll_repeat_entry)
6032     {
6033       [scroll_repeat_entry invalidate];
6034       [scroll_repeat_entry release];
6035       scroll_repeat_entry = nil;
6036     }
6037   last_hit_part = 0;
6041 /* treat scrollwheel events in the bar as though they were in the main window */
6042 - (void) scrollWheel: (NSEvent *)theEvent
6044   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
6045   [view mouseDown: theEvent];
6048 @end  /* EmacsScroller */
6052 /* ==========================================================================
6054     EmacsPrefsController implementation
6056    ========================================================================== */
6059 @implementation EmacsPrefsController
6061 /* in Tiger+, can just do [popup selectItemWithTag: tag]; */
6062 static void selectItemWithTag (NSPopUpButton *popup, int tag)
6064   NSEnumerator *items = [[popup itemArray] objectEnumerator];
6065   NSMenuItem *item;
6066   while (item = [items nextObject])
6067     {
6068       if ([item tag] == tag)
6069         {
6070           [popup selectItem: item];
6071           return;
6072         }
6073     }
6076 - init
6078   [NSBundle loadNibNamed: @"preferences" owner: self];
6079   return self;
6083 - (void) showForFrame: (struct frame *)f
6085   frame = f;
6086   [self setPanelFromValues];
6087   [prefsWindow makeKeyAndOrderFront: self];
6088   [prefsWindow display];
6092 /* If you change this, change setPanelFromDefaultValues too. */
6093 - (void) setPanelFromValues
6095   int cursorType
6096     = ns_lisp_to_cursor_type (get_frame_param (frame, Qcursor_type));
6097   prevExpandSpace = XFLOATINT (ns_expand_space);
6099 #ifdef NS_IMPL_COCOA
6100   prevUseHighlightColor = ns_use_system_highlight_color;
6101 #endif
6103   [expandSpaceSlider setFloatValue: prevExpandSpace];
6104   [cursorTypeMatrix selectCellWithTag: (cursorType == FILLED_BOX_CURSOR ? 1 :
6105                                         (cursorType == BAR_CURSOR ? 2 :
6106                                          (cursorType == HBAR_CURSOR ? 3 : 4)))];
6107   selectItemWithTag (alternateModMenu,
6108                      parse_solitary_modifier (ns_alternate_modifier));
6109   selectItemWithTag (commandModMenu,
6110                      parse_solitary_modifier (ns_command_modifier));
6111 #ifdef NS_IMPL_COCOA
6112   selectItemWithTag (controlModMenu,
6113                      parse_solitary_modifier (ns_control_modifier));
6114   selectItemWithTag (functionModMenu,
6115                      parse_solitary_modifier (ns_function_modifier));
6116   [smoothFontsCheck setState: (NILP (ns_antialias_text) ? NO : YES)];
6117   [useQuickdrawCheck setState: (NILP (ns_use_qd_smoothing) ? NO : YES)];
6118   [useSysHiliteCheck setState: (NILP (prevUseHighlightColor) ? NO : YES)];
6119 #endif
6123 /* This and ns_set_default_prefs should be changed together. */
6124 - (void) setPanelFromDefaultValues
6126   [expandSpaceSlider setFloatValue: 0.0];
6127   [cursorTypeMatrix selectCellWithTag: 1]; /* filled box */
6128   selectItemWithTag (alternateModMenu, meta_modifier);
6129   selectItemWithTag (commandModMenu, super_modifier);
6130 #ifdef NS_IMPL_COCOA
6131   selectItemWithTag (controlModMenu, ctrl_modifier);
6132   selectItemWithTag (functionModMenu, 0); /* none */
6133   [smoothFontsCheck setState: YES];
6134   [useQuickdrawCheck setState: NO];
6135   [useSysHiliteCheck setState: YES];
6136 #endif
6140 - (void) setValuesFromPanel
6142   int altTag = [[alternateModMenu selectedItem] tag];
6143   int cmdTag = [[commandModMenu selectedItem] tag];
6144 #ifdef NS_IMPL_COCOA
6145   int ctrlTag = [[controlModMenu selectedItem] tag];
6146   int fnTag = [[functionModMenu selectedItem] tag];
6147 #endif
6148   float expandSpace = [expandSpaceSlider floatValue];
6149   int cursorTag = [[cursorTypeMatrix selectedCell] tag];
6150   Lisp_Object cursor_type = ns_cursor_type_to_lisp
6151        ( cursorTag == 1 ? FILLED_BOX_CURSOR
6152        : cursorTag == 2 ? BAR_CURSOR
6153        : cursorTag == 3 ? HBAR_CURSOR : HOLLOW_BOX_CURSOR);
6155   if (expandSpace != prevExpandSpace)
6156     {
6157       ns_expand_space = make_float (expandSpace);
6158       /* TODO: more needed: store needed metrics in nsfont_info, update
6159          frame default font max_bounds and fontp, recompute faces */
6160 /*         FRAME_LINE_HEIGHT (frame) *= (expandSpace / prevExpandSpace);
6161            x_set_window_size (frame, 0, frame->text_cols, frame->text_lines); */
6162       prevExpandSpace = expandSpace;
6163     }
6165   store_frame_param (frame, Qcursor_type, cursor_type);
6166   x_set_cursor_type (frame, cursor_type, Qnil);  /* FIXME: do only if changed */
6168   ns_alternate_modifier = ns_mod_to_lisp (altTag);
6169   ns_command_modifier = ns_mod_to_lisp (cmdTag);
6170 #ifdef NS_IMPL_COCOA
6171   ns_control_modifier = ns_mod_to_lisp (ctrlTag);
6172   ns_function_modifier = ns_mod_to_lisp (fnTag);
6173   ns_antialias_text = [smoothFontsCheck state] ? Qt : Qnil;
6174   ns_use_qd_smoothing = [useQuickdrawCheck state] ? Qt : Qnil;
6175   ns_use_system_highlight_color = [useSysHiliteCheck state] ? Qt : Qnil;
6176   if (! EQ (ns_use_system_highlight_color, prevUseHighlightColor))
6177     {
6178       prevUseHighlightColor = ns_use_system_highlight_color;
6179       if (EQ (ns_use_system_highlight_color, Qt))
6180         {
6181           ns_selection_color = [[NSUserDefaults standardUserDefaults]
6182                                  stringForKey: @"AppleHighlightColor"];
6183           if (ns_selection_color == nil)
6184             ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
6185         }
6186       else
6187         ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
6188     }
6189 #endif /* NS_IMPL_COCOA */
6190   Fcall_interactively (intern ("ns-save-preferences"), Qnil, Qnil);
6194 /* buttons */
6195 - (IBAction)cancel: (id)sender
6197   [prefsWindow close];
6201 - (IBAction)ok: (id)sender
6203   [self setValuesFromPanel];
6204   [prefsWindow close];
6208 - (IBAction)resetToDefaults: (id)sender
6210   [self setPanelFromDefaultValues];
6214 - (IBAction)runHelp: (id)sender
6216   Feval (Fcons (intern ("info"),
6217                 Fcons (build_string ("(emacs)Mac / GNUstep Customization"),
6218                        Qnil)));
6219   SET_FRAME_GARBAGED (frame);
6220   ns_send_appdefined (-1);
6224 - (IBAction)setColors: (id)sender
6226   Lisp_Object lispFrame;
6227   XSETFRAME (lispFrame, frame);
6228   ns_raise_frame(frame);
6229   Fns_popup_color_panel (lispFrame);
6233 - (IBAction)setDefaultFont: (id)sender
6235   Lisp_Object lispFrame;
6236   XSETFRAME (lispFrame, frame);
6237   ns_raise_frame(frame);
6238   Fns_popup_font_panel (lispFrame);
6241 @end  /* EmacsPrefsController */
6246 /* ==========================================================================
6248    Font-related functions; these used to be in nsfaces.m
6250    ========================================================================== */
6253 Lisp_Object
6254 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
6256   struct font *font = XFONT_OBJECT (font_object);
6258   if (fontset < 0)
6259     fontset = fontset_from_font (font_object);
6260   FRAME_FONTSET (f) = fontset;
6262   if (FRAME_FONT (f) == font)
6263     /* This font is already set in frame F.  There's nothing more to
6264        do.  */
6265     return font_object;
6267   FRAME_FONT (f) = font;
6269   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
6270   FRAME_COLUMN_WIDTH (f) = font->average_width;
6271   FRAME_SPACE_WIDTH (f) = font->space_width;
6272   FRAME_LINE_HEIGHT (f) = font->height;
6274   compute_fringe_widths (f, 1);
6276   /* Compute the scroll bar width in character columns.  */
6277   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6278     {
6279       int wid = FRAME_COLUMN_WIDTH (f);
6280       FRAME_CONFIG_SCROLL_BAR_COLS (f)
6281         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
6282     }
6283   else
6284     {
6285       int wid = FRAME_COLUMN_WIDTH (f);
6286       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6287     }
6289   /* Now make the frame display the given font.  */
6290   if (FRAME_NS_WINDOW (f) != 0)
6291         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6293   return font_object;
6297 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
6298 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
6299          in 1.43. */
6301 const char *
6302 ns_xlfd_to_fontname (const char *xlfd)
6303 /* --------------------------------------------------------------------------
6304     Convert an X font name (XLFD) to an NS font name.
6305     Only family is used.
6306     The string returned is temporarily allocated.
6307    -------------------------------------------------------------------------- */
6309   char *name = xmalloc (180);
6310   int i, len;
6311   const char *ret;
6313   if (!strncmp (xlfd, "--", 2))
6314     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
6315   else
6316     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
6318   /* stopgap for malformed XLFD input */
6319   if (strlen (name) == 0)
6320     strcpy (name, "Monaco");
6322   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
6323      also uppercase after '-' or ' ' */
6324   name[0] = toupper (name[0]);
6325   for (len =strlen (name), i =0; i<len; i++)
6326     {
6327       if (name[i] == '$')
6328         {
6329           name[i] = '-';
6330           if (i+1<len)
6331             name[i+1] = toupper (name[i+1]);
6332         }
6333       else if (name[i] == '_')
6334         {
6335           name[i] = ' ';
6336           if (i+1<len)
6337             name[i+1] = toupper (name[i+1]);
6338         }
6339     }
6340 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
6341   ret = [[NSString stringWithUTF8String: name] UTF8String];
6342   xfree (name);
6343   return ret;
6347 void
6348 syms_of_nsterm ()
6350   NSTRACE (syms_of_nsterm);
6351   DEFVAR_LISP ("ns-input-file", &ns_input_file,
6352               "The file specified in the last NS event.");
6353   ns_input_file =Qnil;
6355   DEFVAR_LISP ("ns-input-text", &ns_input_text,
6356               "The data received in the last NS text drag event.");
6357   ns_input_text =Qnil;
6359   DEFVAR_LISP ("ns-working-text", &ns_working_text,
6360               "String for visualizing working composition sequence.");
6361   ns_working_text =Qnil;
6363   DEFVAR_LISP ("ns-input-font", &ns_input_font,
6364               "The font specified in the last NS event.");
6365   ns_input_font =Qnil;
6367   DEFVAR_LISP ("ns-input-fontsize", &ns_input_fontsize,
6368               "The fontsize specified in the last NS event.");
6369   ns_input_fontsize =Qnil;
6371   DEFVAR_LISP ("ns-input-line", &ns_input_line,
6372                "The line specified in the last NS event.");
6373   ns_input_line =Qnil;
6375   DEFVAR_LISP ("ns-input-color", &ns_input_color,
6376                "The color specified in the last NS event.");
6377   ns_input_color =Qnil;
6379   DEFVAR_LISP ("ns-input-spi-name", &ns_input_spi_name,
6380                "The service name specified in the last NS event.");
6381   ns_input_spi_name =Qnil;
6383   DEFVAR_LISP ("ns-input-spi-arg", &ns_input_spi_arg,
6384                "The service argument specified in the last NS event.");
6385   ns_input_spi_arg =Qnil;
6387   DEFVAR_LISP ("ns-alternate-modifier", &ns_alternate_modifier,
6388                "This variable describes the behavior of the alternate or option key.\n\
6389 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6390 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6391 at all, allowing it to be used at a lower level for accented character entry.");
6393   DEFVAR_LISP ("ns-command-modifier", &ns_command_modifier,
6394                "This variable describes the behavior of the command key.\n\
6395 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6397   DEFVAR_LISP ("ns-control-modifier", &ns_control_modifier,
6398                "This variable describes the behavior of the control key.\n\
6399 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6401   DEFVAR_LISP ("ns-function-modifier", &ns_function_modifier,
6402                "This variable describes the behavior of the function key (on laptops).\n\
6403 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6404 Set to none means that the function key is not interpreted by Emacs at all,\n\
6405 allowing it to be used at a lower level for accented character entry.");
6407   DEFVAR_LISP ("ns-expand-space", &ns_expand_space,
6408                "Amount by which spacing between lines is expanded (positive)\n\
6409 or shrunk (negative).  Zero (the default) means standard line height.\n\
6410 (This variable should only be read, never set.)");
6412   DEFVAR_LISP ("ns-antialias-text", &ns_antialias_text,
6413                "Non-nil (the default) means to render text antialiased. Only has an effect on OS X Panther and above.");
6415   DEFVAR_LISP ("ns-use-qd-smoothing", &ns_use_qd_smoothing,
6416                "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).");
6418   DEFVAR_LISP ("ns-use-system-highlight-color",
6419                &ns_use_system_highlight_color,
6420                "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'.");
6422   staticpro (&ns_display_name_list);
6423   ns_display_name_list = Qnil;
6425   staticpro (&last_mouse_motion_frame);
6426   last_mouse_motion_frame = Qnil;
6428   /*23: now apparently we need to tell emacs what modifiers there are.. */
6429   Qmodifier_value = intern ("modifier-value");
6430   Qalt = intern ("alt");
6431   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
6432   Qhyper = intern ("hyper");
6433   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
6434   Qmeta = intern ("meta");
6435   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
6436   Qsuper = intern ("super");
6437   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
6438   Qcontrol = intern ("control");
6439   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
6441   /* TODO: move to common code */
6442   DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
6443                doc: /* If not nil, Emacs uses toolkit scroll bars.  */);
6444 #ifdef USE_TOOLKIT_SCROLL_BARS
6445   Vx_toolkit_scroll_bars = Qt;
6446 #else
6447   Vx_toolkit_scroll_bars = Qnil;
6448 #endif
6450   /* these are unsupported but we need the declarations to avoid whining
6451      messages from cus-start.el */
6452   DEFVAR_BOOL ("x-use-underline-position-properties",
6453                &x_use_underline_position_properties,
6454      doc: /* NOT SUPPORTED UNDER NS.
6455 *Non-nil means make use of UNDERLINE_POSITION font properties.
6456 A value of nil means ignore them.  If you encounter fonts with bogus
6457 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
6458 to 4.1, set this to nil.
6460 NOTE: Not supported on Mac yet.  */);
6461   x_use_underline_position_properties = 0;
6463   DEFVAR_BOOL ("x-underline-at-descent-line",
6464                &x_underline_at_descent_line,
6465      doc: /* NOT SUPPORTED UNDER NS.
6466 *Non-nil means to draw the underline at the same place as the descent line.
6467 A value of nil means to draw the underline according to the value of the
6468 variable `x-use-underline-position-properties', which is usually at the
6469 baseline level.  The default value is nil.  */);
6470   x_underline_at_descent_line = 0;
6472   /* Tell emacs about this window system. */
6473   Fprovide (intern ("ns"), Qnil);
6477 // arch-tag: 6eaa8f7d-a69b-4e1c-b43d-ab31defbe0d2