upstream
[emacs.git] / src / nsterm.m
blob582e53e202cb239d906e6186b92477e29d78f330
1 /* NeXT/Open/GNUstep / MacOSX communication module.
2    Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2011
3      Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
21 Originally by Carl Edman
22 Updated by Christian Limpach (chris@nice.ch)
23 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
24 MacOSX/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
25 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
28 /* This should be the first include, as it may set up #defines affecting
29    interpretation of even the system includes. */
30 #include <config.h>
32 #include <math.h>
33 #include <sys/types.h>
34 #include <time.h>
35 #include <signal.h>
36 #include <unistd.h>
37 #include <setjmp.h>
39 #include "lisp.h"
40 #include "blockinput.h"
41 #include "sysselect.h"
42 #include "nsterm.h"
43 #include "systime.h"
44 #include "character.h"
45 #include "fontset.h"
46 #include "composite.h"
47 #include "ccl.h"
49 #include "termhooks.h"
50 #include "termopts.h"
51 #include "termchar.h"
53 #include "window.h"
54 #include "keyboard.h"
56 #include "font.h"
58 /* call tracing */
59 #if 0
60 int term_trace_num = 0;
61 #define NSTRACE(x)        fprintf (stderr, "%s:%d: [%d] " #x "\n",         \
62                                 __FILE__, __LINE__, ++term_trace_num)
63 #else
64 #define NSTRACE(x)
65 #endif
68 /* ==========================================================================
70     Local declarations
72    ========================================================================== */
74 /* Convert a symbol indexed with an NSxxx value to a value as defined
75    in keyboard.c (lispy_function_key). I hope this is a correct way
76    of doing things... */
77 static unsigned convert_ns_to_X_keysym[] =
79   NSHomeFunctionKey,            0x50,
80   NSLeftArrowFunctionKey,       0x51,
81   NSUpArrowFunctionKey,         0x52,
82   NSRightArrowFunctionKey,      0x53,
83   NSDownArrowFunctionKey,       0x54,
84   NSPageUpFunctionKey,          0x55,
85   NSPageDownFunctionKey,        0x56,
86   NSEndFunctionKey,             0x57,
87   NSBeginFunctionKey,           0x58,
88   NSSelectFunctionKey,          0x60,
89   NSPrintFunctionKey,           0x61,
90   NSExecuteFunctionKey,         0x62,
91   NSInsertFunctionKey,          0x63,
92   NSUndoFunctionKey,            0x65,
93   NSRedoFunctionKey,            0x66,
94   NSMenuFunctionKey,            0x67,
95   NSFindFunctionKey,            0x68,
96   NSHelpFunctionKey,            0x6A,
97   NSBreakFunctionKey,           0x6B,
99   NSF1FunctionKey,              0xBE,
100   NSF2FunctionKey,              0xBF,
101   NSF3FunctionKey,              0xC0,
102   NSF4FunctionKey,              0xC1,
103   NSF5FunctionKey,              0xC2,
104   NSF6FunctionKey,              0xC3,
105   NSF7FunctionKey,              0xC4,
106   NSF8FunctionKey,              0xC5,
107   NSF9FunctionKey,              0xC6,
108   NSF10FunctionKey,             0xC7,
109   NSF11FunctionKey,             0xC8,
110   NSF12FunctionKey,             0xC9,
111   NSF13FunctionKey,             0xCA,
112   NSF14FunctionKey,             0xCB,
113   NSF15FunctionKey,             0xCC,
114   NSF16FunctionKey,             0xCD,
115   NSF17FunctionKey,             0xCE,
116   NSF18FunctionKey,             0xCF,
117   NSF19FunctionKey,             0xD0,
118   NSF20FunctionKey,             0xD1,
119   NSF21FunctionKey,             0xD2,
120   NSF22FunctionKey,             0xD3,
121   NSF23FunctionKey,             0xD4,
122   NSF24FunctionKey,             0xD5,
124   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
125   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
126   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
128   NSTabCharacter,               0x09,
129   0x19,                         0x09,  /* left tab->regular since pass shift */
130   NSCarriageReturnCharacter,    0x0D,
131   NSNewlineCharacter,           0x0D,
132   NSEnterCharacter,             0x8D,
134   0x1B,                         0x1B   /* escape */
137 static Lisp_Object Qmodifier_value;
138 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper, Qnone;
139 extern Lisp_Object Qcursor_color, Qcursor_type, Qns, Qleft;
141 static Lisp_Object QUTF8_STRING;
143 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
144    the maximum font size to NOT antialias.  On GNUstep there is currently
145    no way to control this behavior. */
146 float ns_antialias_threshold;
148 /* Used to pick up AppleHighlightColor on OS X */
149 NSString *ns_selection_color;
151 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
152 NSString *ns_app_name = @"Emacs";  /* default changed later */
154 /* Display variables */
155 struct ns_display_info *x_display_list; /* Chain of existing displays */
156 Lisp_Object ns_display_name_list;
157 long context_menu_value = 0;
159 /* display update */
160 NSPoint last_mouse_motion_position;
161 static NSRect last_mouse_glyph;
162 static Time last_mouse_movement_time = 0;
163 static Lisp_Object last_mouse_motion_frame;
164 static EmacsScroller *last_mouse_scroll_bar = nil;
165 static struct frame *ns_updating_frame;
166 static NSView *focus_view = NULL;
167 static int ns_window_num =0;
168 static NSRect uRect;
169 static BOOL gsaved = NO;
170 BOOL ns_in_resize = NO;
171 static BOOL ns_fake_keydown = NO;
172 int ns_tmp_flags; /* FIXME */
173 struct nsfont_info *ns_tmp_font; /* FIXME */
174 static BOOL ns_menu_bar_is_hidden = NO;
175 /*static int debug_lock = 0; */
177 /* event loop */
178 static BOOL send_appdefined = YES;
179 static NSEvent *last_appdefined_event = 0;
180 static NSTimer *timed_entry = 0;
181 static NSTimer *fd_entry = nil;
182 static NSTimer *scroll_repeat_entry = nil;
183 static fd_set select_readfds, t_readfds;
184 static struct timeval select_timeout;
185 static int select_nfds;
186 static NSAutoreleasePool *outerpool;
187 static struct input_event *emacs_event = NULL;
188 static struct input_event *q_event_ptr = NULL;
189 static int n_emacs_events_pending = 0;
190 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
191   *ns_pending_service_args;
192 static BOOL inNsSelect = 0;
194 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
195 #define NS_FUNCTION_KEY_MASK 0x800000
196 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
197 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
198 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
199 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
200 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
201 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
202 #define EV_MODIFIERS(e)                               \
203     ((([e modifierFlags] & NSHelpKeyMask) ?           \
204            hyper_modifier : 0)                        \
205      | (!EQ (ns_right_alternate_modifier, Qleft) && \
206         (([e modifierFlags] & NSRightAlternateKeyMask) \
207          == NSRightAlternateKeyMask) ? \
208            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
209      | (([e modifierFlags] & NSAlternateKeyMask) ?                 \
210            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
211      | (([e modifierFlags] & NSShiftKeyMask) ?     \
212            shift_modifier : 0)                        \
213      | (!EQ (ns_right_control_modifier, Qleft) && \
214         (([e modifierFlags] & NSRightControlKeyMask) \
215          == NSRightControlKeyMask) ? \
216            parse_solitary_modifier (ns_right_control_modifier) : 0) \
217      | (([e modifierFlags] & NSControlKeyMask) ?      \
218            parse_solitary_modifier (ns_control_modifier) : 0)     \
219      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
220            parse_solitary_modifier (ns_function_modifier) : 0)    \
221      | (!EQ (ns_right_command_modifier, Qleft) && \
222         (([e modifierFlags] & NSRightCommandKeyMask) \
223          == NSRightCommandKeyMask) ? \
224            parse_solitary_modifier (ns_right_command_modifier) : 0) \
225      | (([e modifierFlags] & NSCommandKeyMask) ?      \
226            parse_solitary_modifier (ns_command_modifier):0))
228 #define EV_UDMODIFIERS(e)                                      \
229     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
230      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
231      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
232      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
233      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
234      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
235      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
236      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
237      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
239 #define EV_BUTTON(e)                                                         \
240     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
241       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
242      [e buttonNumber] - 1)
244 /* Convert the time field to a timestamp in milliseconds. */
245 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
247 /* This is a piece of code which is common to all the event handling
248    methods.  Maybe it should even be a function.  */
249 #define EV_TRAILER(e)                                         \
250   {                                                           \
251   XSETFRAME (emacs_event->frame_or_window, emacsframe);       \
252   if (e) emacs_event->timestamp = EV_TIMESTAMP (e);           \
253   n_emacs_events_pending++;                                   \
254   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);     \
255   EVENT_INIT (*emacs_event);                                  \
256   ns_send_appdefined (-1);                                    \
257   }
259 void x_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
261 /* TODO: get rid of need for these forward declarations */
262 static void ns_condemn_scroll_bars (struct frame *f);
263 static void ns_judge_scroll_bars (struct frame *f);
264 void x_set_frame_alpha (struct frame *f);
267 /* ==========================================================================
269     Utilities
271    ========================================================================== */
274 static Lisp_Object
275 append2 (Lisp_Object list, Lisp_Object item)
276 /* --------------------------------------------------------------------------
277    Utility to append to a list
278    -------------------------------------------------------------------------- */
280   Lisp_Object array[2];
281   array[0] = list;
282   array[1] = Fcons (item, Qnil);
283   return Fnconc (2, &array[0]);
287 void
288 ns_init_paths (void)
289 /* --------------------------------------------------------------------------
290    Used to allow emacs to find its resources under Emacs.app
291    Called from emacs.c at startup.
292    -------------------------------------------------------------------------- */
294   NSBundle *bundle = [NSBundle mainBundle];
295   NSString *binDir = [bundle bundlePath], *resourceDir = [bundle resourcePath];
296   NSString *resourcePath, *resourcePaths;
297   NSRange range;
298   BOOL onWindows = NO; /* how do I determine this? */
299   NSString *pathSeparator = onWindows ? @";" : @":";
300   NSFileManager *fileManager = [NSFileManager defaultManager];
301   BOOL isDir;
302 /*NSLog (@"ns_init_paths: '%@'\n%@\n", [[NSBundle mainBundle] bundlePath], [[NSBundle mainBundle] resourcePath]); */
304   /* get bindir from base */
305   range = [resourceDir rangeOfString: @"Contents"];
306   if (range.location != NSNotFound)
307     {
308       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
309 #ifdef NS_IMPL_COCOA
310       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
311 #endif
312     }
314   /* the following based on Andrew Choi's init_mac_osx_environment () */
315   if (!getenv ("EMACSLOADPATH"))
316     {
317       NSArray *paths = [resourceDir stringsByAppendingPaths:
318                                   [NSArray arrayWithObjects:
319                                          @"site-lisp", @"lisp", @"leim", nil]];
320       NSEnumerator *pathEnum = [paths objectEnumerator];
321       resourcePaths = @"";
322       while (resourcePath = [pathEnum nextObject])
323         {
324           if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
325             if (isDir)
326               {
327                 if ([resourcePaths length] > 0)
328                   resourcePaths
329                     = [resourcePaths stringByAppendingString: pathSeparator];
330                 resourcePaths
331                   = [resourcePaths stringByAppendingString: resourcePath];
332               }
333         }
334       if ([resourcePaths length] > 0)
335         setenv ("EMACSLOADPATH", [resourcePaths UTF8String], 1);
336 /*NSLog (@"loadPath: '%@'\n", resourcePaths); */
337     }
339   if (!getenv ("EMACSPATH"))
340     {
341       NSArray *paths = [binDir stringsByAppendingPaths:
342                                   [NSArray arrayWithObjects: @"bin",
343                                                              @"lib-exec", nil]];
344       NSEnumerator *pathEnum = [paths objectEnumerator];
345       resourcePaths = @"";
346       while (resourcePath = [pathEnum nextObject])
347         {
348           if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
349             if (isDir)
350               {
351                 if ([resourcePaths length] > 0)
352                   resourcePaths
353                     = [resourcePaths stringByAppendingString: pathSeparator];
354                 resourcePaths
355                   = [resourcePaths stringByAppendingString: resourcePath];
356               }
357         }
358       if ([resourcePaths length] > 0)
359         setenv ("EMACSPATH", [resourcePaths UTF8String], 1);
360     }
362   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
363   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
364     {
365       if (isDir)
366         {
367           if (!getenv ("EMACSDATA"))
368             setenv ("EMACSDATA", [resourcePath UTF8String], 1);
369           if (!getenv ("EMACSDOC"))
370             setenv ("EMACSDOC", [resourcePath UTF8String], 1);
371         }
372     }
374   if (!getenv ("INFOPATH"))
375     {
376       resourcePath = [resourceDir stringByAppendingPathComponent: @"info"];
377       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
378         if (isDir)
379           setenv ("INFOPATH", [[resourcePath stringByAppendingString: @":"]
380                                              UTF8String], 1);
381       /* Note, extra colon needed to cause merge w/later user additions. */
382     }
386 static int
387 timeval_subtract (struct timeval *result, struct timeval x, struct timeval y)
388 /* --------------------------------------------------------------------------
389    Subtract the `struct timeval' values X and Y, storing the result in RESULT.
390    Return 1 if the difference is negative, otherwise 0.
391    -------------------------------------------------------------------------- */
393   /* Perform the carry for the later subtraction by updating y.
394      This is safer because on some systems
395      the tv_sec member is unsigned.  */
396   if (x.tv_usec < y.tv_usec)
397     {
398       int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
399       y.tv_usec -= 1000000 * nsec;
400       y.tv_sec += nsec;
401     }
402   if (x.tv_usec - y.tv_usec > 1000000)
403     {
404       int nsec = (y.tv_usec - x.tv_usec) / 1000000;
405       y.tv_usec += 1000000 * nsec;
406       y.tv_sec -= nsec;
407     }
409   /* Compute the time remaining to wait.  tv_usec is certainly positive.  */
410   result->tv_sec = x.tv_sec - y.tv_sec;
411   result->tv_usec = x.tv_usec - y.tv_usec;
413   /* Return indication of whether the result should be considered negative.  */
414   return x.tv_sec < y.tv_sec;
417 static void
418 ns_timeout (int usecs)
419 /* --------------------------------------------------------------------------
420      Blocking timer utility used by ns_ring_bell
421    -------------------------------------------------------------------------- */
423   struct timeval wakeup;
425   EMACS_GET_TIME (wakeup);
427   /* Compute time to wait until, propagating carry from usecs.  */
428   wakeup.tv_usec += usecs;
429   wakeup.tv_sec += (wakeup.tv_usec / 1000000);
430   wakeup.tv_usec %= 1000000;
432   /* Keep waiting until past the time wakeup.  */
433   while (1)
434     {
435       struct timeval timeout;
437       EMACS_GET_TIME (timeout);
439       /* In effect, timeout = wakeup - timeout.
440          Break if result would be negative.  */
441       if (timeval_subtract (&timeout, wakeup, timeout))
442         break;
444       /* Try to wait that long--but we might wake up sooner.  */
445       select (0, NULL, NULL, NULL, &timeout);
446     }
450 void
451 ns_release_object (void *obj)
452 /* --------------------------------------------------------------------------
453     Release an object (callable from C)
454    -------------------------------------------------------------------------- */
456     [(id)obj release];
460 void
461 ns_retain_object (void *obj)
462 /* --------------------------------------------------------------------------
463     Retain an object (callable from C)
464    -------------------------------------------------------------------------- */
466     [(id)obj retain];
470 void *
471 ns_alloc_autorelease_pool (void)
472 /* --------------------------------------------------------------------------
473      Allocate a pool for temporary objects (callable from C)
474    -------------------------------------------------------------------------- */
476   return [[NSAutoreleasePool alloc] init];
480 void
481 ns_release_autorelease_pool (void *pool)
482 /* --------------------------------------------------------------------------
483      Free a pool and temporary objects it refers to (callable from C)
484    -------------------------------------------------------------------------- */
486   ns_release_object (pool);
491 /* ==========================================================================
493     Focus (clipping) and screen update
495    ========================================================================== */
497 static NSRect
498 ns_resize_handle_rect (NSWindow *window)
500   NSRect r = [window frame];
501   r.origin.x = r.size.width - RESIZE_HANDLE_SIZE;
502   r.origin.y = 0;
503   r.size.width = r.size.height = RESIZE_HANDLE_SIZE;
504   return r;
509 // Window constraining
510 // -------------------
512 // To ensure that the windows are not placed under the menu bar, they
513 // are typically moved by the call-back constrainFrameRect. However,
514 // by overriding it, it's possible to inhibit this, leaving the window
515 // in it's original position.
517 // It's possible to hide the menu bar. However, technically, it's only
518 // possible to hide it when the application is active. To ensure that
519 // this work properly, the menu bar and window constraining are
520 // deferred until the application becomes active.
522 // Even though it's not possible to manually move a window above the
523 // top of the screen, it is allowed if it's done programmatically,
524 // when the menu is hidden. This allows the editable area to cover the
525 // full screen height.
527 // Test cases
528 // ----------
530 // Use the following extra files:
532 //    init.el:
533 //       ;; Hide menu and place frame slightly above the top of the screen.
534 //       (setq ns-auto-hide-menu-bar t)
535 //       (set-frame-position (selected-frame) 0 -20)
537 // Test 1:
539 //    emacs -Q -l init.el
541 //    Result: No menu bar, and the title bar should be above the screen.
543 // Test 2:
545 //    emacs -Q
547 //    Result: Menu bar visible, frame placed immediately below the menu.
550 static void
551 ns_constrain_all_frames (void)
553   Lisp_Object tail, frame;
555   FOR_EACH_FRAME (tail, frame)
556     {
557       struct frame *f = XFRAME (frame);
558       if (FRAME_NS_P (f))
559         {
560           NSView *view = FRAME_NS_VIEW (f);
561           /* This no-op will trigger the default window placing
562            * constriant system. */
563           f->output_data.ns->dont_constrain = 0;
564           [[view window] setFrameOrigin:[[view window] frame].origin];
565         }
566     }
570 /* True, if the menu bar should be hidden.  */
572 static BOOL
573 ns_menu_bar_should_be_hidden (void)
575   return !NILP (ns_auto_hide_menu_bar)
576     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
580 /* Show or hide the menu bar, based on user setting.  */
582 static void
583 ns_update_auto_hide_menu_bar (void)
585 #ifndef MAC_OS_X_VERSION_10_6
586 #define MAC_OS_X_VERSION_10_6 1060
587 #endif
588 #ifdef NS_IMPL_COCOA
589 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
590   BLOCK_INPUT;
592   NSTRACE (ns_update_auto_hide_menu_bar);
594   if (NSApp != nil
595       && [NSApp isActive]
596       && [NSApp respondsToSelector:@selector(setPresentationOptions:)])
597     {
598       // Note, "setPresentationOptions" triggers an error unless the
599       // application is active.
600       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
602       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
603         {
604           NSApplicationPresentationOptions options
605             = NSApplicationPresentationAutoHideDock;
607           if (menu_bar_should_be_hidden)
608             options |= NSApplicationPresentationAutoHideMenuBar;
610           [NSApp setPresentationOptions: options];
612           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
614           if (!ns_menu_bar_is_hidden)
615             {
616               ns_constrain_all_frames ();
617             }
618         }
619     }
621   UNBLOCK_INPUT;
622 #endif
623 #endif
627 static void
628 ns_update_begin (struct frame *f)
629 /* --------------------------------------------------------------------------
630    Prepare for a grouped sequence of drawing calls
631    external (RIF) call; whole frame, called before update_window_begin
632    -------------------------------------------------------------------------- */
634   NSView *view = FRAME_NS_VIEW (f);
635   NSTRACE (ns_update_begin);
637   ns_update_auto_hide_menu_bar ();
639   ns_updating_frame = f;
640   [view lockFocus];
642 #ifdef NS_IMPL_GNUSTEP
643   uRect = NSMakeRect (0, 0, 0, 0);
644 #endif
648 static void
649 ns_update_window_begin (struct window *w)
650 /* --------------------------------------------------------------------------
651    Prepare for a grouped sequence of drawing calls
652    external (RIF) call; for one window, called after update_begin
653    -------------------------------------------------------------------------- */
655   struct frame *f = XFRAME (WINDOW_FRAME (w));
656  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
657   NSTRACE (ns_update_window_begin);
659   updated_window = w;
660   set_output_cursor (&w->cursor);
662   BLOCK_INPUT;
664   if (f == hlinfo->mouse_face_mouse_frame)
665     {
666       /* Don't do highlighting for mouse motion during the update.  */
667       hlinfo->mouse_face_defer = 1;
669         /* If the frame needs to be redrawn,
670            simply forget about any prior mouse highlighting.  */
671       if (FRAME_GARBAGED_P (f))
672         hlinfo->mouse_face_window = Qnil;
674       /* (further code for mouse faces ifdef'd out in other terms elided) */
675     }
677   UNBLOCK_INPUT;
681 static void
682 ns_update_window_end (struct window *w, int cursor_on_p,
683                       int mouse_face_overwritten_p)
684 /* --------------------------------------------------------------------------
685    Finished a grouped sequence of drawing calls
686    external (RIF) call; for one window called before update_end
687    -------------------------------------------------------------------------- */
689   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
691   /* note: this fn is nearly identical in all terms */
692   if (!w->pseudo_window_p)
693     {
694       BLOCK_INPUT;
696       if (cursor_on_p)
697         display_and_set_cursor (w, 1,
698                                 output_cursor.hpos, output_cursor.vpos,
699                                 output_cursor.x, output_cursor.y);
701       if (draw_window_fringes (w, 1))
702         x_draw_vertical_border (w);
704       UNBLOCK_INPUT;
705     }
707   /* If a row with mouse-face was overwritten, arrange for
708      frame_up_to_date to redisplay the mouse highlight.  */
709   if (mouse_face_overwritten_p)
710     {
711       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
712       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
713       hlinfo->mouse_face_window = Qnil;
714     }
716   updated_window = NULL;
717   NSTRACE (update_window_end);
721 static void
722 ns_update_end (struct frame *f)
723 /* --------------------------------------------------------------------------
724    Finished a grouped sequence of drawing calls
725    external (RIF) call; for whole frame, called after update_window_end
726    -------------------------------------------------------------------------- */
728   NSView *view = FRAME_NS_VIEW (f);
730 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
731     MOUSE_HL_INFO (f)->mouse_face_defer = 0;
733   BLOCK_INPUT;
735 #ifdef NS_IMPL_GNUSTEP
736   /* trigger flush only in the rectangle we tracked as being drawn */
737   [view unlockFocusNeedsFlush: NO];
738 /*fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", uRect.origin.x, uRect.origin.y, uRect.size.width, uRect.size.height); */
739   [view lockFocusInRect: uRect];
740 #endif
742   [view unlockFocus];
743   [[view window] flushWindow];
745   UNBLOCK_INPUT;
746   ns_updating_frame = NULL;
747   NSTRACE (ns_update_end);
751 static void
752 ns_flush (struct frame *f)
753 /* --------------------------------------------------------------------------
754    external (RIF) call
755    NS impl is no-op since currently we flush in ns_update_end and elsewhere
756    -------------------------------------------------------------------------- */
758     NSTRACE (ns_flush);
762 static void
763 ns_focus (struct frame *f, NSRect *r, int n)
764 /* --------------------------------------------------------------------------
765    Internal: Focus on given frame.  During small local updates this is used to
766      draw, however during large updates, ns_update_begin and ns_update_end are
767      called to wrap the whole thing, in which case these calls are stubbed out.
768      Except, on GNUstep, we accumulate the rectangle being drawn into, because
769      the back end won't do this automatically, and will just end up flushing
770      the entire window.
771    -------------------------------------------------------------------------- */
773 //  NSTRACE (ns_focus);
774 #ifdef NS_IMPL_GNUSTEP
775   NSRect u;
776     if (n == 2)
777       u = NSUnionRect (r[0], r[1]);
778     else if (r)
779       u = *r;
780 #endif
781 /* static int c =0;
782    fprintf (stderr, "focus: %d", c++);
783    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
784    fprintf (stderr, "\n"); */
786   if (f != ns_updating_frame)
787     {
788       NSView *view = FRAME_NS_VIEW (f);
789       if (view != focus_view)
790         {
791           if (focus_view != NULL)
792             {
793               [focus_view unlockFocus];
794               [[focus_view window] flushWindow];
795 /*debug_lock--; */
796             }
798           if (view)
799 #ifdef NS_IMPL_GNUSTEP
800             r ? [view lockFocusInRect: u] : [view lockFocus];
801 #else
802             [view lockFocus];
803 #endif
804           focus_view = view;
805 /*if (view) debug_lock++; */
806         }
807 #ifdef NS_IMPL_GNUSTEP
808       else
809         {
810           /* more than one rect being drawn into */
811           if (view && r)
812             {
813               [view unlockFocus]; /* add prev rect to redraw list */
814               [view lockFocusInRect: u]; /* focus for draw in new rect */
815             }
816         }
817 #endif
818     }
819 #ifdef NS_IMPL_GNUSTEP
820   else
821     {
822       /* in batch mode, but in GNUstep must still track rectangles explicitly */
823       uRect = (r ? NSUnionRect (uRect, u) : [FRAME_NS_VIEW (f) visibleRect]);
824     }
825 #endif
827   /* clipping */
828   if (r)
829     {
830       [[NSGraphicsContext currentContext] saveGraphicsState];
831       if (n == 2)
832         NSRectClipList (r, 2);
833       else
834         NSRectClip (*r);
835       gsaved = YES;
836     }
840 static void
841 ns_unfocus (struct frame *f)
842 /* --------------------------------------------------------------------------
843      Internal: Remove focus on given frame
844    -------------------------------------------------------------------------- */
846 //  NSTRACE (ns_unfocus);
848   if (gsaved)
849     {
850       [[NSGraphicsContext currentContext] restoreGraphicsState];
851       gsaved = NO;
852     }
854   if (f != ns_updating_frame)
855     {
856       if (focus_view != NULL)
857         {
858           [focus_view unlockFocus];
859           [[focus_view window] flushWindow];
860           focus_view = NULL;
861 /*debug_lock--; */
862         }
863     }
867 static void
868 ns_clip_to_row (struct window *w, struct glyph_row *row, int area, BOOL gc)
869 /* --------------------------------------------------------------------------
870      Internal (but parallels other terms): Focus drawing on given row
871    -------------------------------------------------------------------------- */
873   struct frame *f = XFRAME (WINDOW_FRAME (w));
874   NSRect clip_rect;
875   int window_x, window_y, window_width;
877   window_box (w, area, &window_x, &window_y, &window_width, 0);
879   clip_rect.origin.x = window_x - FRAME_INTERNAL_BORDER_WIDTH (f);
880   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
881   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
882   clip_rect.size.width = window_width + 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
883   clip_rect.size.height = row->visible_height;
885   /* allow a full-height row at the top when requested
886      (used to draw fringe all the way through internal border area) */
887   if (gc && clip_rect.origin.y < 5)
888     {
889       clip_rect.origin.y -= FRAME_INTERNAL_BORDER_WIDTH (f);
890       clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
891     }
893   /* likewise at bottom */
894   if (gc &&
895       FRAME_PIXEL_HEIGHT (f) - (clip_rect.origin.y + clip_rect.size.height) < 5)
896     clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
898   ns_focus (f, &clip_rect, 1);
902 static void
903 ns_ring_bell (struct frame *f)
904 /* --------------------------------------------------------------------------
905      "Beep" routine
906    -------------------------------------------------------------------------- */
908   NSTRACE (ns_ring_bell);
909   if (visible_bell)
910     {
911       NSAutoreleasePool *pool;
912       struct frame *frame = SELECTED_FRAME ();
913       NSView *view;
915       BLOCK_INPUT;
916       pool = [[NSAutoreleasePool alloc] init];
918       view = FRAME_NS_VIEW (frame);
919       if (view != nil)
920         {
921           NSRect r, surr;
922           NSPoint dim = NSMakePoint (128, 128);
924           r = [view bounds];
925           r.origin.x += (r.size.width - dim.x) / 2;
926           r.origin.y += (r.size.height - dim.y) / 2;
927           r.size.width = dim.x;
928           r.size.height = dim.y;
929           surr = NSInsetRect (r, -2, -2);
930           ns_focus (frame, &surr, 1);
931           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
932           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
933                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
934           NSRectFill (r);
935           [[view window] flushWindow];
936           ns_timeout (150000);
937           [[view window] restoreCachedImage];
938           [[view window] flushWindow];
939           ns_unfocus (frame);
940         }
941       [pool release];
942       UNBLOCK_INPUT;
943     }
944   else
945     {
946       NSBeep ();
947     }
951 static void
952 ns_reset_terminal_modes (struct terminal *terminal)
953 /*  Externally called as hook */
955   NSTRACE (ns_reset_terminal_modes);
959 static void
960 ns_set_terminal_modes (struct terminal *terminal)
961 /*  Externally called as hook */
963   NSTRACE (ns_set_terminal_modes);
968 /* ==========================================================================
970     Frame / window manager related functions
972    ========================================================================== */
975 static void
976 ns_raise_frame (struct frame *f)
977 /* --------------------------------------------------------------------------
978      Bring window to foreground and make it active
979    -------------------------------------------------------------------------- */
981   NSView *view = FRAME_NS_VIEW (f);
982   check_ns ();
983   BLOCK_INPUT;
984   FRAME_SAMPLE_VISIBILITY (f);
985   if (FRAME_VISIBLE_P (f))
986     {
987       [[view window] makeKeyAndOrderFront: NSApp];
988     }
989   UNBLOCK_INPUT;
993 static void
994 ns_lower_frame (struct frame *f)
995 /* --------------------------------------------------------------------------
996      Send window to back
997    -------------------------------------------------------------------------- */
999   NSView *view = FRAME_NS_VIEW (f);
1000   check_ns ();
1001   BLOCK_INPUT;
1002   [[view window] orderBack: NSApp];
1003   UNBLOCK_INPUT;
1007 static void
1008 ns_frame_raise_lower (struct frame *f, int raise)
1009 /* --------------------------------------------------------------------------
1010      External (hook)
1011    -------------------------------------------------------------------------- */
1013   NSTRACE (ns_frame_raise_lower);
1015   if (raise)
1016     ns_raise_frame (f);
1017   else
1018     ns_lower_frame (f);
1022 static void
1023 ns_frame_rehighlight (struct frame *frame)
1024 /* --------------------------------------------------------------------------
1025      External (hook): called on things like window switching within frame
1026    -------------------------------------------------------------------------- */
1028   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
1029   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1031   NSTRACE (ns_frame_rehighlight);
1032   if (dpyinfo->x_focus_frame)
1033     {
1034       dpyinfo->x_highlight_frame
1035         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1036            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1037            : dpyinfo->x_focus_frame);
1038       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1039         {
1040           FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
1041           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1042         }
1043     }
1044   else
1045       dpyinfo->x_highlight_frame = 0;
1047   if (dpyinfo->x_highlight_frame &&
1048          dpyinfo->x_highlight_frame != old_highlight)
1049     {
1050       if (old_highlight)
1051         {
1052           x_update_cursor (old_highlight, 1);
1053           x_set_frame_alpha (old_highlight);
1054         }
1055       if (dpyinfo->x_highlight_frame)
1056         {
1057           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1058           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1059         }
1060     }
1064 void
1065 x_make_frame_visible (struct frame *f)
1066 /* --------------------------------------------------------------------------
1067      External: Show the window (X11 semantics)
1068    -------------------------------------------------------------------------- */
1070   NSTRACE (x_make_frame_visible);
1071   /* XXX: at some points in past this was not needed, as the only place that
1072      called this (frame.c:Fraise_frame ()) also called raise_lower;
1073      if this ends up the case again, comment this out again. */
1074   if (!FRAME_VISIBLE_P (f))
1075     {
1076       f->async_visible = 1;
1077       ns_raise_frame (f);
1078     }
1082 void
1083 x_make_frame_invisible (struct frame *f)
1084 /* --------------------------------------------------------------------------
1085      External: Hide the window (X11 semantics)
1086    -------------------------------------------------------------------------- */
1088   NSView * view = FRAME_NS_VIEW (f);
1089   NSTRACE (x_make_frame_invisible);
1090   check_ns ();
1091   [[view window] orderOut: NSApp];
1092   f->async_visible = 0;
1093   f->async_iconified = 0;
1097 void
1098 x_iconify_frame (struct frame *f)
1099 /* --------------------------------------------------------------------------
1100      External: Iconify window
1101    -------------------------------------------------------------------------- */
1103   NSView * view = FRAME_NS_VIEW (f);
1104   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1105   NSTRACE (x_iconify_frame);
1106   check_ns ();
1108   if (dpyinfo->x_highlight_frame == f)
1109     dpyinfo->x_highlight_frame = 0;
1111   if ([[view window] windowNumber] <= 0)
1112     {
1113       /* the window is still deferred.  Make it very small, bring it
1114          on screen and order it out. */
1115       NSRect s = { { 100, 100}, {0, 0} };
1116       NSRect t;
1117       t = [[view window] frame];
1118       [[view window] setFrame: s display: NO];
1119       [[view window] orderBack: NSApp];
1120       [[view window] orderOut: NSApp];
1121       [[view window] setFrame: t display: NO];
1122     }
1123   [[view window] miniaturize: NSApp];
1127 void
1128 x_destroy_window (struct frame *f)
1129 /* --------------------------------------------------------------------------
1130      External: Delete the window
1131    -------------------------------------------------------------------------- */
1133   NSView *view = FRAME_NS_VIEW (f);
1134   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1135   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1136   NSTRACE (x_destroy_window);
1137   check_ns ();
1139   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1141   BLOCK_INPUT;
1143   free_frame_menubar (f);
1145   if (FRAME_FACE_CACHE (f))
1146     free_frame_faces (f);
1148   if (f == dpyinfo->x_focus_frame)
1149     dpyinfo->x_focus_frame = 0;
1150   if (f == dpyinfo->x_highlight_frame)
1151     dpyinfo->x_highlight_frame = 0;
1152   if (f == hlinfo->mouse_face_mouse_frame)
1153     {
1154       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
1155       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
1156       hlinfo->mouse_face_window = Qnil;
1157       hlinfo->mouse_face_deferred_gc = 0;
1158       hlinfo->mouse_face_mouse_frame = 0;
1159     }
1161   xfree (f->output_data.ns);
1163   [[view window] close];
1164   [view release];
1166   ns_window_num--;
1167   UNBLOCK_INPUT;
1171 void
1172 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1173 /* --------------------------------------------------------------------------
1174      External: Position the window
1175    -------------------------------------------------------------------------- */
1177   NSView *view = FRAME_NS_VIEW (f);
1178   NSArray *screens = [NSScreen screens];
1179   NSScreen *fscreen = [screens objectAtIndex: 0];
1180   NSScreen *screen = [[view window] screen];
1182   NSTRACE (x_set_offset);
1184   BLOCK_INPUT;
1186   f->left_pos = xoff;
1187   f->top_pos = yoff;
1189   if (view != nil && screen && fscreen)
1190     {
1191       f->left_pos = f->size_hint_flags & XNegative
1192         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1193         : f->left_pos;
1194       /* We use visibleFrame here to take menu bar into account.
1195          Ideally we should also adjust left/top with visibleFrame.origin.  */
1197       f->top_pos = f->size_hint_flags & YNegative
1198         ? ([screen visibleFrame].size.height + f->top_pos
1199            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1200            - FRAME_TOOLBAR_HEIGHT (f))
1201         : f->top_pos;
1202 #ifdef NS_IMPL_GNUSTEP
1203       if (f->left_pos < 100)
1204         f->left_pos = 100;  /* don't overlap menu */
1205 #endif
1206       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1207          menu bar.  */
1208       f->output_data.ns->dont_constrain = 0;
1209       [[view window] setFrameTopLeftPoint:
1210                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1211                                     SCREENMAXBOUND ([fscreen frame].size.height
1212                                                     - NS_TOP_POS (f)))];
1213       f->size_hint_flags &= ~(XNegative|YNegative);
1214     }
1216   UNBLOCK_INPUT;
1220 void
1221 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1222 /* --------------------------------------------------------------------------
1223      Adjust window pixel size based on given character grid size
1224      Impl is a bit more complex than other terms, need to do some
1225      internal clipping.
1226    -------------------------------------------------------------------------- */
1228   EmacsView *view = FRAME_NS_VIEW (f);
1229   EmacsToolbar *toolbar = [view toolbar];
1230   NSWindow *window = [view window];
1231   NSRect wr = [window frame];
1232   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1233   int pixelwidth, pixelheight;
1234   static int oldRows, oldCols, oldFontWidth, oldFontHeight;
1235   static int oldTB;
1236   static struct frame *oldF;
1238   NSTRACE (x_set_window_size);
1240   if (view == nil ||
1241       (f == oldF
1242        && rows == oldRows && cols == oldCols
1243        && oldFontWidth == FRAME_COLUMN_WIDTH (f)
1244        && oldFontHeight == FRAME_LINE_HEIGHT (f)
1245        && oldTB == tb))
1246     return;
1248 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1250   BLOCK_INPUT;
1252   check_frame_size (f, &rows, &cols);
1253   oldF = f;
1254   oldRows = rows;
1255   oldCols = cols;
1256   oldFontWidth = FRAME_COLUMN_WIDTH (f);
1257   oldFontHeight = FRAME_LINE_HEIGHT (f);
1258   oldTB = tb;
1260   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1261   compute_fringe_widths (f, 0);
1263   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1264   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1266   /* If we have a toolbar, take its height into account. */
1267   if (tb)
1268     /* NOTE: previously this would generate wrong result if toolbar not
1269              yet displayed and fixing toolbar_height=32 helped, but
1270              now (200903) seems no longer needed */
1271     FRAME_TOOLBAR_HEIGHT (f) =
1272       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1273         - FRAME_NS_TITLEBAR_HEIGHT (f);
1274   else
1275     FRAME_TOOLBAR_HEIGHT (f) = 0;
1277   wr.size.width = pixelwidth + f->border_width;
1278   wr.size.height = pixelheight + FRAME_NS_TITLEBAR_HEIGHT (f)
1279                   + FRAME_TOOLBAR_HEIGHT (f);
1281   /* Do not try to constrain to this screen.  We may have multiple
1282      screens, and want Emacs to span those.  Constraining to screen
1283      prevents that, and that is not nice to the user.  */
1284  if (f->output_data.ns->zooming)
1285    f->output_data.ns->zooming = 0;
1286  else
1287    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1289   [view setRows: rows andColumns: cols];
1290   [window setFrame: wr display: YES];
1292 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1294   /* This is a trick to compensate for Emacs' managing the scrollbar area
1295      as a fixed number of standard character columns.  Instead of leaving
1296      blank space for the extra, we chopped it off above.  Now for
1297      left-hand scrollbars, we shift all rendering to the left by the
1298      difference between the real width and Emacs' imagined one.  For
1299      right-hand bars, don't worry about it since the extra is never used.
1300      (Obviously doesn't work for vertically split windows tho..) */
1301   {
1302     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1303       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1304                      - NS_SCROLL_BAR_WIDTH (f), 0)
1305       : NSMakePoint (0, 0);
1306     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1307     [view setBoundsOrigin: origin];
1308   }
1310   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1311   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1312   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1313 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1315   mark_window_cursors_off (XWINDOW (f->root_window));
1316   cancel_mouse_face (f);
1318   UNBLOCK_INPUT;
1323 /* ==========================================================================
1325     Color management
1327    ========================================================================== */
1330 NSColor *
1331 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1333   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1334   if (idx < 1 || idx >= color_table->avail)
1335     return nil;
1336   return color_table->colors[idx];
1340 unsigned long
1341 ns_index_color (NSColor *color, struct frame *f)
1343   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1344   int idx;
1345   NSNumber *index;
1347   if (!color_table->colors)
1348     {
1349       color_table->size = NS_COLOR_CAPACITY;
1350       color_table->avail = 1; /* skip idx=0 as marker */
1351       color_table->colors
1352         = (NSColor **)xmalloc (color_table->size * sizeof (NSColor *));
1353       color_table->colors[0] = nil;
1354       color_table->empty_indices = [[NSMutableSet alloc] init];
1355     }
1357   /* do we already have this color ? */
1358   {
1359     int i;
1360     for (i = 1; i < color_table->avail; i++)
1361       {
1362         if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1363           {
1364             [color_table->colors[i] retain];
1365             return i;
1366           }
1367       }
1368   }
1370   if ([color_table->empty_indices count] > 0)
1371     {
1372       index = [color_table->empty_indices anyObject];
1373       [color_table->empty_indices removeObject: index];
1374       idx = [index unsignedIntValue];
1375     }
1376   else
1377     {
1378       if (color_table->avail == color_table->size)
1379         {
1380           color_table->size += NS_COLOR_CAPACITY;
1381           color_table->colors
1382             = (NSColor **)xrealloc (color_table->colors,
1383                                     color_table->size * sizeof (NSColor *));
1384         }
1385       idx = color_table->avail++;
1386     }
1388   color_table->colors[idx] = color;
1389   [color retain];
1390 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1391   return idx;
1395 void
1396 ns_free_indexed_color (unsigned long idx, struct frame *f)
1398   struct ns_color_table *color_table;
1399   NSColor *color;
1400   NSNumber *index;
1402   if (!f)
1403     return;
1405   color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1407   if (idx <= 0 || idx >= color_table->size) {
1408     message1("ns_free_indexed_color: Color index out of range.\n");
1409     return;
1410   }
1412   index = [NSNumber numberWithUnsignedInt: idx];
1413   if ([color_table->empty_indices containsObject: index]) {
1414     message1("ns_free_indexed_color: attempt to free already freed color.\n");
1415     return;
1416   }
1418   color = color_table->colors[idx];
1419   [color release];
1420   color_table->colors[idx] = nil;
1421   [color_table->empty_indices addObject: [NSNumber numberWithUnsignedInt: idx]];
1422 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1426 static int
1427 ns_get_color (const char *name, NSColor **col)
1428 /* --------------------------------------------------------------------------
1429      Parse a color name
1430    -------------------------------------------------------------------------- */
1431 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1432    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1433    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1435   NSColor *new = nil;
1436   static char hex[20];
1437   int scaling;
1438   float r = -1.0, g, b;
1439   NSString *nsname = [NSString stringWithUTF8String: name];
1441 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1442   BLOCK_INPUT;
1444   if ([nsname isEqualToString: @"ns_selection_color"])
1445     {
1446       nsname = ns_selection_color;
1447       name = [ns_selection_color UTF8String];
1448     }
1450   /* First, check for some sort of numeric specification. */
1451   hex[0] = '\0';
1453   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1454     {
1455       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1456       [scanner scanFloat: &r];
1457       [scanner scanFloat: &g];
1458       [scanner scanFloat: &b];
1459     }
1460   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1461     {
1462       strncpy (hex, name + 4, 19);
1463       hex[19] = '\0';
1464       scaling = (strlen(hex) - 2) / 3;
1465     }
1466   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1467     {
1468       int len = (strlen(name) - 1);
1469       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1470       int i;
1471       scaling = strlen(name+start) / 3;
1472       for (i=0; i<3; i++) {
1473         strncpy(hex + i * (scaling + 1), name + start + i * scaling, scaling);
1474         hex[(i+1) * (scaling + 1) - 1] = '/';
1475       }
1476       hex[3 * (scaling + 1) - 1] = '\0';
1477     }
1479   if (hex[0])
1480     {
1481       int rr, gg, bb;
1482       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1483       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1484         {
1485           r = rr / fscale;
1486           g = gg / fscale;
1487           b = bb / fscale;
1488         }
1489     }
1491   if (r >= 0.0)
1492     {
1493       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1494       UNBLOCK_INPUT;
1495       return 0;
1496     }
1498   /* Otherwise, color is expected to be from a list */
1499   {
1500     NSEnumerator *lenum, *cenum;
1501     NSString *name;
1502     NSColorList *clist;
1504 #ifdef NS_IMPL_GNUSTEP
1505     /* XXX: who is wrong, the requestor or the implementation? */
1506     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1507         == NSOrderedSame)
1508       nsname = @"highlightColor";
1509 #endif
1511     lenum = [[NSColorList availableColorLists] objectEnumerator];
1512     while ( (clist = [lenum nextObject]) && new == nil)
1513       {
1514         cenum = [[clist allKeys] objectEnumerator];
1515         while ( (name = [cenum nextObject]) && new == nil )
1516           {
1517             if ([name compare: nsname
1518                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1519               new = [clist colorWithKey: name];
1520           }
1521       }
1522   }
1524   if (new)
1525     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1526   UNBLOCK_INPUT;
1527   return new ? 0 : 1;
1531 static NSColor *
1532 ns_get_color_default (const char *name, NSColor *dflt)
1533 /* --------------------------------------------------------------------------
1534      Parse a color or use a default value
1535    -------------------------------------------------------------------------- */
1537   NSColor * col;
1539   if (ns_get_color (name, &col))
1540     return dflt;
1541   else
1542     return col;
1547 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1548 /* --------------------------------------------------------------------------
1549      Convert a Lisp string object to a NS color
1550    -------------------------------------------------------------------------- */
1552   NSTRACE (ns_lisp_to_color);
1553   if (STRINGP (color))
1554     return ns_get_color (SDATA (color), col);
1555   else if (SYMBOLP (color))
1556     return ns_get_color (SDATA (SYMBOL_NAME (color)), col);
1557   return 1;
1561 Lisp_Object
1562 ns_color_to_lisp (NSColor *col)
1563 /* --------------------------------------------------------------------------
1564      Convert a color to a lisp string with the RGB equivalent
1565    -------------------------------------------------------------------------- */
1567   CGFloat red, green, blue, alpha, gray;
1568   char buf[1024];
1569   const char *str;
1570   NSTRACE (ns_color_to_lisp);
1572   BLOCK_INPUT;
1573   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1575       if ((str =[[col colorNameComponent] UTF8String]))
1576         {
1577           UNBLOCK_INPUT;
1578           return build_string ((char *)str);
1579         }
1581     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1582         getRed: &red green: &green blue: &blue alpha: &alpha];
1583   if (red ==green && red ==blue)
1584     {
1585       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1586             getWhite: &gray alpha: &alpha];
1587       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1588                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1589       UNBLOCK_INPUT;
1590       return build_string (buf);
1591     }
1593   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1594             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1596   UNBLOCK_INPUT;
1597   return build_string (buf);
1601 void
1602 ns_query_color(void *col, XColor *color_def, int setPixel)
1603 /* --------------------------------------------------------------------------
1604          Get ARGB values out of NSColor col and put them into color_def.
1605          If setPixel, set the pixel to a concatenated version.
1606          and set color_def pixel to the resulting index.
1607    -------------------------------------------------------------------------- */
1609   CGFloat r, g, b, a;
1611   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1612   color_def->red   = r * 65535;
1613   color_def->green = g * 65535;
1614   color_def->blue  = b * 65535;
1616   if (setPixel == YES)
1617     color_def->pixel
1618       = ARGB_TO_ULONG((int)(a*255),
1619                       (int)(r*255), (int)(g*255), (int)(b*255));
1624 ns_defined_color (struct frame *f,
1625                   const char *name,
1626                   XColor *color_def,
1627                   int alloc,
1628                   char makeIndex)
1629 /* --------------------------------------------------------------------------
1630          Return 1 if named color found, and set color_def rgb accordingly.
1631          If makeIndex and alloc are nonzero put the color in the color_table,
1632          and set color_def pixel to the resulting index.
1633          If makeIndex is zero, set color_def pixel to ARGB.
1634          Return 0 if not found
1635    -------------------------------------------------------------------------- */
1637   NSColor *col;
1638   NSTRACE (ns_defined_color);
1640   BLOCK_INPUT;
1641   if (ns_get_color (name, &col) != 0) /* Color not found  */
1642     {
1643       UNBLOCK_INPUT;
1644       return 0;
1645     }
1646   if (makeIndex && alloc)
1647     color_def->pixel = ns_index_color (col, f);
1648   ns_query_color (col, color_def, !makeIndex);
1649   UNBLOCK_INPUT;
1650   return 1;
1654 unsigned long
1655 ns_get_rgb_color (struct frame *f, float r, float g, float b, float a)
1656 /* --------------------------------------------------------------------------
1657     return an autoreleased RGB color
1658    -------------------------------------------------------------------------- */
1660 /*static int c = 1; fprintf (stderr, "color request %d\n", c++); */
1661   if (r < 0.0) r = 0.0;
1662   else if (r > 1.0) r = 1.0;
1663   if (g < 0.0) g = 0.0;
1664   else if (g > 1.0) g = 1.0;
1665   if (b < 0.0) b = 0.0;
1666   else if (b > 1.0) b = 1.0;
1667   if (a < 0.0) a = 0.0;
1668   else if (a > 1.0) a = 1.0;
1669   return (unsigned long) ns_index_color(
1670     [NSColor colorWithCalibratedRed: r green: g blue: b alpha: a], f);
1674 void
1675 x_set_frame_alpha (struct frame *f)
1676 /* --------------------------------------------------------------------------
1677      change the entire-frame transparency
1678    -------------------------------------------------------------------------- */
1680   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1681   EmacsView *view = FRAME_NS_VIEW (f);
1682   double alpha = 1.0;
1683   double alpha_min = 1.0;
1685   if (dpyinfo->x_highlight_frame == f)
1686     alpha = f->alpha[0];
1687   else
1688     alpha = f->alpha[1];
1690   if (FLOATP (Vframe_alpha_lower_limit))
1691     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1692   else if (INTEGERP (Vframe_alpha_lower_limit))
1693     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1695   if (alpha < 0.0)
1696     return;
1697   else if (1.0 < alpha)
1698     alpha = 1.0;
1699   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1700     alpha = alpha_min;
1702 #ifdef NS_IMPL_COCOA
1703   [[view window] setAlphaValue: alpha];
1704 #endif
1708 /* ==========================================================================
1710     Mouse handling
1712    ========================================================================== */
1715 void
1716 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1717 /* --------------------------------------------------------------------------
1718      Programmatically reposition mouse pointer in pixel coordinates
1719    -------------------------------------------------------------------------- */
1721   NSTRACE (x_set_mouse_pixel_position);
1722   ns_raise_frame (f);
1723 #if 0
1724   /* FIXME: this does not work, and what about GNUstep? */
1725 #ifdef NS_IMPL_COCOA
1726   [FRAME_NS_VIEW (f) lockFocus];
1727   PSsetmouse ((float)pix_x, (float)pix_y);
1728   [FRAME_NS_VIEW (f) unlockFocus];
1729 #endif
1730 #endif
1734 void
1735 x_set_mouse_position (struct frame *f, int h, int v)
1736 /* --------------------------------------------------------------------------
1737      Programmatically reposition mouse pointer in character coordinates
1738    -------------------------------------------------------------------------- */
1740   int pix_x, pix_y;
1742   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1743   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1745   if (pix_x < 0) pix_x = 0;
1746   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1748   if (pix_y < 0) pix_y = 0;
1749   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1751   x_set_mouse_pixel_position (f, pix_x, pix_y);
1755 static int
1756 note_mouse_movement (struct frame *frame, float x, float y)
1757 /*   ------------------------------------------------------------------------
1758      Called by EmacsView on mouseMovement events.  Passes on
1759      to emacs mainstream code if we moved off of a rect of interest
1760      known as last_mouse_glyph.
1761      ------------------------------------------------------------------------ */
1763 //  NSTRACE (note_mouse_movement);
1765   XSETFRAME (last_mouse_motion_frame, frame);
1767   /* Note, this doesn't get called for enter/leave, since we don't have a
1768      position.  Those are taken care of in the corresponding NSView methods. */
1770   /* has movement gone beyond last rect we were tracking? */
1771   if (x < last_mouse_glyph.origin.x ||
1772       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1773       y < last_mouse_glyph.origin.y ||
1774       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1775     {
1776       ns_update_begin(frame);
1777       frame->mouse_moved = 1;
1778       note_mouse_highlight (frame, x, y);
1779       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1780       ns_update_end(frame);
1781       return 1;
1782     }
1784   return 0;
1788 static void
1789 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1790                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1791                    Time *time)
1792 /* --------------------------------------------------------------------------
1793     External (hook): inform emacs about mouse position and hit parts.
1794     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1795     x & y should be position in the scrollbar (the whole bar, not the handle)
1796     and length of scrollbar respectively
1797    -------------------------------------------------------------------------- */
1799   id view;
1800   NSPoint position;
1801   int xchar, ychar;
1802   Lisp_Object frame, tail;
1803   struct frame *f;
1804   struct ns_display_info *dpyinfo;
1806   NSTRACE (ns_mouse_position);
1808   if (*fp == NULL)
1809     {
1810       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1811       return;
1812     }
1814   dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1816   BLOCK_INPUT;
1818   if (last_mouse_scroll_bar != nil && insist == 0)
1819     {
1820       /* TODO: we do not use this path at the moment because drag events will
1821            go directly to the EmacsScroller.  Leaving code in for now. */
1822       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1823                                               x: x y: y];
1824       if (time) *time = last_mouse_movement_time;
1825       last_mouse_scroll_bar = nil;
1826     }
1827   else
1828     {
1829       /* Clear the mouse-moved flag for every frame on this display.  */
1830       FOR_EACH_FRAME (tail, frame)
1831         if (FRAME_NS_P (XFRAME (frame))
1832             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1833           XFRAME (frame)->mouse_moved = 0;
1835       last_mouse_scroll_bar = nil;
1836       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1837         f = last_mouse_frame;
1838       else
1839         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1840                                     : SELECTED_FRAME ();
1842       if (f && f->output_data.ns)  /* TODO: 2nd check no longer needed? */
1843         {
1844           view = FRAME_NS_VIEW (*fp);
1846           position = [[view window] mouseLocationOutsideOfEventStream];
1847           position = [view convertPoint: position fromView: nil];
1848           remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1849 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1851           if (bar_window) *bar_window = Qnil;
1852           if (part) *part = 0; /*scroll_bar_handle; */
1854           if (x) XSETINT (*x, lrint (position.x));
1855           if (y) XSETINT (*y, lrint (position.y));
1856           if (time) *time = last_mouse_movement_time;
1857           *fp = f;
1858         }
1859     }
1861   UNBLOCK_INPUT;
1865 static void
1866 ns_frame_up_to_date (struct frame *f)
1867 /* --------------------------------------------------------------------------
1868     External (hook): Fix up mouse highlighting right after a full update.
1869     Some highlighting was deferred if GC was happening during
1870     note_mouse_highlight (), while other highlighting was deferred for update.
1871    -------------------------------------------------------------------------- */
1873   NSTRACE (ns_frame_up_to_date);
1875   if (FRAME_NS_P (f))
1876     {
1877       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1878       if ((hlinfo->mouse_face_deferred_gc || f ==hlinfo->mouse_face_mouse_frame)
1879       /*&& hlinfo->mouse_face_mouse_frame*/)
1880         {
1881           BLOCK_INPUT;
1882           ns_update_begin(f);
1883           if (hlinfo->mouse_face_mouse_frame)
1884             note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1885                                   hlinfo->mouse_face_mouse_x,
1886                                   hlinfo->mouse_face_mouse_y);
1887           hlinfo->mouse_face_deferred_gc = 0;
1888           ns_update_end(f);
1889           UNBLOCK_INPUT;
1890         }
1891     }
1895 void
1896 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1897 /* --------------------------------------------------------------------------
1898     External (RIF): set frame mouse pointer type.
1899    -------------------------------------------------------------------------- */
1901   NSTRACE (ns_define_frame_cursor);
1902   if (FRAME_POINTER_TYPE (f) != cursor)
1903     {
1904       EmacsView *view = FRAME_NS_VIEW (f);
1905       FRAME_POINTER_TYPE (f) = cursor;
1906       [[view window] invalidateCursorRectsForView: view];
1907       /* Redisplay assumes this function also draws the changed frame
1908          cursor, but this function doesn't, so do it explicitly.  */
1909       x_update_cursor (f, 1);
1910     }
1915 /* ==========================================================================
1917     Keyboard handling
1919    ========================================================================== */
1922 static unsigned
1923 ns_convert_key (unsigned code)
1924 /* --------------------------------------------------------------------------
1925     Internal call used by NSView-keyDown.
1926    -------------------------------------------------------------------------- */
1928   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1929                                 / sizeof (convert_ns_to_X_keysym[0]));
1930   unsigned keysym;
1931   /* An array would be faster, but less easy to read. */
1932   for (keysym = 0; keysym < last_keysym; keysym += 2)
1933     if (code == convert_ns_to_X_keysym[keysym])
1934       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1935   return 0;
1936 /* if decide to use keyCode and Carbon table, use this line:
1937      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1941 char *
1942 x_get_keysym_name (int keysym)
1943 /* --------------------------------------------------------------------------
1944     Called by keyboard.c.  Not sure if the return val is important, except
1945     that it be unique.
1946    -------------------------------------------------------------------------- */
1948   static char value[16];
1949   NSTRACE (x_get_keysym_name);
1950   sprintf (value, "%d", keysym);
1951   return value;
1956 /* ==========================================================================
1958     Block drawing operations
1960    ========================================================================== */
1963 static void
1964 ns_redraw_scroll_bars (struct frame *f)
1966   int i;
1967   id view;
1968   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1969   NSTRACE (ns_judge_scroll_bars);
1970   for (i =[subviews count]-1; i >= 0; i--)
1971     {
1972       view = [subviews objectAtIndex: i];
1973       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1974       [view display];
1975     }
1979 void
1980 ns_clear_frame (struct frame *f)
1981 /* --------------------------------------------------------------------------
1982       External (hook): Erase the entire frame
1983    -------------------------------------------------------------------------- */
1985   NSView *view = FRAME_NS_VIEW (f);
1986   NSRect r;
1988   NSTRACE (ns_clear_frame);
1989   if (ns_in_resize)
1990     return;
1992  /* comes on initial frame because we have
1993     after-make-frame-functions = select-frame */
1994  if (!FRAME_DEFAULT_FACE (f))
1995    return;
1997   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
1999   output_cursor.hpos = output_cursor.vpos = 0;
2000   output_cursor.x = -1;
2002   r = [view bounds];
2004   BLOCK_INPUT;
2005   ns_focus (f, &r, 1);
2006   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2007   NSRectFill (r);
2008   ns_unfocus (f);
2010 #ifdef NS_IMPL_COCOA
2011   [[view window] display];  /* redraw resize handle */
2012 #endif
2014   /* as of 2006/11 or so this is now needed */
2015   ns_redraw_scroll_bars (f);
2016   UNBLOCK_INPUT;
2020 void
2021 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2022 /* --------------------------------------------------------------------------
2023     External (RIF):  Clear section of frame
2024    -------------------------------------------------------------------------- */
2026   NSRect r = NSMakeRect (x, y, width, height);
2027   NSView *view = FRAME_NS_VIEW (f);
2028   struct face *face = FRAME_DEFAULT_FACE (f);
2030   if (!view || !face)
2031     return;
2033   NSTRACE (ns_clear_frame_area);
2035   r = NSIntersectionRect (r, [view frame]);
2036   ns_focus (f, &r, 1);
2037   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2039 #ifdef NS_IMPL_COCOA
2040   {
2041     /* clip out the resize handle */
2042     NSWindow *window = [FRAME_NS_VIEW (f) window];
2043     NSRect ir
2044       = [view convertRect: ns_resize_handle_rect (window) fromView: nil];
2046     ir = NSIntersectionRect (r, ir);
2047     if (NSIsEmptyRect (ir))
2048       {
2049 #endif
2051   NSRectFill (r);
2053 #ifdef NS_IMPL_COCOA
2054       }
2055     else
2056       {
2057         NSRect r1 = r, r2 = r; /* upper and lower non-intersecting */
2058         r1.size.height -= ir.size.height;
2059         r2.origin.y += r1.size.height;
2060         r2.size.width -= ir.size.width;
2061         r2.size.height = ir.size.height;
2062         NSRectFill (r1);
2063         NSRectFill (r2);
2064       }
2065   }
2066 #endif
2068   ns_unfocus (f);
2069   return;
2073 static void
2074 ns_scroll_run (struct window *w, struct run *run)
2075 /* --------------------------------------------------------------------------
2076     External (RIF):  Insert or delete n lines at line vpos
2077    -------------------------------------------------------------------------- */
2079   struct frame *f = XFRAME (w->frame);
2080   int x, y, width, height, from_y, to_y, bottom_y;
2082   NSTRACE (ns_scroll_run);
2084   /* begin copy from other terms */
2085   /* Get frame-relative bounding box of the text display area of W,
2086      without mode lines.  Include in this box the left and right
2087      fringe of W.  */
2088   window_box (w, -1, &x, &y, &width, &height);
2090   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2091   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2092   bottom_y = y + height;
2094   if (to_y < from_y)
2095     {
2096       /* Scrolling up.  Make sure we don't copy part of the mode
2097          line at the bottom.  */
2098       if (from_y + run->height > bottom_y)
2099         height = bottom_y - from_y;
2100       else
2101         height = run->height;
2102     }
2103   else
2104     {
2105       /* Scolling down.  Make sure we don't copy over the mode line.
2106          at the bottom.  */
2107       if (to_y + run->height > bottom_y)
2108         height = bottom_y - to_y;
2109       else
2110         height = run->height;
2111     }
2112   /* end copy from other terms */
2114   if (height == 0)
2115       return;
2117   BLOCK_INPUT;
2119   updated_window = w;
2120   x_clear_cursor (w);
2122   {
2123     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2124     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2125     NSPoint dstOrigin = NSMakePoint (x, to_y);
2127     ns_focus (f, &dstRect, 1);
2128     NSCopyBits (0, srcRect , dstOrigin);
2129     ns_unfocus (f);
2130   }
2132   UNBLOCK_INPUT;
2136 static void
2137 ns_after_update_window_line (struct glyph_row *desired_row)
2138 /* --------------------------------------------------------------------------
2139     External (RIF): preparatory to fringe update after text was updated
2140    -------------------------------------------------------------------------- */
2142   struct window *w = updated_window;
2143   struct frame *f;
2144   int width, height;
2146   NSTRACE (ns_after_update_window_line);
2148   /* begin copy from other terms */
2149   xassert (w);
2151   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2152     desired_row->redraw_fringe_bitmaps_p = 1;
2154   /* When a window has disappeared, make sure that no rest of
2155      full-width rows stays visible in the internal border.
2156      Under NS this is drawn inside the fringes. */
2157   if (windows_or_buffers_changed
2158       && (f = XFRAME (w->frame),
2159           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2160           width != 0)
2161       && (height = desired_row->visible_height,
2162           height > 0))
2163     {
2164       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2166       /* Internal border is drawn below the tool bar.  */
2167       if (WINDOWP (f->tool_bar_window)
2168           && w == XWINDOW (f->tool_bar_window))
2169         y -= width;
2170       /* end copy from other terms */
2172       BLOCK_INPUT;
2173       if (!desired_row->full_width_p)
2174         {
2175           int x1 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2176             + WINDOW_LEFT_FRINGE_WIDTH (w);
2177           int x2 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2178             + FRAME_PIXEL_WIDTH (f) - NS_SCROLL_BAR_WIDTH (f)
2179             - WINDOW_RIGHT_FRINGE_WIDTH (w)
2180             - FRAME_INTERNAL_BORDER_WIDTH (f);
2181           ns_clear_frame_area (f, x1, y, width, height);
2182           ns_clear_frame_area (f, x2, y, width, height);
2183         }
2184       UNBLOCK_INPUT;
2185     }
2189 static void
2190 ns_shift_glyphs_for_insert (struct frame *f,
2191                            int x, int y, int width, int height,
2192                            int shift_by)
2193 /* --------------------------------------------------------------------------
2194     External (RIF): copy an area horizontally, don't worry about clearing src
2195    -------------------------------------------------------------------------- */
2197   NSRect srcRect = NSMakeRect (x, y, width, height);
2198   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2199   NSPoint dstOrigin = dstRect.origin;
2201   NSTRACE (ns_shift_glyphs_for_insert);
2203   ns_focus (f, &dstRect, 1);
2204   NSCopyBits (0, srcRect, dstOrigin);
2205   ns_unfocus (f);
2210 /* ==========================================================================
2212     Character encoding and metrics
2214    ========================================================================== */
2217 static inline void
2218 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2219 /* --------------------------------------------------------------------------
2220      External (RIF); compute left/right overhang of whole string and set in s
2221    -------------------------------------------------------------------------- */
2223   struct face *face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2224   struct font *font = s->font; /*face->font; */
2226   if (s->char2b)
2227     {
2228       struct font_metrics metrics;
2229       unsigned int codes[2];
2230       codes[0] = *(s->char2b);
2231       codes[1] = *(s->char2b + s->nchars - 1);
2233       font->driver->text_extents (font, codes, 2, &metrics);
2234       s->left_overhang = -metrics.lbearing;
2235       s->right_overhang
2236         = metrics.rbearing > metrics.width
2237         ? metrics.rbearing - metrics.width : 0;
2238     }
2239   else
2240     {
2241       s->left_overhang = 0;
2242       s->right_overhang = ((struct nsfont_info *)font)->ital ?
2243         FONT_HEIGHT (font) * 0.2 : 0;
2244     }
2249 /* ==========================================================================
2251     Fringe and cursor drawing
2253    ========================================================================== */
2256 extern int max_used_fringe_bitmap;
2257 static void
2258 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2259                       struct draw_fringe_bitmap_params *p)
2260 /* --------------------------------------------------------------------------
2261     External (RIF); fringe-related
2262    -------------------------------------------------------------------------- */
2264   struct frame *f = XFRAME (WINDOW_FRAME (w));
2265   struct face *face = p->face;
2266   int rowY;
2267   static EmacsImage **bimgs = NULL;
2268   static int nBimgs = 0;
2269   /* NS-specific: move internal border inside fringe */
2270   int x = p->bx < 0 ? p->x : p->bx;
2271   int wd = p->bx < 0 ? p->wd : p->nx;
2272   BOOL fringeOnVeryLeft
2273     = x - WINDOW_LEFT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w)
2274       - FRAME_INTERNAL_BORDER_WIDTH (f) < 10;
2275   BOOL fringeOnVeryRight
2276     = FRAME_PIXEL_WIDTH (f) - x - wd - FRAME_INTERNAL_BORDER_WIDTH (f)
2277       - WINDOW_RIGHT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w) < 10;
2278   int xAdjust = FRAME_INTERNAL_BORDER_WIDTH (f) *
2279     (fringeOnVeryLeft ? -1 : (fringeOnVeryRight ? 1 : 0));
2281   /* grow bimgs if needed */
2282   if (nBimgs < max_used_fringe_bitmap)
2283     {
2284       EmacsImage **newBimgs
2285         = xmalloc (max_used_fringe_bitmap * sizeof (EmacsImage *));
2286       memset (newBimgs, 0, max_used_fringe_bitmap * sizeof (EmacsImage *));
2288       if (nBimgs)
2289         {
2290           memcpy (newBimgs, bimgs, nBimgs * sizeof (EmacsImage *));
2291           xfree (bimgs);
2292         }
2294       bimgs = newBimgs;
2295       nBimgs = max_used_fringe_bitmap;
2296     }
2298   /* Must clip because of partially visible lines.  */
2299   rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2300   ns_clip_to_row (w, row, -1, YES);
2302   if (p->bx >= 0 && !p->overlay_p)
2303     {
2304       int yAdjust = rowY - FRAME_INTERNAL_BORDER_WIDTH (f) < 5 ?
2305         -FRAME_INTERNAL_BORDER_WIDTH (f) : 0;
2306       int yIncr = FRAME_PIXEL_HEIGHT (f) - (p->by+yAdjust + p->ny) < 5 ?
2307         FRAME_INTERNAL_BORDER_WIDTH (f) : 0
2308         + (yAdjust ? FRAME_INTERNAL_BORDER_WIDTH (f) : 0);
2309       NSRect r = NSMakeRect (p->bx+xAdjust, p->by+yAdjust, p->nx, p->ny+yIncr);
2310       NSRectClip (r);
2311       [ns_lookup_indexed_color(face->background, f) set];
2312       NSRectFill (r);
2313     }
2315   if (p->which)
2316     {
2317       NSRect r = NSMakeRect (p->x+xAdjust, p->y, p->wd, p->h);
2318       NSPoint pt = r.origin;
2319       EmacsImage *img = bimgs[p->which - 1];
2321       if (!img)
2322         {
2323           unsigned short *bits = p->bits + p->dh;
2324           int len = 8 * p->h/8;
2325           int i;
2326           unsigned char *cbits = xmalloc (len);
2328           for (i =0; i<len; i++)
2329             cbits[i] = ~(bits[i] & 0xff);
2330           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2331                                            flip: NO];
2332           bimgs[p->which - 1] = img;
2333           xfree (cbits);
2334         }
2336       NSRectClip (r);
2337       /* Since we composite the bitmap instead of just blitting it, we need
2338          to erase the whole background. */
2339       [ns_lookup_indexed_color(face->background, f) set];
2340       NSRectFill (r);
2341       pt.y += p->h;
2342       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2343       [img compositeToPoint: pt operation: NSCompositeSourceOver];
2344     }
2345   ns_unfocus (f);
2349 void
2350 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2351                        int x, int y, int cursor_type, int cursor_width,
2352                        int on_p, int active_p)
2353 /* --------------------------------------------------------------------------
2354      External call (RIF): draw cursor.
2355      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2356    -------------------------------------------------------------------------- */
2358   NSRect r, s;
2359   int fx, fy, h, cursor_height;
2360   struct frame *f = WINDOW_XFRAME (w);
2361   struct glyph *phys_cursor_glyph;
2362   int overspill;
2363   struct glyph *cursor_glyph;
2364   struct face *face;
2365   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2367   /* If cursor is out of bounds, don't draw garbage.  This can happen
2368      in mini-buffer windows when switching between echo area glyphs
2369      and mini-buffer.  */
2371   NSTRACE (dumpcursor);
2373   if (!on_p)
2374     return;
2376   w->phys_cursor_type = cursor_type;
2377   w->phys_cursor_on_p = on_p;
2379   if (cursor_type == NO_CURSOR)
2380     {
2381       w->phys_cursor_width = 0;
2382       return;
2383     }
2385   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2386     {
2387       if (glyph_row->exact_window_width_line_p
2388           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2389         {
2390           glyph_row->cursor_in_fringe_p = 1;
2391           draw_fringe_bitmap (w, glyph_row, 0);
2392         }
2393       return;
2394     }
2396   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2397      (other terminals do it the other way round).  We must set
2398      w->phys_cursor_width to the cursor width.  For bar cursors, that
2399      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2400   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2402   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2403      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2404   if (cursor_type == BAR_CURSOR)
2405     {
2406       if (cursor_width < 1)
2407         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2408       w->phys_cursor_width = cursor_width;
2409     }
2410   /* If we have an HBAR, "cursor_width" MAY specify height. */
2411   else if (cursor_type == HBAR_CURSOR)
2412     {
2413       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2414       fy += h - cursor_height;
2415       h = cursor_height;
2416     }
2418   r.origin.x = fx, r.origin.y = fy;
2419   r.size.height = h;
2420   r.size.width = w->phys_cursor_width;
2422   /* FIXME: if we overwrite the internal border area, it does not get erased;
2423      fix by truncating cursor, but better would be to erase properly */
2424   overspill = r.origin.x + r.size.width -
2425     WINDOW_TEXT_TO_FRAME_PIXEL_X (w, WINDOW_BOX_RIGHT_EDGE_X (w)
2426       - WINDOW_TOTAL_FRINGE_WIDTH (w) - FRAME_INTERNAL_BORDER_WIDTH (f));
2427   if (overspill > 0)
2428     r.size.width -= overspill;
2430   /* TODO: only needed in rare cases with last-resort font in HELLO..
2431      should we do this more efficiently? */
2432   ns_clip_to_row (w, glyph_row, -1, NO); /* do ns_focus(f, &r, 1); if remove */
2435   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2436   if (face && NS_FACE_BACKGROUND (face)
2437       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2438     {
2439       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2440       hollow_color = FRAME_CURSOR_COLOR (f);
2441     }
2442   else
2443     [FRAME_CURSOR_COLOR (f) set];
2445 #ifdef NS_IMPL_COCOA
2446   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2447            atomic.  Cleaner ways of doing this should be investigated.
2448            One way would be to set a global variable DRAWING_CURSOR
2449            when making the call to draw_phys..(), don't focus in that
2450            case, then move the ns_unfocus() here after that call. */
2451   NSDisableScreenUpdates ();
2452 #endif
2454   switch (cursor_type)
2455     {
2456     case NO_CURSOR:
2457       break;
2458     case FILLED_BOX_CURSOR:
2459       NSRectFill (r);
2460       break;
2461     case HOLLOW_BOX_CURSOR:
2462       NSRectFill (r);
2463       [hollow_color set];
2464       NSRectFill (NSInsetRect (r, 1, 1));
2465       [FRAME_CURSOR_COLOR (f) set];
2466       break;
2467     case HBAR_CURSOR:
2468       NSRectFill (r);
2469       break;
2470     case BAR_CURSOR:
2471       s = r;
2472       /* If the character under cursor is R2L, draw the bar cursor
2473          on the right of its glyph, rather than on the left.  */
2474       cursor_glyph = get_phys_cursor_glyph (w);
2475       if ((cursor_glyph->resolved_level & 1) != 0)
2476         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2478       NSRectFill (s);
2479       break;
2480     }
2481   ns_unfocus (f);
2483   /* draw the character under the cursor */
2484   if (cursor_type != NO_CURSOR)
2485     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2487 #ifdef NS_IMPL_COCOA
2488   NSEnableScreenUpdates ();
2489 #endif
2494 static void
2495 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2496 /* --------------------------------------------------------------------------
2497      External (RIF): Draw a vertical line.
2498    -------------------------------------------------------------------------- */
2500   struct frame *f = XFRAME (WINDOW_FRAME (w));
2501   struct face *face;
2502   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2504   NSTRACE (ns_draw_vertical_window_border);
2506   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2507   if (face)
2508       [ns_lookup_indexed_color(face->foreground, f) set];
2510   ns_focus (f, &r, 1);
2511   NSRectFill(r);
2512   ns_unfocus (f);
2516 void
2517 show_hourglass (struct atimer *timer)
2519   if (hourglass_shown_p)
2520     return;
2522   BLOCK_INPUT;
2524   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2526   hourglass_shown_p = 1;
2527   UNBLOCK_INPUT;
2531 void
2532 hide_hourglass (void)
2534   if (!hourglass_shown_p)
2535     return;
2537   BLOCK_INPUT;
2539   /* TODO: remove NSProgressIndicator from all frames */
2541   hourglass_shown_p = 0;
2542   UNBLOCK_INPUT;
2547 /* ==========================================================================
2549     Glyph drawing operations
2551    ========================================================================== */
2554 static inline NSRect
2555 ns_fix_rect_ibw (NSRect r, int fibw, int frame_pixel_width)
2556 /* --------------------------------------------------------------------------
2557     Under NS we draw internal borders inside fringes, and want full-width
2558     rendering to go all the way to edge.  This function makes that correction.
2559    -------------------------------------------------------------------------- */
2561   if (r.origin.y <= fibw+1)
2562     {
2563       r.size.height += r.origin.y;
2564       r.origin.y = 0;
2565     }
2566   if (r.origin.x <= fibw+1)
2567     {
2568       r.size.width += r.origin.x;
2569       r.origin.x = 0;
2570     }
2571   if (frame_pixel_width - (r.origin.x+r.size.width) <= fibw+1)
2572     r.size.width += fibw;
2574   return r;
2578 static int
2579 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2580 /* --------------------------------------------------------------------------
2581     Wrapper utility to account for internal border width on full-width lines,
2582     and allow top full-width rows to hit the frame top.  nr should be pointer
2583     to two successive NSRects.  Number of rects actually used is returned.
2584    -------------------------------------------------------------------------- */
2586   int n = get_glyph_string_clip_rects (s, nr, 2);
2587   if (s->row->full_width_p)
2588     {
2589       *nr = ns_fix_rect_ibw (*nr, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2590                             FRAME_PIXEL_WIDTH (s->f));
2591       if (n == 2)
2592         *nr = ns_fix_rect_ibw (*(nr+1), FRAME_INTERNAL_BORDER_WIDTH (s->f),
2593                               FRAME_PIXEL_WIDTH (s->f));
2594     }
2595   return n;
2598 void
2599 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2600                          NSColor *defaultCol, CGFloat width, CGFloat x)
2601 /* --------------------------------------------------------------------------
2602    Draw underline, overline, and strike-through on glyph string s.
2603    -------------------------------------------------------------------------- */
2605   if (s->for_overlaps)
2606     return;
2608   /* Do underline. */
2609   if (face->underline_p)
2610     {
2611       NSRect r;
2612       unsigned long thickness, position;
2614       /* If the prev was underlined, match its appearance. */
2615       if (s->prev && s->prev->face->underline_p
2616           && s->prev->underline_thickness > 0)
2617         {
2618           thickness = s->prev->underline_thickness;
2619           position = s->prev->underline_position;
2620         }
2621       else
2622         {
2623           struct font *font;
2624           unsigned long descent;
2626           font=s->font;
2627           descent = s->y + s->height - s->ybase;
2629           /* Use underline thickness of font, defaulting to 1. */
2630           thickness = (font && font->underline_thickness > 0)
2631             ? font->underline_thickness : 1;
2633           /* Determine the offset of underlining from the baseline. */
2634           if (x_underline_at_descent_line)
2635             position = descent - thickness;
2636           else if (x_use_underline_position_properties
2637                    && font && font->underline_position >= 0)
2638             position = font->underline_position;
2639           else if (font)
2640             position = lround (font->descent / 2);
2641           else
2642             position = underline_minimum_offset;
2644           position = max (position, underline_minimum_offset);
2646           /* Ensure underlining is not cropped. */
2647           if (descent <= position)
2648             {
2649               position = descent - 1;
2650               thickness = 1;
2651             }
2652           else if (descent < position + thickness)
2653             thickness = 1;
2654         }
2656       s->underline_thickness = thickness;
2657       s->underline_position = position;
2659       r = NSMakeRect (x, s->ybase + position, width, thickness);
2661       if (face->underline_defaulted_p)
2662         [defaultCol set];
2663       else
2664         [ns_lookup_indexed_color (face->underline_color, s->f) set];
2665       NSRectFill (r);
2666     }
2668   /* Do overline. We follow other terms in using a thickness of 1
2669      and ignoring overline_margin. */
2670   if (face->overline_p)
2671     {
2672       NSRect r;
2673       r = NSMakeRect (x, s->y, width, 1);
2675       if (face->overline_color_defaulted_p)
2676         [defaultCol set];
2677       else
2678         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2679       NSRectFill (r);
2680     }
2682   /* Do strike-through.  We follow other terms for thickness and
2683      vertical position.*/
2684   if (face->strike_through_p)
2685     {
2686       NSRect r;
2687       unsigned long dy;
2689       dy = lrint ((s->height - 1) / 2);
2690       r = NSMakeRect (x, s->y + dy, width, 1);
2692       if (face->strike_through_color_defaulted_p)
2693         [defaultCol set];
2694       else
2695         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2696       NSRectFill (r);
2697     }
2700 static void
2701 ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char right_p)
2702 /* --------------------------------------------------------------------------
2703     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2704     Note we can't just use an NSDrawRect command, because of the possibility
2705     of some sides not being drawn, and because the rect will be filled.
2706    -------------------------------------------------------------------------- */
2708   NSRect s = r;
2709   [col set];
2711   /* top, bottom */
2712   s.size.height = thickness;
2713   NSRectFill (s);
2714   s.origin.y += r.size.height - thickness;
2715   NSRectFill (s);
2717   s.size.height = r.size.height;
2718   s.origin.y = r.origin.y;
2720   /* left, right (optional) */
2721   s.size.width = thickness;
2722   if (left_p)
2723     NSRectFill (s);
2724   if (right_p)
2725     {
2726       s.origin.x += r.size.width - thickness;
2727       NSRectFill (s);
2728     }
2732 static void
2733 ns_draw_relief (NSRect r, int thickness, char raised_p,
2734                char top_p, char bottom_p, char left_p, char right_p,
2735                struct glyph_string *s)
2736 /* --------------------------------------------------------------------------
2737     Draw a relief rect inside r, optionally leaving some sides open.
2738     Note we can't just use an NSDrawBezel command, because of the possibility
2739     of some sides not being drawn, and because the rect will be filled.
2740    -------------------------------------------------------------------------- */
2742   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2743   NSColor *newBaseCol = nil;
2744   NSRect sr = r;
2746   NSTRACE (ns_draw_relief);
2748   /* set up colors */
2750   if (s->face->use_box_color_for_shadows_p)
2751     {
2752       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2753     }
2754 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2755            && s->img->pixmap
2756            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2757        {
2758          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2759        } */
2760   else
2761     {
2762       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2763     }
2765   if (newBaseCol == nil)
2766     newBaseCol = [NSColor grayColor];
2768   if (newBaseCol != baseCol)  /* TODO: better check */
2769     {
2770       [baseCol release];
2771       baseCol = [newBaseCol retain];
2772       [lightCol release];
2773       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2774       [darkCol release];
2775       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2776     }
2778   [(raised_p ? lightCol : darkCol) set];
2780   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2782   /* top */
2783   sr.size.height = thickness;
2784   if (top_p) NSRectFill (sr);
2786   /* left */
2787   sr.size.height = r.size.height;
2788   sr.size.width = thickness;
2789   if (left_p) NSRectFill (sr);
2791   [(raised_p ? darkCol : lightCol) set];
2793   /* bottom */
2794   sr.size.width = r.size.width;
2795   sr.size.height = thickness;
2796   sr.origin.y += r.size.height - thickness;
2797   if (bottom_p) NSRectFill (sr);
2799   /* right */
2800   sr.size.height = r.size.height;
2801   sr.origin.y = r.origin.y;
2802   sr.size.width = thickness;
2803   sr.origin.x += r.size.width - thickness;
2804   if (right_p) NSRectFill (sr);
2808 static void
2809 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2810 /* --------------------------------------------------------------------------
2811       Function modeled after x_draw_glyph_string_box ().
2812       Sets up parameters for drawing.
2813    -------------------------------------------------------------------------- */
2815   int right_x, last_x;
2816   char left_p, right_p;
2817   struct glyph *last_glyph;
2818   NSRect r;
2819   int thickness;
2820   struct face *face;
2822   if (s->hl == DRAW_MOUSE_FACE)
2823     {
2824       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2825       if (!face)
2826         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2827     }
2828   else
2829     face = s->face;
2831   thickness = face->box_line_width;
2833   NSTRACE (ns_dumpglyphs_box_or_relief);
2835   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2836             ? WINDOW_RIGHT_EDGE_X (s->w)
2837             : window_box_right (s->w, s->area));
2838   last_glyph = (s->cmp || s->img
2839                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2841   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2842               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2844   left_p = (s->first_glyph->left_box_line_p
2845             || (s->hl == DRAW_MOUSE_FACE
2846                 && (s->prev == NULL || s->prev->hl != s->hl)));
2847   right_p = (last_glyph->right_box_line_p
2848              || (s->hl == DRAW_MOUSE_FACE
2849                  && (s->next == NULL || s->next->hl != s->hl)));
2851   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2853   /* expand full-width row over internal borders */
2854   if (s->row->full_width_p)
2855     r = ns_fix_rect_ibw (r, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2856                         FRAME_PIXEL_WIDTH (s->f));
2858   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2859   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2860     {
2861       ns_draw_box (r, abs (thickness),
2862                    ns_lookup_indexed_color (face->box_color, s->f),
2863                   left_p, right_p);
2864     }
2865   else
2866     {
2867       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2868                      1, 1, left_p, right_p, s);
2869     }
2873 static void
2874 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2875 /* --------------------------------------------------------------------------
2876       Modeled after x_draw_glyph_string_background, which draws BG in
2877       certain cases.  Others are left to the text rendering routine.
2878    -------------------------------------------------------------------------- */
2880   NSTRACE (ns_maybe_dumpglyphs_background);
2882   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2883     {
2884       int box_line_width = max (s->face->box_line_width, 0);
2885       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2886           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2887         {
2888           struct face *face;
2889           if (s->hl == DRAW_MOUSE_FACE)
2890             {
2891               face = FACE_FROM_ID (s->f,
2892                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2893               if (!face)
2894                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2895             }
2896           else
2897             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2898           if (!face->stipple)
2899             [(NS_FACE_BACKGROUND (face) != 0
2900               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2901               : FRAME_BACKGROUND_COLOR (s->f)) set];
2902           else
2903             {
2904               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2905               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2906             }
2908           if (s->hl != DRAW_CURSOR)
2909             {
2910               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2911                                     s->background_width,
2912                                     s->height-2*box_line_width);
2914               /* expand full-width row over internal borders */
2915               if (s->row->full_width_p)
2916                 {
2917                   int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2918                   if (r.origin.y <= fibw+1 + box_line_width)
2919                     {
2920                       r.size.height += r.origin.y;
2921                       r.origin.y = 0;
2922                     }
2923                   if (r.origin.x <= fibw+1)
2924                     {
2925                       r.size.width += 2*r.origin.x;
2926                       r.origin.x = 0;
2927                     }
2928                   if (FRAME_PIXEL_WIDTH (s->f) - (r.origin.x + r.size.width)
2929                       <= fibw+1)
2930                     r.size.width += fibw;
2931                 }
2933               NSRectFill (r);
2934             }
2936           s->background_filled_p = 1;
2937         }
2938     }
2942 static void
2943 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2944 /* --------------------------------------------------------------------------
2945       Renders an image and associated borders.
2946    -------------------------------------------------------------------------- */
2948   EmacsImage *img = s->img->pixmap;
2949   int box_line_vwidth = max (s->face->box_line_width, 0);
2950   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2951   int bg_x, bg_y, bg_height;
2952   int th;
2953   char raised_p;
2954   NSRect br;
2955   struct face *face;
2956   NSColor *tdCol;
2958   NSTRACE (ns_dumpglyphs_image);
2960   if (s->face->box != FACE_NO_BOX
2961       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2962     x += abs (s->face->box_line_width);
2964   bg_x = x;
2965   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2966   bg_height = s->height;
2967   /* other terms have this, but was causing problems w/tabbar mode */
2968   /* - 2 * box_line_vwidth; */
2970   if (s->slice.x == 0) x += s->img->hmargin;
2971   if (s->slice.y == 0) y += s->img->vmargin;
2973   /* Draw BG: if we need larger area than image itself cleared, do that,
2974      otherwise, since we composite the image under NS (instead of mucking
2975      with its background color), we must clear just the image area. */
2976   if (s->hl == DRAW_MOUSE_FACE)
2977     {
2978       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2979       if (!face)
2980        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2981     }
2982   else
2983     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2985   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2987   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2988       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2989     {
2990       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
2991       s->background_filled_p = 1;
2992     }
2993   else
2994     {
2995       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
2996     }
2998   /* expand full-width row over internal borders */
2999   if (s->row->full_width_p)
3000     {
3001       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
3002       if (br.origin.y <= fibw+1 + box_line_vwidth)
3003         {
3004           br.size.height += br.origin.y;
3005           br.origin.y = 0;
3006         }
3007       if (br.origin.x <= fibw+1 + box_line_vwidth)
3008         {
3009           br.size.width += br.origin.x;
3010           br.origin.x = 0;
3011         }
3012       if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) <= fibw+1)
3013         br.size.width += fibw;
3014     }
3016   NSRectFill (br);
3018   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3019   if (img != nil)
3020     [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3021                 operation: NSCompositeSourceOver];
3023   if (s->hl == DRAW_CURSOR)
3024     {
3025     [FRAME_CURSOR_COLOR (s->f) set];
3026     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3027       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3028     else
3029       /* Currently on NS img->mask is always 0. Since
3030          get_window_cursor_type specifies a hollow box cursor when on
3031          a non-masked image we never reach this clause. But we put it
3032          in in antipication of better support for image masks on
3033          NS. */
3034       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3035     }
3036   else
3037     {
3038       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3039     }
3041   /* Draw underline, overline, strike-through. */
3042   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3044   /* Draw relief, if requested */
3045   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3046     {
3047       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3048         {
3049           th = tool_bar_button_relief >= 0 ?
3050             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3051           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3052         }
3053       else
3054         {
3055           th = abs (s->img->relief);
3056           raised_p = (s->img->relief > 0);
3057         }
3059       r.origin.x = x - th;
3060       r.origin.y = y - th;
3061       r.size.width = s->slice.width + 2*th-1;
3062       r.size.height = s->slice.height + 2*th-1;
3063       ns_draw_relief (r, th, raised_p,
3064                       s->slice.y == 0,
3065                       s->slice.y + s->slice.height == s->img->height,
3066                       s->slice.x == 0,
3067                       s->slice.x + s->slice.width == s->img->width, s);
3068     }
3070   /* If there is no mask, the background won't be seen,
3071      so draw a rectangle on the image for the cursor.
3072      Do this for all images, getting trancparency right is not reliable.  */
3073   if (s->hl == DRAW_CURSOR)
3074     {
3075       int thickness = abs (s->img->relief);
3076       if (thickness == 0) thickness = 1;
3077       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3078     }
3082 static void
3083 ns_dumpglyphs_stretch (struct glyph_string *s)
3085   NSRect r[2];
3086   int n, i;
3087   struct face *face;
3088   NSColor *fgCol, *bgCol;
3090   if (!s->background_filled_p)
3091     {
3092       n = ns_get_glyph_string_clip_rect (s, r);
3093       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3095       ns_focus (s->f, r, n);
3097       if (s->hl == DRAW_MOUSE_FACE)
3098        {
3099          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3100          if (!face)
3101            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3102        }
3103       else
3104        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3106       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3107       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3109       for (i=0; i<n; i++)
3110         {
3111           if (!s->row->full_width_p)
3112             {
3113               int overrun, leftoverrun;
3115               /* truncate to avoid overwriting fringe and/or scrollbar */
3116               overrun = max (0, (s->x + s->background_width)
3117                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3118                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3119               r[i].size.width -= overrun;
3121               /* truncate to avoid overwriting to left of the window box */
3122               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3123                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3125               if (leftoverrun > 0)
3126                 {
3127                   r[i].origin.x += leftoverrun;
3128                   r[i].size.width -= leftoverrun;
3129                 }
3131               /* XXX: Try to work between problem where a stretch glyph on
3132                  a partially-visible bottom row will clear part of the
3133                  modeline, and another where list-buffers headers and similar
3134                  rows erroneously have visible_height set to 0.  Not sure
3135                  where this is coming from as other terms seem not to show. */
3136               r[i].size.height = min (s->height, s->row->visible_height);
3137             }
3139           /* expand full-width rows over internal borders */
3140           else
3141             {
3142               r[i] = ns_fix_rect_ibw (r[i], FRAME_INTERNAL_BORDER_WIDTH (s->f),
3143                                       FRAME_PIXEL_WIDTH (s->f));
3144             }
3146           [bgCol set];
3148           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3149              overwriting cursor (usually when cursor on a tab) */
3150           if (s->hl == DRAW_CURSOR)
3151             {
3152               CGFloat x, width;
3154               x = r[i].origin.x;
3155               width = s->w->phys_cursor_width;
3156               r[i].size.width -= width;
3157               r[i].origin.x += width;
3159               NSRectFill (r[i]);
3161               /* Draw overlining, etc. on the cursor. */
3162               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3163                 ns_draw_text_decoration (s, face, bgCol, width, x);
3164               else
3165                 ns_draw_text_decoration (s, face, fgCol, width, x);
3166             }
3167           else
3168             {
3169               NSRectFill (r[i]);
3170             }
3172           /* Draw overlining, etc. on the stretch glyph (or the part
3173              of the stretch glyph after the cursor). */
3174           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3175                                    r[i].origin.x);
3176         }
3177       ns_unfocus (s->f);
3178       s->background_filled_p = 1;
3179     }
3183 static void
3184 ns_draw_glyph_string (struct glyph_string *s)
3185 /* --------------------------------------------------------------------------
3186       External (RIF): Main draw-text call.
3187    -------------------------------------------------------------------------- */
3189   /* TODO (optimize): focus for box and contents draw */
3190   NSRect r[2];
3191   int n;
3192   char box_drawn_p = 0;
3194   NSTRACE (ns_draw_glyph_string);
3196   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3197     {
3198       int width;
3199       struct glyph_string *next;
3201       for (width = 0, next = s->next;
3202            next && width < s->right_overhang;
3203            width += next->width, next = next->next)
3204         if (next->first_glyph->type != IMAGE_GLYPH)
3205           {
3206             if (next->first_glyph->type != STRETCH_GLYPH)
3207               {
3208                 n = ns_get_glyph_string_clip_rect (s->next, r);
3209                 ns_focus (s->f, r, n);
3210                 ns_maybe_dumpglyphs_background (s->next, 1);
3211                 ns_unfocus (s->f);
3212               }
3213             else
3214               {
3215                 ns_dumpglyphs_stretch (s->next);
3216               }
3217             next->num_clips = 0;
3218           }
3219     }
3221   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3222         && (s->first_glyph->type == CHAR_GLYPH
3223             || s->first_glyph->type == COMPOSITE_GLYPH))
3224     {
3225       n = ns_get_glyph_string_clip_rect (s, r);
3226       ns_focus (s->f, r, n);
3227       ns_maybe_dumpglyphs_background (s, 1);
3228       ns_dumpglyphs_box_or_relief (s);
3229       ns_unfocus (s->f);
3230       box_drawn_p = 1;
3231     }
3233   switch (s->first_glyph->type)
3234     {
3236     case IMAGE_GLYPH:
3237       n = ns_get_glyph_string_clip_rect (s, r);
3238       ns_focus (s->f, r, n);
3239       ns_dumpglyphs_image (s, r[0]);
3240       ns_unfocus (s->f);
3241       break;
3243     case STRETCH_GLYPH:
3244       ns_dumpglyphs_stretch (s);
3245       break;
3247     case CHAR_GLYPH:
3248     case COMPOSITE_GLYPH:
3249       n = ns_get_glyph_string_clip_rect (s, r);
3250       ns_focus (s->f, r, n);
3252       if (s->for_overlaps || (s->cmp_from > 0
3253                               && ! s->first_glyph->u.cmp.automatic))
3254         s->background_filled_p = 1;
3255       else
3256         ns_maybe_dumpglyphs_background
3257           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3259       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3260                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3261                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3262                       NS_DUMPGLYPH_NORMAL));
3263       ns_tmp_font = (struct nsfont_info *)s->face->font;
3264       if (ns_tmp_font == NULL)
3265           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
3267       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3268         {
3269           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3270           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3271           NS_FACE_FOREGROUND (s->face) = tmp;
3272         }
3274       ns_tmp_font->font.driver->draw
3275         (s, 0, s->nchars, s->x, s->y,
3276          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3277          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
3279       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3280         {
3281           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3282           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3283           NS_FACE_FOREGROUND (s->face) = tmp;
3284         }
3286       ns_unfocus (s->f);
3287       break;
3289     case GLYPHLESS_GLYPH:
3290       n = ns_get_glyph_string_clip_rect (s, r);
3291       ns_focus (s->f, r, n);
3293       if (s->for_overlaps || (s->cmp_from > 0
3294                               && ! s->first_glyph->u.cmp.automatic))
3295         s->background_filled_p = 1;
3296       else
3297         ns_maybe_dumpglyphs_background
3298           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3299       /* ... */
3300       /* Not yet implemented.  */
3301       /* ... */
3302       ns_unfocus (s->f);
3303       break;
3305     default:
3306       abort ();
3307     }
3309   /* Draw box if not done already. */
3310   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3311     {
3312       n = ns_get_glyph_string_clip_rect (s, r);
3313       ns_focus (s->f, r, n);
3314       ns_dumpglyphs_box_or_relief (s);
3315       ns_unfocus (s->f);
3316     }
3318   s->num_clips = 0;
3323 /* ==========================================================================
3325     Event loop
3327    ========================================================================== */
3330 static void
3331 ns_send_appdefined (int value)
3332 /* --------------------------------------------------------------------------
3333     Internal: post an appdefined event which EmacsApp-sendEvent will
3334               recognize and take as a command to halt the event loop.
3335    -------------------------------------------------------------------------- */
3337   /*NSTRACE (ns_send_appdefined); */
3339   /* Only post this event if we haven't already posted one.  This will end
3340        the [NXApp run] main loop after having processed all events queued at
3341        this moment.  */
3342   if (send_appdefined)
3343     {
3344       NSEvent *nxev;
3346       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3347       send_appdefined = NO;
3349       /* Don't need wakeup timer any more */
3350       if (timed_entry)
3351         {
3352           [timed_entry invalidate];
3353           [timed_entry release];
3354           timed_entry = nil;
3355         }
3357       /* Ditto for file descriptor poller */
3358       if (fd_entry)
3359         {
3360           [fd_entry invalidate];
3361           [fd_entry release];
3362           fd_entry = nil;
3363         }
3365       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3366                                 location: NSMakePoint (0, 0)
3367                            modifierFlags: 0
3368                                timestamp: 0
3369                             windowNumber: [[NSApp mainWindow] windowNumber]
3370                                  context: [NSApp context]
3371                                  subtype: 0
3372                                    data1: value
3373                                    data2: 0];
3375       /* Post an application defined event on the event queue.  When this is
3376          received the [NXApp run] will return, thus having processed all
3377          events which are currently queued.  */
3378       [NSApp postEvent: nxev atStart: NO];
3379     }
3383 static int
3384 ns_read_socket (struct terminal *terminal, int expected,
3385                 struct input_event *hold_quit)
3386 /* --------------------------------------------------------------------------
3387      External (hook): Post an event to ourself and keep reading events until
3388      we read it back again.  In effect process all events which were waiting.
3389      From 21+ we have to manage the event buffer ourselves.
3390    -------------------------------------------------------------------------- */
3392   struct input_event ev;
3393   int nevents;
3395 /* NSTRACE (ns_read_socket); */
3397   if (interrupt_input_blocked)
3398     {
3399       interrupt_input_pending = 1;
3400 #ifdef SYNC_INPUT
3401       pending_signals = 1;
3402 #endif
3403       return -1;
3404     }
3406   interrupt_input_pending = 0;
3407 #ifdef SYNC_INPUT
3408   pending_signals = pending_atimers;
3409 #endif
3411   BLOCK_INPUT;
3412   n_emacs_events_pending = 0;
3413   EVENT_INIT (ev);
3414   emacs_event = &ev;
3415   q_event_ptr = hold_quit;
3417   /* we manage autorelease pools by allocate/reallocate each time around
3418      the loop; strict nesting is occasionally violated but seems not to
3419      matter.. earlier methods using full nesting caused major memory leaks */
3420   [outerpool release];
3421   outerpool = [[NSAutoreleasePool alloc] init];
3423   /* If have pending open-file requests, attend to the next one of those. */
3424   if (ns_pending_files && [ns_pending_files count] != 0
3425       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3426     {
3427       [ns_pending_files removeObjectAtIndex: 0];
3428     }
3429   /* Deal with pending service requests. */
3430   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3431     && [(EmacsApp *)
3432          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3433                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3434     {
3435       [ns_pending_service_names removeObjectAtIndex: 0];
3436       [ns_pending_service_args removeObjectAtIndex: 0];
3437     }
3438   else
3439     {
3440       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3441          to ourself, otherwise [NXApp run] will never exit.  */
3442       send_appdefined = YES;
3444       /* If called via ns_select, this is called once with expected=1,
3445          because we expect either the timeout or file descriptor activity.
3446          In this case the first event through will either be real input or
3447          one of these.  read_avail_input() then calls once more with expected=0
3448          and in that case we need to return quickly if there is nothing.
3449          If we're being called outside of that, it's also OK to return quickly
3450          after one iteration through the event loop, since other terms do
3451          this and emacs expects it. */
3452       if (!(inNsSelect && expected))
3453         {
3454           /* Post an application defined event on the event queue.  When this is
3455              received the [NXApp run] will return, thus having processed all
3456              events which are currently queued, if any.  */
3457           ns_send_appdefined (-1);
3458         }
3460       [NSApp run];
3461     }
3463   nevents = n_emacs_events_pending;
3464   n_emacs_events_pending = 0;
3465   emacs_event = q_event_ptr = NULL;
3466   UNBLOCK_INPUT;
3468   return nevents;
3473 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3474            fd_set *exceptfds, struct timeval *timeout)
3475 /* --------------------------------------------------------------------------
3476      Replacement for select, checking for events
3477    -------------------------------------------------------------------------- */
3479   int result;
3480   double time;
3481   NSEvent *ev;
3482 /*  NSTRACE (ns_select); */
3484   if (NSApp == nil || inNsSelect == 1 /* || ([NSApp isActive] == NO &&
3485                       [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil
3486  inMode:NSDefaultRunLoopMode dequeue:NO] == nil) */)
3487     return select (nfds, readfds, writefds, exceptfds, timeout);
3489   /* Save file descriptor set, which gets overwritten in calls to select ()
3490      Note, this is called from process.c, and only readfds is ever set */
3491   if (readfds)
3492     {
3493       memcpy (&select_readfds, readfds, sizeof (fd_set));
3494       select_nfds = nfds;
3495     }
3496   else
3497     select_nfds = 0;
3499     /* Try an initial select for pending data on input files */
3500   select_timeout.tv_sec = select_timeout.tv_usec = 0;
3501   result = select (nfds, readfds, writefds, exceptfds, &select_timeout);
3502   if (result)
3503     return result;
3505   /* if (!timeout || timed_entry || fd_entry)
3506        fprintf (stderr, "assertion failed: timeout null or timed_entry/fd_entry non-null in ns_select\n"); */
3508     /* set a timeout and run the main AppKit event loop while continuing
3509        to monitor the files */
3510   time = ((double) timeout->tv_sec) + ((double) timeout->tv_usec)/1000000.0;
3511   timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3512                                            target: NSApp
3513                                          selector: @selector (timeout_handler:)
3514                                          userInfo: 0
3515                                           repeats: YES] /* for safe removal */
3516                                                          retain];
3518   /* set a periodic task to try the select () again */
3519   fd_entry = [[NSTimer scheduledTimerWithTimeInterval: 0.1
3520                                                target: NSApp
3521                                              selector: @selector (fd_handler:)
3522                                              userInfo: 0
3523                                               repeats: YES]
3524                retain];
3526   /* Let Application dispatch events until it receives an event of the type
3527      NX_APPDEFINED, which should only be sent by timeout_handler.
3528      We tell read_avail_input() that input is "expected" because we do expect
3529      either the timeout or fd handler to fire, and if they don't, the original
3530      call from process.c that got us here expects us to wait until some input
3531      comes. */
3532   inNsSelect = 1;
3533   gobble_input (1);
3534   ev = last_appdefined_event;
3535   inNsSelect = 0;
3537   if (ev)
3538     {
3539       int t;
3540       if ([ev type] != NSApplicationDefined)
3541         abort ();
3543       t = [ev data1];
3544       last_appdefined_event = 0;
3546       if (t == -2)
3547         {
3548           /* The NX_APPDEFINED event we received was a timeout. */
3549           return 0;
3550         }
3551       else if (t == -1)
3552         {
3553           /* The NX_APPDEFINED event we received was the result of
3554              at least one real input event arriving.  */
3555           errno = EINTR;
3556           return -1;
3557         }
3558       else
3559         {
3560           /* Received back from select () in fd_handler; copy the results */
3561           if (readfds)
3562             memcpy (readfds, &select_readfds, sizeof (fd_set));
3563           return t;
3564         }
3565     }
3566   /* never reached, shut compiler up */
3567   return 0;
3572 /* ==========================================================================
3574     Scrollbar handling
3576    ========================================================================== */
3579 static void
3580 ns_set_vertical_scroll_bar (struct window *window,
3581                            int portion, int whole, int position)
3582 /* --------------------------------------------------------------------------
3583       External (hook): Update or add scrollbar
3584    -------------------------------------------------------------------------- */
3586   Lisp_Object win;
3587   NSRect r, v;
3588   struct frame *f = XFRAME (WINDOW_FRAME (window));
3589   EmacsView *view = FRAME_NS_VIEW (f);
3590   int window_y, window_height;
3591   BOOL barOnVeryLeft, barOnVeryRight;
3592   int top, left, height, width, sb_width, sb_left;
3593   EmacsScroller *bar;
3594 static int count = 0;
3596   /* optimization; display engine sends WAY too many of these.. */
3597   if (!NILP (window->vertical_scroll_bar))
3598     {
3599       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3600       if ([bar checkSamePosition: position portion: portion whole: whole])
3601         {
3602           if (view->scrollbarsNeedingUpdate == 0)
3603             {
3604               if (!windows_or_buffers_changed)
3605                   return;
3606             }
3607           else
3608             view->scrollbarsNeedingUpdate--;
3609         }
3610     }
3612   NSTRACE (ns_set_vertical_scroll_bar);
3614   /* Get dimensions.  */
3615   window_box (window, -1, 0, &window_y, 0, &window_height);
3616   top = window_y;
3617   height = window_height;
3618   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3619   left = WINDOW_SCROLL_BAR_AREA_X (window);
3621   if (top < 5) /* top scrollbar adjustment */
3622     {
3623       top -= FRAME_INTERNAL_BORDER_WIDTH (f);
3624       height += FRAME_INTERNAL_BORDER_WIDTH (f);
3625     }
3627   /* allow for displaying a skinnier scrollbar than char area allotted */
3628   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3629     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3631   barOnVeryLeft = left < 5;
3632   barOnVeryRight = FRAME_PIXEL_WIDTH (f) - left - width < 5;
3633   sb_left = left + FRAME_INTERNAL_BORDER_WIDTH (f)
3634       * (barOnVeryLeft ? -1 : (barOnVeryRight ? 1 : 0));
3636   r = NSMakeRect (sb_left, top, sb_width, height);
3637   /* the parent view is flipped, so we need to flip y value */
3638   v = [view frame];
3639   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3641   XSETWINDOW (win, window);
3642   BLOCK_INPUT;
3644   /* we want at least 5 lines to display a scrollbar */
3645   if (WINDOW_TOTAL_LINES (window) < 5)
3646     {
3647       if (!NILP (window->vertical_scroll_bar))
3648         {
3649           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3650           [bar removeFromSuperview];
3651           window->vertical_scroll_bar = Qnil;
3652         }
3653       ns_clear_frame_area (f, sb_left, top, width, height);
3654       UNBLOCK_INPUT;
3655       return;
3656     }
3658   if (NILP (window->vertical_scroll_bar))
3659     {
3660       ns_clear_frame_area (f, sb_left, top, width, height);
3661       bar = [[EmacsScroller alloc] initFrame: r window: win];
3662       window->vertical_scroll_bar = make_save_value (bar, 0);
3663     }
3664   else
3665     {
3666       NSRect oldRect;
3667       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3668       oldRect = [bar frame];
3669       r.size.width = oldRect.size.width;
3670       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3671         {
3672           if (oldRect.origin.x != r.origin.x)
3673               ns_clear_frame_area (f, sb_left, top, width, height);
3674           [bar setFrame: r];
3675         }
3676     }
3678   [bar setPosition: position portion: portion whole: whole];
3679   UNBLOCK_INPUT;
3683 static void
3684 ns_condemn_scroll_bars (struct frame *f)
3685 /* --------------------------------------------------------------------------
3686      External (hook): arrange for all frame's scrollbars to be removed
3687      at next call to judge_scroll_bars, except for those redeemed.
3688    -------------------------------------------------------------------------- */
3690   int i;
3691   id view;
3692   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3694   NSTRACE (ns_condemn_scroll_bars);
3696   for (i =[subviews count]-1; i >= 0; i--)
3697     {
3698       view = [subviews objectAtIndex: i];
3699       if ([view isKindOfClass: [EmacsScroller class]])
3700         [view condemn];
3701     }
3705 static void
3706 ns_redeem_scroll_bar (struct window *window)
3707 /* --------------------------------------------------------------------------
3708      External (hook): arrange to spare this window's scrollbar
3709      at next call to judge_scroll_bars.
3710    -------------------------------------------------------------------------- */
3712   id bar;
3713   NSTRACE (ns_redeem_scroll_bar);
3714   if (!NILP (window->vertical_scroll_bar))
3715     {
3716       bar =XNS_SCROLL_BAR (window->vertical_scroll_bar);
3717       [bar reprieve];
3718     }
3722 static void
3723 ns_judge_scroll_bars (struct frame *f)
3724 /* --------------------------------------------------------------------------
3725      External (hook): destroy all scrollbars on frame that weren't
3726      redeemed after call to condemn_scroll_bars.
3727    -------------------------------------------------------------------------- */
3729   int i;
3730   id view;
3731   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3732   NSTRACE (ns_judge_scroll_bars);
3733   for (i =[subviews count]-1; i >= 0; i--)
3734     {
3735       view = [subviews objectAtIndex: i];
3736       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3737       [view judge];
3738     }
3742 void
3743 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
3745   /* XXX irrelevant under NS */
3750 /* ==========================================================================
3752     Initialization
3754    ========================================================================== */
3757 x_display_pixel_height (struct ns_display_info *dpyinfo)
3759   NSScreen *screen = [NSScreen mainScreen];
3760   return [screen frame].size.height;
3764 x_display_pixel_width (struct ns_display_info *dpyinfo)
3766   NSScreen *screen = [NSScreen mainScreen];
3767   return [screen frame].size.width;
3771 static Lisp_Object ns_string_to_lispmod (const char *s)
3772 /* --------------------------------------------------------------------------
3773      Convert modifier name to lisp symbol
3774    -------------------------------------------------------------------------- */
3776   if (!strncmp (SDATA (SYMBOL_NAME (Qmeta)), s, 10))
3777     return Qmeta;
3778   else if (!strncmp (SDATA (SYMBOL_NAME (Qsuper)), s, 10))
3779     return Qsuper;
3780   else if (!strncmp (SDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3781     return Qcontrol;
3782   else if (!strncmp (SDATA (SYMBOL_NAME (Qalt)), s, 10))
3783     return Qalt;
3784   else if (!strncmp (SDATA (SYMBOL_NAME (Qhyper)), s, 10))
3785     return Qhyper;
3786   else if (!strncmp (SDATA (SYMBOL_NAME (Qnone)), s, 10))
3787     return Qnone;
3788   else
3789     return Qnil;
3793 static Lisp_Object ns_mod_to_lisp (int m)
3794 /* --------------------------------------------------------------------------
3795      Convert modifier code (see lisp.h) to lisp symbol
3796    -------------------------------------------------------------------------- */
3798   if (m == CHAR_META)
3799     return Qmeta;
3800   else if (m == CHAR_SUPER)
3801     return Qsuper;
3802   else if (m == CHAR_CTL)
3803     return Qcontrol;
3804   else if (m == CHAR_ALT)
3805     return Qalt;
3806   else if (m == CHAR_HYPER)
3807     return Qhyper;
3808   else /* if (m == 0) */
3809     return Qnone;
3813 static void
3814 ns_default (const char *parameter, Lisp_Object *result,
3815            Lisp_Object yesval, Lisp_Object noval,
3816            BOOL is_float, BOOL is_modstring)
3817 /* --------------------------------------------------------------------------
3818       Check a parameter value in user's preferences
3819    -------------------------------------------------------------------------- */
3821   const char *value;
3823   if ( (value =[[[NSUserDefaults standardUserDefaults]
3824                    stringForKey: [NSString stringWithUTF8String: parameter]]
3825                 UTF8String]) )
3826     {
3827       double f;
3828       char *pos;
3829       if (strcasecmp (value, "YES") == 0)
3830         *result = yesval;
3831       else if (strcasecmp (value, "NO") == 0)
3832         *result = noval;
3833       else if (is_float && (f = strtod (value, &pos), pos != value))
3834         *result = make_float (f);
3835       else if (is_modstring && value)
3836         *result = ns_string_to_lispmod (value);
3837       else fprintf (stderr,
3838                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3839     }
3843 void
3844 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3845 /* --------------------------------------------------------------------------
3846       Initialize global info and storage for display.
3847    -------------------------------------------------------------------------- */
3849     NSScreen *screen = [NSScreen mainScreen];
3850     NSWindowDepth depth = [screen depth];
3851     Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
3853     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3854     dpyinfo->resy = 72.27;
3855     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3856                                                   NSColorSpaceFromDepth (depth)]
3857                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3858                                                  NSColorSpaceFromDepth (depth)];
3859     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3860     dpyinfo->image_cache = make_image_cache ();
3861     dpyinfo->color_table
3862       = (struct ns_color_table *)xmalloc (sizeof (struct ns_color_table));
3863     dpyinfo->color_table->colors = NULL;
3864     dpyinfo->root_window = 42; /* a placeholder.. */
3866     hlinfo->mouse_face_mouse_frame = NULL;
3867     hlinfo->mouse_face_deferred_gc = 0;
3868     hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
3869     hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
3870     hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
3871     hlinfo->mouse_face_window = hlinfo->mouse_face_overlay = Qnil;
3872     hlinfo->mouse_face_hidden = 0;
3874     hlinfo->mouse_face_mouse_x = hlinfo->mouse_face_mouse_y = 0;
3875     hlinfo->mouse_face_defer = 0;
3877     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3879     dpyinfo->n_fonts = 0;
3880     dpyinfo->smallest_font_height = 1;
3881     dpyinfo->smallest_char_width = 1;
3885 /* This and next define (many of the) public functions in this file. */
3886 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3887          with using despite presence in the "system dependent" redisplay
3888          interface.  In addition, many of the ns_ methods have code that is
3889          shared with all terms, indicating need for further refactoring. */
3890 extern frame_parm_handler ns_frame_parm_handlers[];
3891 static struct redisplay_interface ns_redisplay_interface =
3893   ns_frame_parm_handlers,
3894   x_produce_glyphs,
3895   x_write_glyphs,
3896   x_insert_glyphs,
3897   x_clear_end_of_line,
3898   ns_scroll_run,
3899   ns_after_update_window_line,
3900   ns_update_window_begin,
3901   ns_update_window_end,
3902   x_cursor_to,
3903   ns_flush,
3904   0, /* flush_display_optional */
3905   x_clear_window_mouse_face,
3906   x_get_glyph_overhangs,
3907   x_fix_overlapping_area,
3908   ns_draw_fringe_bitmap,
3909   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3910   0, /* destroy_fringe_bitmap */
3911   ns_compute_glyph_string_overhangs,
3912   ns_draw_glyph_string, /* interface to nsfont.m */
3913   ns_define_frame_cursor,
3914   ns_clear_frame_area,
3915   ns_draw_window_cursor,
3916   ns_draw_vertical_window_border,
3917   ns_shift_glyphs_for_insert
3921 static void
3922 ns_delete_display (struct ns_display_info *dpyinfo)
3924   /* TODO... */
3928 /* This function is called when the last frame on a display is deleted. */
3929 static void
3930 ns_delete_terminal (struct terminal *terminal)
3932   struct ns_display_info *dpyinfo = terminal->display_info.ns;
3933   int i;
3935   /* Protect against recursive calls.  delete_frame in
3936      delete_terminal calls us back when it deletes our last frame.  */
3937   if (!terminal->name)
3938     return;
3940   BLOCK_INPUT;
3942   x_destroy_all_bitmaps (dpyinfo);
3943   ns_delete_display (dpyinfo);
3944   UNBLOCK_INPUT;
3948 static struct terminal *
3949 ns_create_terminal (struct ns_display_info *dpyinfo)
3950 /* --------------------------------------------------------------------------
3951       Set up use of NS before we make the first connection.
3952    -------------------------------------------------------------------------- */
3954   struct terminal *terminal;
3956   NSTRACE (ns_create_terminal);
3958   terminal = create_terminal ();
3960   terminal->type = output_ns;
3961   terminal->display_info.ns = dpyinfo;
3962   dpyinfo->terminal = terminal;
3964   terminal->rif = &ns_redisplay_interface;
3966   terminal->clear_frame_hook = ns_clear_frame;
3967   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
3968   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
3969   terminal->ring_bell_hook = ns_ring_bell;
3970   terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
3971   terminal->set_terminal_modes_hook = ns_set_terminal_modes;
3972   terminal->update_begin_hook = ns_update_begin;
3973   terminal->update_end_hook = ns_update_end;
3974   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
3975   terminal->read_socket_hook = ns_read_socket;
3976   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
3977   terminal->mouse_position_hook = ns_mouse_position;
3978   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
3979   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
3981   terminal->fullscreen_hook = 0; /* see XTfullscreen_hook */
3983   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
3984   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
3985   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
3986   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
3988   terminal->delete_frame_hook = x_destroy_window;
3989   terminal->delete_terminal_hook = ns_delete_terminal;
3991   terminal->scroll_region_ok = 1;
3992   terminal->char_ins_del_ok = 1;
3993   terminal->line_ins_del_ok = 1;
3994   terminal->fast_clear_end_of_line = 1;
3995   terminal->memory_below_frame = 0;
3997   return terminal;
4001 struct ns_display_info *
4002 ns_term_init (Lisp_Object display_name)
4003 /* --------------------------------------------------------------------------
4004      Start the Application and get things rolling.
4005    -------------------------------------------------------------------------- */
4007   struct terminal *terminal;
4008   struct ns_display_info *dpyinfo;
4009   static int ns_initialized = 0;
4010   Lisp_Object tmp;
4012   NSTRACE (ns_term_init);
4014   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4015   /*GSDebugAllocationActive (YES); */
4016   BLOCK_INPUT;
4017   handling_signal = 0;
4019   if (!ns_initialized)
4020     {
4021       baud_rate = 38400;
4022       Fset_input_interrupt_mode (Qnil);
4023       ns_initialized = 1;
4024     }
4026   ns_pending_files = [[NSMutableArray alloc] init];
4027   ns_pending_service_names = [[NSMutableArray alloc] init];
4028   ns_pending_service_args = [[NSMutableArray alloc] init];
4030   /* Start app and create the main menu, window, view.
4031      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4032      The view will then ask the NSApp to stop and return to Emacs. */
4033   [EmacsApp sharedApplication];
4034   if (NSApp == nil)
4035     return NULL;
4036   [NSApp setDelegate: NSApp];
4038   /* debugging: log all notifications */
4039   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4040                                          selector: @selector (logNotification:)
4041                                              name: nil object: nil]; */
4043   dpyinfo = (struct ns_display_info *)xmalloc (sizeof (struct ns_display_info));
4044   memset (dpyinfo, 0, sizeof (struct ns_display_info));
4046   ns_initialize_display_info (dpyinfo);
4047   terminal = ns_create_terminal (dpyinfo);
4049   terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
4050   init_kboard (terminal->kboard);
4051   KVAR (terminal->kboard, Vwindow_system) = Qns;
4052   terminal->kboard->next_kboard = all_kboards;
4053   all_kboards = terminal->kboard;
4054   /* Don't let the initial kboard remain current longer than necessary.
4055      That would cause problems if a file loaded on startup tries to
4056      prompt in the mini-buffer.  */
4057   if (current_kboard == initial_kboard)
4058     current_kboard = terminal->kboard;
4059   terminal->kboard->reference_count++;
4061   dpyinfo->next = x_display_list;
4062   x_display_list = dpyinfo;
4064   /* Put it on ns_display_name_list */
4065   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
4066                                 ns_display_name_list);
4067   dpyinfo->name_list_element = XCAR (ns_display_name_list);
4069   /* Set the name of the terminal. */
4070   terminal->name = (char *) xmalloc (SBYTES (display_name) + 1);
4071   strncpy (terminal->name, SDATA (display_name), SBYTES (display_name));
4072   terminal->name[SBYTES (display_name)] = 0;
4074   UNBLOCK_INPUT;
4076   if (!inhibit_x_resources)
4077     {
4078       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4079                  Qt, Qnil, NO, NO);
4080       tmp = Qnil;
4081       /* this is a standard variable */
4082       ns_default ("AppleAntiAliasingThreshold", &tmp,
4083                  make_float (10.0), make_float (6.0), YES, NO);
4084       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4085     }
4087   ns_selection_color = [[NSUserDefaults standardUserDefaults]
4088                          stringForKey: @"AppleHighlightColor"];
4089   if (ns_selection_color == nil)
4090     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
4092   {
4093     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4095     if ( cl == nil )
4096       {
4097         Lisp_Object color_file, color_map, color;
4098         int r,g,b;
4099         unsigned long c;
4100         char *name;
4102         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4103                          Fsymbol_value (intern ("data-directory")));
4104         if (NILP (Ffile_readable_p (color_file)))
4105           fatal ("Could not find %s.\n", SDATA (color_file));
4107         color_map = Fx_load_color_file (color_file);
4108         if (NILP (color_map))
4109           fatal ("Could not read %s.\n", SDATA (color_file));
4111         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4112         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4113           {
4114             color = XCAR (color_map);
4115             name = SDATA (XCAR (color));
4116             c = XINT (XCDR (color));
4117             [cl setColor:
4118                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4119                                             green: GREEN_FROM_ULONG (c) / 255.0
4120                                              blue: BLUE_FROM_ULONG (c) / 255.0
4121                                             alpha: 1.0]
4122                   forKey: [NSString stringWithUTF8String: name]];
4123           }
4124         [cl writeToFile: nil];
4125       }
4126   }
4128   {
4129     char c[128];
4130 #ifdef NS_IMPL_GNUSTEP
4131     strncpy (c, gnustep_base_version, sizeof (c));
4132 #else
4133     /*PSnextrelease (128, c); */
4134     snprintf (c, sizeof (c), "%g", NSAppKitVersionNumber);
4135 #endif
4136     Vwindow_system_version = build_string (c);
4137   }
4139   delete_keyboard_wait_descriptor (0);
4141   ns_app_name = [[NSProcessInfo processInfo] processName];
4143 /* Set up OS X app menu */
4144 #ifdef NS_IMPL_COCOA
4145   {
4146     NSMenu *appMenu;
4147     NSMenuItem *item;
4148     /* set up the application menu */
4149     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4150     [svcsMenu setAutoenablesItems: NO];
4151     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4152     [appMenu setAutoenablesItems: NO];
4153     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4154     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4156     [appMenu insertItemWithTitle: @"About Emacs"
4157                           action: @selector (orderFrontStandardAboutPanel:)
4158                    keyEquivalent: @""
4159                          atIndex: 0];
4160     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4161     [appMenu insertItemWithTitle: @"Preferences..."
4162                           action: @selector (showPreferencesWindow:)
4163                    keyEquivalent: @","
4164                          atIndex: 2];
4165     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4166     item = [appMenu insertItemWithTitle: @"Services"
4167                                  action: @selector (menuDown:)
4168                           keyEquivalent: @""
4169                                 atIndex: 4];
4170     [appMenu setSubmenu: svcsMenu forItem: item];
4171     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4172     [appMenu insertItemWithTitle: @"Hide Emacs"
4173                           action: @selector (hide:)
4174                    keyEquivalent: @"h"
4175                          atIndex: 6];
4176     item =  [appMenu insertItemWithTitle: @"Hide Others"
4177                           action: @selector (hideOtherApplications:)
4178                    keyEquivalent: @"h"
4179                          atIndex: 7];
4180     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4181     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4182     [appMenu insertItemWithTitle: @"Quit Emacs"
4183                           action: @selector (terminate:)
4184                    keyEquivalent: @"q"
4185                          atIndex: 9];
4187     item = [mainMenu insertItemWithTitle: ns_app_name
4188                                   action: @selector (menuDown:)
4189                            keyEquivalent: @""
4190                                  atIndex: 0];
4191     [mainMenu setSubmenu: appMenu forItem: item];
4192     [dockMenu insertItemWithTitle: @"New Frame"
4193                            action: @selector (newFrame:)
4194                     keyEquivalent: @""
4195                           atIndex: 0];
4197     [NSApp setMainMenu: mainMenu];
4198     [NSApp setAppleMenu: appMenu];
4199     [NSApp setServicesMenu: svcsMenu];
4200     /* Needed at least on Cocoa, to get dock menu to show windows */
4201     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4202   }
4203 #endif /* MAC OS X menu setup */
4205   [NSApp run];
4207   return dpyinfo;
4211 void
4212 ns_term_shutdown (int sig)
4214   [[NSUserDefaults standardUserDefaults] synchronize];
4216   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4217   if (STRINGP (Vauto_save_list_file_name))
4218     unlink (SDATA (Vauto_save_list_file_name));
4220   if (sig == 0 || sig == SIGTERM)
4221     {
4222       [NSApp terminate: NSApp];
4223     }
4224   else // force a stack trace to happen
4225     {
4226       abort();
4227     }
4231 /* ==========================================================================
4233     EmacsApp implementation
4235    ========================================================================== */
4238 @implementation EmacsApp
4240 - (void)logNotification: (NSNotification *)notification
4242   const char *name = [[notification name] UTF8String];
4243   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4244       && !strstr (name, "WindowNumber"))
4245     NSLog (@"notification: '%@'", [notification name]);
4249 - (void)sendEvent: (NSEvent *)theEvent
4250 /* --------------------------------------------------------------------------
4251      Called when NSApp is running for each event received.  Used to stop
4252      the loop when we choose, since there's no way to just run one iteration.
4253    -------------------------------------------------------------------------- */
4255   int type = [theEvent type];
4256   NSWindow *window = [theEvent window];
4257 /*  NSTRACE (sendEvent); */
4258 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4260 #ifdef NS_IMPL_COCOA
4261   if (type == NSApplicationDefined
4262       && [theEvent data2] == NSAPP_DATA2_RUNASSCRIPT)
4263     {
4264       ns_run_ascript ();
4265       [self stop: self];
4266       return;
4267     }
4268 #endif
4270   if (type == NSCursorUpdate && window == nil)
4271     {
4272       fprintf (stderr, "Dropping external cursor update event.\n");
4273       return;
4274     }
4276 #ifdef NS_IMPL_COCOA
4277   /* pass mouse down in resize handle and subsequent drags directly to
4278      EmacsWindow so we can generate continuous redisplays */
4279   if (ns_in_resize)
4280     {
4281       if (type == NSLeftMouseDragged)
4282         {
4283           [window mouseDragged: theEvent];
4284           return;
4285         }
4286       else if (type == NSLeftMouseUp)
4287         {
4288           [window mouseUp: theEvent];
4289           return;
4290         }
4291     }
4292   else if (type == NSLeftMouseDown)
4293     {
4294       NSRect r = ns_resize_handle_rect (window);
4295       if (NSPointInRect ([theEvent locationInWindow], r))
4296         {
4297           ns_in_resize = YES;
4298           [window mouseDown: theEvent];
4299           return;
4300         }
4301     }
4302 #endif
4304   if (type == NSApplicationDefined)
4305     {
4306       /* Events posted by ns_send_appdefined interrupt the run loop here.
4307          But, if a modal window is up, an appdefined can still come through,
4308          (e.g., from a makeKeyWindow event) but stopping self also stops the
4309          modal loop. Just defer it until later. */
4310       if ([NSApp modalWindow] == nil)
4311         {
4312           last_appdefined_event = theEvent;
4313           [self stop: self];
4314         }
4315       else
4316         {
4317           send_appdefined = YES;
4318         }
4319     }
4321   [super sendEvent: theEvent];
4325 - (void)showPreferencesWindow: (id)sender
4327   struct frame *emacsframe = SELECTED_FRAME ();
4328   NSEvent *theEvent = [NSApp currentEvent];
4330   if (!emacs_event)
4331     return;
4332   emacs_event->kind = NS_NONKEY_EVENT;
4333   emacs_event->code = KEY_NS_SHOW_PREFS;
4334   emacs_event->modifiers = 0;
4335   EV_TRAILER (theEvent);
4339 - (void)newFrame: (id)sender
4341   struct frame *emacsframe = SELECTED_FRAME ();
4342   NSEvent *theEvent = [NSApp currentEvent];
4344   if (!emacs_event)
4345     return;
4346   emacs_event->kind = NS_NONKEY_EVENT;
4347   emacs_event->code = KEY_NS_NEW_FRAME;
4348   emacs_event->modifiers = 0;
4349   EV_TRAILER (theEvent);
4353 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4354 - (BOOL) openFile: (NSString *)fileName
4356   struct frame *emacsframe = SELECTED_FRAME ();
4357   NSEvent *theEvent = [NSApp currentEvent];
4359   if (!emacs_event)
4360     return NO;
4362   emacs_event->kind = NS_NONKEY_EVENT;
4363   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4364   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4365   ns_input_line = Qnil; /* can be start or cons start,end */
4366   emacs_event->modifiers =0;
4367   EV_TRAILER (theEvent);
4369   return YES;
4373 /* **************************************************************************
4375       EmacsApp delegate implementation
4377    ************************************************************************** */
4379 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4380 /* --------------------------------------------------------------------------
4381      When application is loaded, terminate event loop in ns_term_init
4382    -------------------------------------------------------------------------- */
4384   NSTRACE (applicationDidFinishLaunching);
4385   [NSApp setServicesProvider: NSApp];
4386   ns_send_appdefined (-2);
4390 /* Termination sequences:
4391     C-x C-c:
4392     Cmd-Q:
4393     MenuBar | File | Exit:
4394     Select Quit from App menubar:
4395         -terminate
4396         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4397         ns_term_shutdown()
4399     Select Quit from Dock menu:
4400     Logout attempt:
4401         -appShouldTerminate
4402           Cancel -> Nothing else
4403           Accept ->
4405           -terminate
4406           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4407           ns_term_shutdown()
4411 - (void) terminate: (id)sender
4413   struct frame *emacsframe = SELECTED_FRAME ();
4415   if (!emacs_event)
4416     return;
4418   emacs_event->kind = NS_NONKEY_EVENT;
4419   emacs_event->code = KEY_NS_POWER_OFF;
4420   emacs_event->arg = Qt; /* mark as non-key event */
4421   EV_TRAILER ((id)nil);
4425 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4427   int ret;
4429   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4430     return NSTerminateNow;
4432     ret = NSRunAlertPanel(ns_app_name,
4433                           [NSString stringWithUTF8String:"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?"],
4434                           @"Save Buffers and Exit", @"Cancel", nil);
4436     if (ret == NSAlertDefaultReturn)
4437         return NSTerminateNow;
4438     else if (ret == NSAlertAlternateReturn)
4439         return NSTerminateCancel;
4440     return NSTerminateNow;  /* just in case */
4444 /*   Notification from the Workspace to open a file */
4445 - (BOOL)application: sender openFile: (NSString *)file
4447   [ns_pending_files addObject: file];
4448   return YES;
4452 /*   Open a file as a temporary file */
4453 - (BOOL)application: sender openTempFile: (NSString *)file
4455   [ns_pending_files addObject: file];
4456   return YES;
4460 /*   Notification from the Workspace to open a file noninteractively (?) */
4461 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4463   [ns_pending_files addObject: file];
4464   return YES;
4468 /*   Notification from the Workspace to open multiple files */
4469 - (void)application: sender openFiles: (NSArray *)fileList
4471   NSEnumerator *files = [fileList objectEnumerator];
4472   NSString *file;
4473   while ((file = [files nextObject]) != nil)
4474     [ns_pending_files addObject: file];
4476   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4481 /* Handle dock menu requests.  */
4482 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4484   return dockMenu;
4488 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4489 - (void)applicationWillBecomeActive: (NSNotification *)notification
4491   //ns_app_active=YES;
4493 - (void)applicationDidBecomeActive: (NSNotification *)notification
4495   NSTRACE (applicationDidBecomeActive);
4497   //ns_app_active=YES;
4499   ns_update_auto_hide_menu_bar ();
4500   // No constrining takes place when the application is not active.
4501   ns_constrain_all_frames ();
4503 - (void)applicationDidResignActive: (NSNotification *)notification
4505   //ns_app_active=NO;
4506   ns_send_appdefined (-1);
4511 /* ==========================================================================
4513     EmacsApp aux handlers for managing event loop
4515    ========================================================================== */
4518 - (void)timeout_handler: (NSTimer *)timedEntry
4519 /* --------------------------------------------------------------------------
4520      The timeout specified to ns_select has passed.
4521    -------------------------------------------------------------------------- */
4523   /*NSTRACE (timeout_handler); */
4524   ns_send_appdefined (-2);
4527 - (void)fd_handler: (NSTimer *) fdEntry
4528 /* --------------------------------------------------------------------------
4529      Check data waiting on file descriptors and terminate if so
4530    -------------------------------------------------------------------------- */
4532   int result;
4533   /* NSTRACE (fd_handler); */
4535   if (select_nfds == 0)
4536     return;
4538   memcpy (&t_readfds, &select_readfds, sizeof (fd_set));
4540   select_timeout.tv_sec = select_timeout.tv_usec = 0;
4541   result = select (select_nfds, &t_readfds, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
4542                   &select_timeout);
4543   if (result)
4544     {
4545       memcpy (&select_readfds, &t_readfds, sizeof (fd_set));
4546       ns_send_appdefined (result);
4547     }
4552 /* ==========================================================================
4554     Service provision
4556    ========================================================================== */
4558 /* called from system: queue for next pass through event loop */
4559 - (void)requestService: (NSPasteboard *)pboard
4560               userData: (NSString *)userData
4561                  error: (NSString **)error
4563   [ns_pending_service_names addObject: userData];
4564   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4565       SDATA (ns_string_from_pasteboard (pboard))]];
4569 /* called from ns_read_socket to clear queue */
4570 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4572   struct frame *emacsframe = SELECTED_FRAME ();
4573   NSEvent *theEvent = [NSApp currentEvent];
4575   if (!emacs_event)
4576     return NO;
4578   emacs_event->kind = NS_NONKEY_EVENT;
4579   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4580   ns_input_spi_name = build_string ([name UTF8String]);
4581   ns_input_spi_arg = build_string ([arg UTF8String]);
4582   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4583   EV_TRAILER (theEvent);
4585   return YES;
4589 @end  /* EmacsApp */
4593 /* ==========================================================================
4595     EmacsView implementation
4597    ========================================================================== */
4600 @implementation EmacsView
4602 /* needed to inform when window closed from LISP */
4603 - (void) setWindowClosing: (BOOL)closing
4605   windowClosing = closing;
4609 - (void)dealloc
4611   NSTRACE (EmacsView_dealloc);
4612   [toolbar release];
4613   [super dealloc];
4617 /* called on font panel selection */
4618 - (void)changeFont: (id)sender
4620   NSEvent *e =[[self window] currentEvent];
4621   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4622   id newFont;
4623   float size;
4625   NSTRACE (changeFont);
4626   if (!emacs_event)
4627     return;
4629   if (newFont = [sender convertFont:
4630                            ((struct nsfont_info *)face->font)->nsfont])
4631     {
4632       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4634       emacs_event->kind = NS_NONKEY_EVENT;
4635       emacs_event->modifiers = 0;
4636       emacs_event->code = KEY_NS_CHANGE_FONT;
4638       size = [newFont pointSize];
4639       ns_input_fontsize = make_number (lrint (size));
4640       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4641       EV_TRAILER (e);
4642     }
4646 - (BOOL)acceptsFirstResponder
4648   NSTRACE (acceptsFirstResponder);
4649   return YES;
4653 - (void)resetCursorRects
4655   NSRect visible = [self visibleRect];
4656   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4657   NSTRACE (resetCursorRects);
4659   if (currentCursor == nil)
4660     currentCursor = [NSCursor arrowCursor];
4662   if (!NSIsEmptyRect (visible))
4663     [self addCursorRect: visible cursor: currentCursor];
4664   [currentCursor setOnMouseEntered: YES];
4669 /*****************************************************************************/
4670 /* Keyboard handling. */
4671 #define NS_KEYLOG 0
4673 - (void)keyDown: (NSEvent *)theEvent
4675   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4676   int code;
4677   unsigned fnKeysym = 0;
4678   int flags;
4679   static NSMutableArray *nsEvArray;
4680 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4681   static BOOL firstTime = YES;
4682 #endif
4683   int left_is_none;
4685   NSTRACE (keyDown);
4687   /* Rhapsody and OS X give up and down events for the arrow keys */
4688   if (ns_fake_keydown == YES)
4689     ns_fake_keydown = NO;
4690   else if ([theEvent type] != NSKeyDown)
4691     return;
4693   if (!emacs_event)
4694     return;
4696  if (![[self window] isKeyWindow]
4697      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4698      /* we must avoid an infinite loop here. */
4699      && (EmacsView *)[[theEvent window] delegate] != self)
4700    {
4701      /* XXX: There is an occasional condition in which, when Emacs display
4702          updates a different frame from the current one, and temporarily
4703          selects it, then processes some interrupt-driven input
4704          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4705          for some reason that window has its first responder set to the NSView
4706          most recently updated (I guess), which is not the correct one. */
4707      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4708      return;
4709    }
4711   if (nsEvArray == nil)
4712     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4714   [NSCursor setHiddenUntilMouseMoves: YES];
4716   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4717     {
4718       clear_mouse_face (hlinfo);
4719       hlinfo->mouse_face_hidden = 1;
4720     }
4722   if (!processingCompose)
4723     {
4724       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4725         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4726       /* (Carbon way: [theEvent keyCode]) */
4728       /* is it a "function key"? */
4729       fnKeysym = ns_convert_key (code);
4730       if (fnKeysym)
4731         {
4732           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4733              because Emacs treats Delete and KP-Delete same (in simple.el). */
4734           if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4735             code = 0xFF08; /* backspace */
4736           else
4737             code = fnKeysym;
4738         }
4740       /* are there modifiers? */
4741       emacs_event->modifiers = 0;
4742       flags = [theEvent modifierFlags];
4744       if (flags & NSHelpKeyMask)
4745           emacs_event->modifiers |= hyper_modifier;
4747       if (flags & NSShiftKeyMask)
4748         emacs_event->modifiers |= shift_modifier;
4750       if ((flags & NSRightCommandKeyMask) == NSRightCommandKeyMask)
4751         emacs_event->modifiers |= parse_solitary_modifier
4752           (EQ (ns_right_command_modifier, Qleft)
4753            ? ns_command_modifier
4754            : ns_right_command_modifier);
4756       if ((flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask)
4757         {
4758           emacs_event->modifiers |= parse_solitary_modifier
4759             (ns_command_modifier);
4761           /* if super (default), take input manager's word so things like
4762              dvorak / qwerty layout work */
4763           if (EQ (ns_command_modifier, Qsuper)
4764               && !fnKeysym
4765               && [[theEvent characters] length] != 0)
4766             {
4767               /* XXX: the code we get will be unshifted, so if we have
4768                  a shift modifier, must convert ourselves */
4769               if (!(flags & NSShiftKeyMask))
4770                 code = [[theEvent characters] characterAtIndex: 0];
4771 #if 0
4772               /* this is ugly and also requires linking w/Carbon framework
4773                  (for LMGetKbdType) so for now leave this rare (?) case
4774                  undealt with.. in future look into CGEvent methods */
4775               else
4776                 {
4777                   long smv = GetScriptManagerVariable (smKeyScript);
4778                   Handle uchrHandle = GetResource
4779                     ('uchr', GetScriptVariable (smv, smScriptKeys));
4780                   UInt32 dummy = 0;
4781                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
4782                                  [[theEvent characters] characterAtIndex: 0],
4783                                  kUCKeyActionDisplay,
4784                                  (flags & ~NSCommandKeyMask) >> 8,
4785                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
4786                                  &dummy, 1, &dummy, &code);
4787                   code &= 0xFF;
4788                 }
4789 #endif
4790             }
4791         }
4793       if ((flags & NSRightControlKeyMask) == NSRightControlKeyMask)
4794           emacs_event->modifiers |= parse_solitary_modifier
4795               (EQ (ns_right_control_modifier, Qleft)
4796                ? ns_control_modifier
4797                : ns_right_control_modifier);
4799       if ((flags & NSLeftControlKeyMask) == NSLeftControlKeyMask)
4800         emacs_event->modifiers |= parse_solitary_modifier
4801           (ns_control_modifier);
4803       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
4804           emacs_event->modifiers |=
4805             parse_solitary_modifier (ns_function_modifier);
4807       left_is_none = NILP (ns_alternate_modifier)
4808         || EQ (ns_alternate_modifier, Qnone);
4810       if ((flags & NSRightAlternateKeyMask) == NSRightAlternateKeyMask)
4811         {
4812           if ((NILP (ns_right_alternate_modifier)
4813                || EQ (ns_right_alternate_modifier, Qnone)
4814                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
4815               && !fnKeysym)
4816             {   /* accept pre-interp alt comb */
4817               if ([[theEvent characters] length] > 0)
4818                 code = [[theEvent characters] characterAtIndex: 0];
4819               /*HACK: clear lone shift modifier to stop next if from firing */
4820               if (emacs_event->modifiers == shift_modifier)
4821                 emacs_event->modifiers = 0;
4822             }
4823           else
4824             emacs_event->modifiers |= parse_solitary_modifier
4825               (EQ (ns_right_alternate_modifier, Qleft)
4826                ? ns_alternate_modifier
4827                : ns_right_alternate_modifier);
4828         }
4830       if ((flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask) /* default = meta */
4831         {
4832           if (left_is_none && !fnKeysym)
4833             {   /* accept pre-interp alt comb */
4834               if ([[theEvent characters] length] > 0)
4835                 code = [[theEvent characters] characterAtIndex: 0];
4836               /*HACK: clear lone shift modifier to stop next if from firing */
4837               if (emacs_event->modifiers == shift_modifier)
4838                 emacs_event->modifiers = 0;
4839             }
4840           else
4841               emacs_event->modifiers |=
4842                 parse_solitary_modifier (ns_alternate_modifier);
4843         }
4845   if (NS_KEYLOG)
4846     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
4847              code, fnKeysym, flags, emacs_event->modifiers);
4849       /* if it was a function key or had modifiers, pass it directly to emacs */
4850       if (fnKeysym || (emacs_event->modifiers
4851                        && (emacs_event->modifiers != shift_modifier)
4852                        && [[theEvent charactersIgnoringModifiers] length] > 0))
4853 /*[[theEvent characters] length] */
4854         {
4855           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4856           if (code < 0x20)
4857             code |= (1<<28)|(3<<16);
4858           else if (code == 0x7f)
4859             code |= (1<<28)|(3<<16);
4860           else if (!fnKeysym)
4861             emacs_event->kind = code > 0xFF
4862               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4864           emacs_event->code = code;
4865           EV_TRAILER (theEvent);
4866           return;
4867         }
4868     }
4870   
4871 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4872   /* if we get here we should send the key for input manager processing */
4873   if (firstTime && [[NSInputManager currentInputManager]
4874                      wantsToDelayTextChangeNotifications] == NO)
4875     fprintf (stderr,
4876           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
4877   firstTime = NO;
4878 #endif
4879   if (NS_KEYLOG && !processingCompose)
4880     fprintf (stderr, "keyDown: Begin compose sequence.\n");
4882   processingCompose = YES;
4883   [nsEvArray addObject: theEvent];
4884   [self interpretKeyEvents: nsEvArray];
4885   [nsEvArray removeObject: theEvent];
4889 #ifdef NS_IMPL_COCOA
4890 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
4891    decided not to send key-down for.
4892    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
4893    This only applies on Tiger and earlier.
4894    If it matches one of these, send it on to keyDown. */
4895 -(void)keyUp: (NSEvent *)theEvent
4897   int flags = [theEvent modifierFlags];
4898   int code = [theEvent keyCode];
4899   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
4900       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
4901     {
4902       if (NS_KEYLOG)
4903         fprintf (stderr, "keyUp: passed test");
4904       ns_fake_keydown = YES;
4905       [self keyDown: theEvent];
4906     }
4908 #endif
4911 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
4914 /* <NSTextInput>: called when done composing;
4915    NOTE: also called when we delete over working text, followed immed.
4916          by doCommandBySelector: deleteBackward: */
4917 - (void)insertText: (id)aString
4919   int code;
4920   int len = [(NSString *)aString length];
4921   int i;
4923   if (NS_KEYLOG)
4924     NSLog (@"insertText '%@'\tlen = %d", aString, len);
4925   processingCompose = NO;
4927   if (!emacs_event)
4928     return;
4930   /* first, clear any working text */
4931   if (workingText != nil)
4932     [self deleteWorkingText];
4934   /* now insert the string as keystrokes */
4935   for (i =0; i<len; i++)
4936     {
4937       code = [aString characterAtIndex: i];
4938       /* TODO: still need this? */
4939       if (code == 0x2DC)
4940         code = '~'; /* 0x7E */
4941       emacs_event->modifiers = 0;
4942       emacs_event->kind
4943         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4944       emacs_event->code = code;
4945       EV_TRAILER ((id)nil);
4946     }
4950 /* <NSTextInput>: inserts display of composing characters */
4951 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
4953   NSString *str = [aString respondsToSelector: @selector (string)] ?
4954     [aString string] : aString;
4955   if (NS_KEYLOG)
4956     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
4957            selRange.length, selRange.location);
4959   if (workingText != nil)
4960     [self deleteWorkingText];
4961   if ([str length] == 0)
4962     return;
4964   if (!emacs_event)
4965     return;
4967   processingCompose = YES;
4968   workingText = [str copy];
4969   ns_working_text = build_string ([workingText UTF8String]);
4971   emacs_event->kind = NS_TEXT_EVENT;
4972   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
4973   EV_TRAILER ((id)nil);
4977 /* delete display of composing characters [not in <NSTextInput>] */
4978 - (void)deleteWorkingText
4980   if (workingText == nil)
4981     return;
4982   if (NS_KEYLOG)
4983     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
4984   [workingText release];
4985   workingText = nil;
4986   processingCompose = NO;
4988   if (!emacs_event)
4989     return;
4991   emacs_event->kind = NS_TEXT_EVENT;
4992   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
4993   EV_TRAILER ((id)nil);
4997 - (BOOL)hasMarkedText
4999   return workingText != nil;
5003 - (NSRange)markedRange
5005   NSRange rng = workingText != nil
5006     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5007   if (NS_KEYLOG)
5008     NSLog (@"markedRange request");
5009   return rng;
5013 - (void)unmarkText
5015   if (NS_KEYLOG)
5016     NSLog (@"unmark (accept) text");
5017   [self deleteWorkingText];
5018   processingCompose = NO;
5022 /* used to position char selection windows, etc. */
5023 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5025   NSRect rect;
5026   NSPoint pt;
5027   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5028   if (NS_KEYLOG)
5029     NSLog (@"firstRectForCharRange request");
5031   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5032   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5033   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5034   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5035                                        +FRAME_LINE_HEIGHT (emacsframe));
5037   pt = [self convertPoint: pt toView: nil];
5038   pt = [[self window] convertBaseToScreen: pt];
5039   rect.origin = pt;
5040   return rect;
5044 - (long)conversationIdentifier
5046   return (long)self;
5050 - (void)doCommandBySelector: (SEL)aSelector
5052   if (NS_KEYLOG)
5053     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5055   if (aSelector == @selector (deleteBackward:))
5056     {
5057       /* happens when user backspaces over an ongoing composition:
5058          throw a 'delete' into the event queue */
5059       if (!emacs_event)
5060         return;
5061       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5062       emacs_event->code = 0xFF08;
5063       EV_TRAILER ((id)nil);
5064     }
5067 - (NSArray *)validAttributesForMarkedText
5069   static NSArray *arr = nil;
5070   if (arr == nil) arr = [NSArray new];
5071  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5072   return arr;
5075 - (NSRange)selectedRange
5077   if (NS_KEYLOG)
5078     NSLog (@"selectedRange request");
5079   return NSMakeRange (NSNotFound, 0);
5082 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5084   if (NS_KEYLOG)
5085     NSLog (@"characterIndexForPoint request");
5086   return 0;
5089 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5091   static NSAttributedString *str = nil;
5092   if (str == nil) str = [NSAttributedString new];
5093   if (NS_KEYLOG)
5094     NSLog (@"attributedSubstringFromRange request");
5095   return str;
5098 /* End <NSTextInput> impl. */
5099 /*****************************************************************************/
5102 /* This is what happens when the user presses a mouse button.  */
5103 - (void)mouseDown: (NSEvent *)theEvent
5105   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5106   Lisp_Object window;
5108   NSTRACE (mouseDown);
5110   [self deleteWorkingText];
5112   if (!emacs_event)
5113     return;
5115   last_mouse_frame = emacsframe;
5116   /* appears to be needed to prevent spurious movement events generated on
5117      button clicks */
5118   last_mouse_frame->mouse_moved = 0;
5120   if ([theEvent type] == NSScrollWheel)
5121     {
5122       float delta = [theEvent deltaY];
5123       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5124       if (delta == 0)
5125         return;
5126       emacs_event->kind = WHEEL_EVENT;
5127       emacs_event->code = 0;
5128       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5129         ((delta > 0) ? up_modifier : down_modifier);
5130     }
5131   else
5132     {
5133       emacs_event->kind = MOUSE_CLICK_EVENT;
5134       emacs_event->code = EV_BUTTON (theEvent);
5135       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5136                              | EV_UDMODIFIERS (theEvent);
5137     }
5138   XSETINT (emacs_event->x, lrint (p.x));
5139   XSETINT (emacs_event->y, lrint (p.y));
5140   EV_TRAILER (theEvent);
5144 - (void)rightMouseDown: (NSEvent *)theEvent
5146   NSTRACE (rightMouseDown);
5147   [self mouseDown: theEvent];
5151 - (void)otherMouseDown: (NSEvent *)theEvent
5153   NSTRACE (otherMouseDown);
5154   [self mouseDown: theEvent];
5158 - (void)mouseUp: (NSEvent *)theEvent
5160   NSTRACE (mouseUp);
5161   [self mouseDown: theEvent];
5165 - (void)rightMouseUp: (NSEvent *)theEvent
5167   NSTRACE (rightMouseUp);
5168   [self mouseDown: theEvent];
5172 - (void)otherMouseUp: (NSEvent *)theEvent
5174   NSTRACE (otherMouseUp);
5175   [self mouseDown: theEvent];
5179 - (void) scrollWheel: (NSEvent *)theEvent
5181   NSTRACE (scrollWheel);
5182   [self mouseDown: theEvent];
5186 /* Tell emacs the mouse has moved. */
5187 - (void)mouseMoved: (NSEvent *)e
5189   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5190   Lisp_Object frame;
5192 //  NSTRACE (mouseMoved);
5194   last_mouse_movement_time = EV_TIMESTAMP (e);
5195   last_mouse_motion_position
5196     = [self convertPoint: [e locationInWindow] fromView: nil];
5198   /* update any mouse face */
5199   if (hlinfo->mouse_face_hidden)
5200     {
5201       hlinfo->mouse_face_hidden = 0;
5202       clear_mouse_face (hlinfo);
5203     }
5205   /* tooltip handling */
5206   previous_help_echo_string = help_echo_string;
5207   help_echo_string = Qnil;
5209   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
5210                             last_mouse_motion_position.y))
5211     help_echo_string = previous_help_echo_string;
5213   XSETFRAME (frame, emacsframe);
5214   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5215     {
5216       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5217          (note_mouse_highlight), which is called through the
5218          note_mouse_movement () call above */
5219       gen_help_event (help_echo_string, frame, help_echo_window,
5220                       help_echo_object, help_echo_pos);
5221     }
5222   else
5223     {
5224       help_echo_string = Qnil;
5225       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5226     }
5228   if (emacsframe->mouse_moved && send_appdefined)
5229     ns_send_appdefined (-1);
5233 - (void)mouseDragged: (NSEvent *)e
5235   NSTRACE (mouseDragged);
5236   [self mouseMoved: e];
5240 - (void)rightMouseDragged: (NSEvent *)e
5242   NSTRACE (rightMouseDragged);
5243   [self mouseMoved: e];
5247 - (void)otherMouseDragged: (NSEvent *)e
5249   NSTRACE (otherMouseDragged);
5250   [self mouseMoved: e];
5254 - (BOOL)windowShouldClose: (id)sender
5256   NSEvent *e =[[self window] currentEvent];
5258   NSTRACE (windowShouldClose);
5259   windowClosing = YES;
5260   if (!emacs_event)
5261     return NO;
5262   emacs_event->kind = DELETE_WINDOW_EVENT;
5263   emacs_event->modifiers = 0;
5264   emacs_event->code = 0;
5265   EV_TRAILER (e);
5266   /* Don't close this window, let this be done from lisp code.  */
5267   return NO;
5271 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5272 /* normalize frame to gridded text size */
5274   NSTRACE (windowWillResize);
5275 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5277   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5278 #ifdef NS_IMPL_GNUSTEP
5279                                         frameSize.width + 3);
5280 #else
5281                                         frameSize.width);
5282 #endif
5283   if (cols < MINWIDTH)
5284     cols = MINWIDTH;
5286   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, frameSize.height
5287 #ifdef NS_IMPL_GNUSTEP
5288       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + 3
5289         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5290 #else
5291       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5292         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5293 #endif
5294   if (rows < MINHEIGHT)
5295     rows = MINHEIGHT;
5296 #ifdef NS_IMPL_COCOA
5297   {
5298     /* this sets window title to have size in it; the wm does this under GS */
5299     NSRect r = [[self window] frame];
5300     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5301       {
5302         if (old_title != 0)
5303           {
5304             xfree (old_title);
5305             old_title = 0;
5306           }
5307       }
5308     else
5309       {
5310         char *size_title;
5311         NSWindow *window = [self window];
5312         if (old_title == 0)
5313           {
5314             const char *t = [[[self window] title] UTF8String];
5315             char *pos = strstr (t, "  â€”  ");
5316             if (pos)
5317               *pos = '\0';
5318             old_title = (char *) xmalloc (strlen (t) + 1);
5319             strcpy (old_title, t);
5320           }
5321         size_title = xmalloc (strlen (old_title) + 40);
5322         sprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5323         [window setTitle: [NSString stringWithUTF8String: size_title]];
5324         [window display];
5325         xfree (size_title);
5326       }
5327   }
5328 #endif /* NS_IMPL_COCOA */
5329 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5331   return frameSize;
5335 - (void)windowDidResize: (NSNotification *)notification
5337   NSWindow *theWindow = [notification object];
5339 #ifdef NS_IMPL_GNUSTEP
5340    /* in GNUstep, at least currently, it's possible to get a didResize
5341       without getting a willResize.. therefore we need to act as if we got
5342       the willResize now */
5343   NSSize sz = [theWindow frame].size;
5344   sz = [self windowWillResize: theWindow toSize: sz];
5345 #endif /* NS_IMPL_GNUSTEP */
5347   NSTRACE (windowDidResize);
5348 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5350 #ifdef NS_IMPL_COCOA
5351   if (old_title != 0)
5352     {
5353       xfree (old_title);
5354       old_title = 0;
5355     }
5356 #endif /* NS_IMPL_COCOA */
5358   /* Avoid loop under GNUstep due to call at beginning of this function.
5359      (x_set_window_size causes a resize which causes
5360      a "windowDidResize" which calls x_set_window_size).  */
5361 #ifndef NS_IMPL_GNUSTEP
5362   if (cols > 0 && rows > 0)
5363     x_set_window_size (emacsframe, 0, cols, rows);
5364 #endif
5366   ns_send_appdefined (-1);
5370 - (void)windowDidBecomeKey: (NSNotification *)notification
5371 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5373   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5374   struct frame *old_focus = dpyinfo->x_focus_frame;
5376   NSTRACE (windowDidBecomeKey);
5378   if (emacsframe != old_focus)
5379     dpyinfo->x_focus_frame = emacsframe;
5381   ns_frame_rehighlight (emacsframe);
5383   if (emacs_event)
5384     {
5385       emacs_event->kind = FOCUS_IN_EVENT;
5386       EV_TRAILER ((id)nil);
5387     }
5391 - (void)windowDidResignKey: (NSNotification *)notification
5392 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5394   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5395   NSTRACE (windowDidResignKey);
5397   if (dpyinfo->x_focus_frame == emacsframe)
5398     dpyinfo->x_focus_frame = 0;
5400   ns_frame_rehighlight (emacsframe);
5402   /* FIXME: for some reason needed on second and subsequent clicks away
5403             from sole-frame Emacs to get hollow box to show */
5404   if (!windowClosing && [[self window] isVisible] == YES)
5405     {
5406       x_update_cursor (emacsframe, 1);
5407       x_set_frame_alpha (emacsframe);
5408     }
5410   if (emacs_event)
5411     {
5412       [self deleteWorkingText];
5413       emacs_event->kind = FOCUS_IN_EVENT;
5414       EV_TRAILER ((id)nil);
5415     }
5419 - (void)windowWillMiniaturize: sender
5421   NSTRACE (windowWillMiniaturize);
5425 - (BOOL)isFlipped
5427   return YES;
5431 - (BOOL)isOpaque
5433   return NO;
5437 - initFrameFromEmacs: (struct frame *)f
5439   NSRect r, wr;
5440   Lisp_Object tem;
5441   NSWindow *win;
5442   NSButton *toggleButton;
5443   int vbextra = NS_SCROLL_BAR_WIDTH (f);
5444   NSSize sz;
5445   NSColor *col;
5446   NSString *name;
5448   NSTRACE (initFrameFromEmacs);
5450   windowClosing = NO;
5451   processingCompose = NO;
5452   scrollbarsNeedingUpdate = 0;
5454 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5456   ns_userRect = NSMakeRect (0, 0, 0, 0);
5457   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5458                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5459   [self initWithFrame: r];
5460   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5462   FRAME_NS_VIEW (f) = self;
5463   emacsframe = f;
5464   old_title = 0;
5466   win = [[EmacsWindow alloc]
5467             initWithContentRect: r
5468                       styleMask: (NSResizableWindowMask |
5469 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5470                                   NSTitledWindowMask |
5471 #endif
5472                                   NSMiniaturizableWindowMask |
5473                                   NSClosableWindowMask)
5474                         backing: NSBackingStoreBuffered
5475                           defer: YES];
5477   wr = [win frame];
5478   f->border_width = wr.size.width - r.size.width;
5479   FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5481   [win setAcceptsMouseMovedEvents: YES];
5482   [win setDelegate: self];
5483   [win useOptimizedDrawing: YES];
5485   sz.width = FRAME_COLUMN_WIDTH (f);
5486   sz.height = FRAME_LINE_HEIGHT (f);
5487   [win setResizeIncrements: sz];
5489   [[win contentView] addSubview: self];
5491   if (ns_drag_types)
5492     [self registerForDraggedTypes: ns_drag_types];
5494   tem = f->name;
5495   name = [NSString stringWithUTF8String:
5496                    NILP (tem) ? (unsigned char *)"Emacs" : SDATA (tem)];
5497   [win setTitle: name];
5499   /* toolbar support */
5500   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5501                          [NSString stringWithFormat: @"Emacs Frame %d",
5502                                    ns_window_num]];
5503   [win setToolbar: toolbar];
5504   [toolbar setVisible: NO];
5505 #ifdef NS_IMPL_COCOA
5506   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5507   [toggleButton setTarget: self];
5508   [toggleButton setAction: @selector (toggleToolbar: )];
5509 #endif
5510   FRAME_TOOLBAR_HEIGHT (f) = 0;
5512   tem = f->icon_name;
5513   if (!NILP (tem))
5514     [win setMiniwindowTitle:
5515            [NSString stringWithUTF8String: SDATA (tem)]];
5517   {
5518     NSScreen *screen = [win screen];
5520     if (screen != 0)
5521       [win setFrameTopLeftPoint: NSMakePoint
5522            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5523             IN_BOUND (-SCREENMAX,
5524                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5525   }
5527   [win makeFirstResponder: self];
5529   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5530                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5531   [win setBackgroundColor: col];
5532   if ([col alphaComponent] != 1.0)
5533     [win setOpaque: NO];
5535   [self allocateGState];
5537   [NSApp registerServicesMenuSendTypes: ns_send_types
5538                            returnTypes: nil];
5540   ns_window_num++;
5541   return self;
5545 - (void)windowDidMove: sender
5547   NSWindow *win = [self window];
5548   NSRect r = [win frame];
5549   NSArray *screens = [NSScreen screens];
5550   NSScreen *screen = [screens objectAtIndex: 0];
5552   NSTRACE (windowDidMove);
5554   if (!emacsframe->output_data.ns)
5555     return;
5556   if (screen != nil)
5557     {
5558       emacsframe->left_pos = r.origin.x;
5559       emacsframe->top_pos =
5560         [screen frame].size.height - (r.origin.y + r.size.height);
5561     }
5565 /* Called AFTER method below, but before our windowWillResize call there leads
5566    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5567    location so set_window_size moves the frame. */
5568 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5570   emacsframe->output_data.ns->zooming = 1;
5571   return YES;
5575 /* Override to do something slightly nonstandard, but nice.  First click on
5576    zoom button will zoom vertically.  Second will zoom completely.  Third
5577    returns to original. */
5578 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5579                         defaultFrame:(NSRect)defaultFrame
5581   NSRect result = [sender frame];
5583   NSTRACE (windowWillUseStandardFrame);
5585   if (abs (defaultFrame.size.height - result.size.height)
5586       > FRAME_LINE_HEIGHT (emacsframe))
5587     {
5588       /* first click */
5589       ns_userRect = result;
5590       result.size.height = defaultFrame.size.height;
5591       result.origin.y = defaultFrame.origin.y;
5592     }
5593   else
5594     {
5595       if (abs (defaultFrame.size.width - result.size.width)
5596           > FRAME_COLUMN_WIDTH (emacsframe))
5597         result = defaultFrame;  /* second click */
5598       else
5599         {
5600           /* restore */
5601           result = ns_userRect.size.height ? ns_userRect : result;
5602           ns_userRect = NSMakeRect (0, 0, 0, 0);
5603         }
5604     }
5606   [self windowWillResize: sender toSize: result.size];
5607   return result;
5611 - (void)windowDidDeminiaturize: sender
5613   NSTRACE (windowDidDeminiaturize);
5614   if (!emacsframe->output_data.ns)
5615     return;
5616   emacsframe->async_iconified = 0;
5617   emacsframe->async_visible   = 1;
5618   windows_or_buffers_changed++;
5620   if (emacs_event)
5621     {
5622       emacs_event->kind = ICONIFY_EVENT;
5623       EV_TRAILER ((id)nil);
5624     }
5628 - (void)windowDidExpose: sender
5630   NSTRACE (windowDidExpose);
5631   if (!emacsframe->output_data.ns)
5632     return;
5633   emacsframe->async_visible = 1;
5634   SET_FRAME_GARBAGED (emacsframe);
5636   if (send_appdefined)
5637     ns_send_appdefined (-1);
5641 - (void)windowDidMiniaturize: sender
5643   NSTRACE (windowDidMiniaturize);
5644   if (!emacsframe->output_data.ns)
5645     return;
5647   emacsframe->async_iconified = 1;
5648   emacsframe->async_visible = 0;
5650   if (emacs_event)
5651     {
5652       emacs_event->kind = ICONIFY_EVENT;
5653       EV_TRAILER ((id)nil);
5654     }
5658 - (void)mouseEntered: (NSEvent *)theEvent
5660   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5661   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5662   NSTRACE (mouseEntered);
5664   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5668 - (void)mouseExited: (NSEvent *)theEvent
5670   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5671   NSRect r;
5672   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
5674   NSTRACE (mouseExited);
5676   if (!hlinfo)
5677     return;
5679   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5681   if (emacsframe == hlinfo->mouse_face_mouse_frame)
5682     {
5683       clear_mouse_face (hlinfo);
5684       hlinfo->mouse_face_mouse_frame = 0;
5685     }
5689 - menuDown: sender
5691   NSTRACE (menuDown);
5692   if (context_menu_value == -1)
5693     context_menu_value = [sender tag];
5694   else
5695     find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
5696                                   emacsframe->menu_bar_vector,
5697                                   (void *)[sender tag]);
5698   ns_send_appdefined (-1);
5699   return self;
5703 - (EmacsToolbar *)toolbar
5705   return toolbar;
5709 /* this gets called on toolbar button click */
5710 - toolbarClicked: (id)item
5712   NSEvent *theEvent;
5713   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
5715   NSTRACE (toolbarClicked);
5717   if (!emacs_event)
5718     return self;
5720   /* send first event (for some reason two needed) */
5721   theEvent = [[self window] currentEvent];
5722   emacs_event->kind = TOOL_BAR_EVENT;
5723   XSETFRAME (emacs_event->arg, emacsframe);
5724   EV_TRAILER (theEvent);
5726   emacs_event->kind = TOOL_BAR_EVENT;
5727 /*   XSETINT (emacs_event->code, 0); */
5728   emacs_event->arg = AREF (emacsframe->tool_bar_items,
5729                           idx + TOOL_BAR_ITEM_KEY);
5730   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5731   EV_TRAILER (theEvent);
5732   return self;
5736 - toggleToolbar: (id)sender
5738   if (!emacs_event)
5739     return self;
5741   emacs_event->kind = NS_NONKEY_EVENT;
5742   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
5743   EV_TRAILER ((id)nil);
5744   return self;
5748 - (void)drawRect: (NSRect)rect
5750   int x = NSMinX (rect), y = NSMinY (rect);
5751   int width = NSWidth (rect), height = NSHeight (rect);
5753   NSTRACE (drawRect);
5755   if (!emacsframe || !emacsframe->output_data.ns || ns_in_resize)
5756     return;
5758   ns_clear_frame_area (emacsframe, x, y, width, height);
5759   expose_frame (emacsframe, x, y, width, height);
5761   /*
5762     drawRect: may be called (at least in OS X 10.5) for invisible
5763     views as well for some reason.  Thus, do not infer visibility
5764     here.
5766     emacsframe->async_visible = 1;
5767     emacsframe->async_iconified = 0;
5768   */
5772 /* NSDraggingDestination protocol methods.  Actually this is not really a
5773    protocol, but a category of Object.  O well...  */
5775 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
5777   NSTRACE (draggingEntered);
5778   return NSDragOperationGeneric;
5782 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
5784   return YES;
5788 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
5790   id pb;
5791   int x, y;
5792   NSString *type;
5793   NSEvent *theEvent = [[self window] currentEvent];
5794   NSPoint position;
5796   NSTRACE (performDragOperation);
5798   if (!emacs_event)
5799     return NO;
5801   position = [self convertPoint: [sender draggingLocation] fromView: nil];
5802   x = lrint (position.x);  y = lrint (position.y);
5804   pb = [sender draggingPasteboard];
5805   type = [pb availableTypeFromArray: ns_drag_types];
5806   if (type == 0)
5807     {
5808       return NO;
5809     }
5810   else if ([type isEqualToString: NSFilenamesPboardType])
5811     {
5812       NSArray *files;
5813       NSEnumerator *fenum;
5814       NSString *file;
5816       if (!(files = [pb propertyListForType: type]))
5817         return NO;
5819       fenum = [files objectEnumerator];
5820       while ( (file = [fenum nextObject]) )
5821         {
5822           emacs_event->kind = NS_NONKEY_EVENT;
5823           emacs_event->code = KEY_NS_DRAG_FILE;
5824           XSETINT (emacs_event->x, x);
5825           XSETINT (emacs_event->y, y);
5826           ns_input_file = append2 (ns_input_file,
5827                                    build_string ([file UTF8String]));
5828           emacs_event->modifiers = EV_MODIFIERS (theEvent);
5829           EV_TRAILER (theEvent);
5830         }
5831       return YES;
5832     }
5833   else if ([type isEqualToString: NSURLPboardType])
5834     {
5835       NSString *file;
5836       NSURL *fileURL;
5838       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
5839           [fileURL isFileURL] == NO)
5840         return NO;
5842       file = [fileURL path];
5843       emacs_event->kind = NS_NONKEY_EVENT;
5844       emacs_event->code = KEY_NS_DRAG_FILE;
5845       XSETINT (emacs_event->x, x);
5846       XSETINT (emacs_event->y, y);
5847       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
5848       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5849       EV_TRAILER (theEvent);
5850       return YES;
5851     }
5852   else if ([type isEqualToString: NSStringPboardType]
5853            || [type isEqualToString: NSTabularTextPboardType])
5854     {
5855       NSString *data;
5857       if (! (data = [pb stringForType: type]))
5858         return NO;
5860       emacs_event->kind = NS_NONKEY_EVENT;
5861       emacs_event->code = KEY_NS_DRAG_TEXT;
5862       XSETINT (emacs_event->x, x);
5863       XSETINT (emacs_event->y, y);
5864       ns_input_text = build_string ([data UTF8String]);
5865       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5866       EV_TRAILER (theEvent);
5867       return YES;
5868     }
5869   else if ([type isEqualToString: NSColorPboardType])
5870     {
5871       NSColor *c = [NSColor colorFromPasteboard: pb];
5872       emacs_event->kind = NS_NONKEY_EVENT;
5873       emacs_event->code = KEY_NS_DRAG_COLOR;
5874       XSETINT (emacs_event->x, x);
5875       XSETINT (emacs_event->y, y);
5876       ns_input_color = ns_color_to_lisp (c);
5877       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5878       EV_TRAILER (theEvent);
5879       return YES;
5880     }
5881   else if ([type isEqualToString: NSFontPboardType])
5882     {
5883       /* impl based on GNUstep NSTextView.m */
5884       NSData *data = [pb dataForType: NSFontPboardType];
5885       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
5886       NSFont *font = [dict objectForKey: NSFontAttributeName];
5887       char fontSize[10];
5889       if (font == nil)
5890         return NO;
5892       emacs_event->kind = NS_NONKEY_EVENT;
5893       emacs_event->code = KEY_NS_CHANGE_FONT;
5894       XSETINT (emacs_event->x, x);
5895       XSETINT (emacs_event->y, y);
5896       ns_input_font = build_string ([[font fontName] UTF8String]);
5897       snprintf (fontSize, 10, "%f", [font pointSize]);
5898       ns_input_fontsize = build_string (fontSize);
5899       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5900       EV_TRAILER (theEvent);
5901       return YES;
5902     }
5903   else
5904     {
5905       error ("Invalid data type in dragging pasteboard.");
5906       return NO;
5907     }
5911 - (id) validRequestorForSendType: (NSString *)typeSent
5912                       returnType: (NSString *)typeReturned
5914   NSTRACE (validRequestorForSendType);
5915   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
5916       && typeReturned == nil)
5917     {
5918       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
5919         return self;
5920     }
5922   return [super validRequestorForSendType: typeSent
5923                                returnType: typeReturned];
5927 /* The next two methods are part of NSServicesRequests informal protocol,
5928    supposedly called when a services menu item is chosen from this app.
5929    But this should not happen because we override the services menu with our
5930    own entries which call ns-perform-service.
5931    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
5932    So let's at least stub them out until further investigation can be done. */
5934 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
5936   /* we could call ns_string_from_pasteboard(pboard) here but then it should
5937      be written into the buffer in place of the existing selection..
5938      ordinary service calls go through functions defined in ns-win.el */
5939   return NO;
5942 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
5944   NSArray *typesDeclared;
5945   Lisp_Object val;
5947   /* We only support NSStringPboardType */
5948   if ([types containsObject:NSStringPboardType] == NO) {
5949     return NO;
5950   }
5952   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
5953   if (CONSP (val) && SYMBOLP (XCAR (val)))
5954     {
5955       val = XCDR (val);
5956       if (CONSP (val) && NILP (XCDR (val)))
5957         val = XCAR (val);
5958     }
5959   if (! STRINGP (val))
5960     return NO;
5962   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
5963   [pb declareTypes:typesDeclared owner:nil];
5964   ns_string_to_pasteboard (pb, val);
5965   return YES;
5969 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
5970    (gives a miniaturized version of the window); currently we use the latter for
5971    frames whose active buffer doesn't correspond to any file
5972    (e.g., '*scratch*') */
5973 - setMiniwindowImage: (BOOL) setMini
5975   id image = [[self window] miniwindowImage];
5976   NSTRACE (setMiniwindowImage);
5978   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
5979      about "AppleDockIconEnabled" notwithstanding, however the set message
5980      below has its effect nonetheless. */
5981   if (image != emacsframe->output_data.ns->miniimage)
5982     {
5983       if (image && [image isKindOfClass: [EmacsImage class]])
5984         [image release];
5985       [[self window] setMiniwindowImage:
5986                        setMini ? emacsframe->output_data.ns->miniimage : nil];
5987     }
5989   return self;
5993 - (void) setRows: (int) r andColumns: (int) c
5995   rows = r;
5996   cols = c;
5999 @end  /* EmacsView */
6003 /* ==========================================================================
6005     EmacsWindow implementation
6007    ========================================================================== */
6009 @implementation EmacsWindow
6011 /* If we have multiple monitors, one above the other, we don't want to
6012    restrict the height to just one monitor.  So we override this.  */
6013 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6015   /* When making the frame visible for the first time, we want to
6016      constrain.  Other times not.  */
6017   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6018   NSTRACE (constrainFrameRect);
6020   if (f->output_data.ns->dont_constrain
6021       || ns_menu_bar_should_be_hidden ())
6022     return frameRect;
6024   f->output_data.ns->dont_constrain = 1;
6025   return [super constrainFrameRect:frameRect toScreen:screen];
6029 /* called only on resize clicks by special case in EmacsApp-sendEvent */
6030 - (void)mouseDown: (NSEvent *)theEvent
6032   if (ns_in_resize)
6033     {
6034       NSSize size = [[theEvent window] frame].size;
6035       grabOffset = [theEvent locationInWindow];
6036       grabOffset.x = size.width - grabOffset.x;
6037     }
6038   else
6039     [super mouseDown: theEvent];
6043 /* stop resizing */
6044 - (void)mouseUp: (NSEvent *)theEvent
6046   if (ns_in_resize)
6047     {
6048       struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6049       ns_in_resize = NO;
6050       ns_set_name_as_filename (f);
6051       [self display];
6052       ns_send_appdefined (-1);
6053     }
6054   else
6055     [super mouseUp: theEvent];
6059 /* send resize events */
6060 - (void)mouseDragged: (NSEvent *)theEvent
6062   if (ns_in_resize)
6063     {
6064       NSPoint p = [theEvent locationInWindow];
6065       NSSize size, vettedSize, origSize = [self frame].size;
6067       size.width = p.x + grabOffset.x;
6068       size.height = origSize.height - p.y + grabOffset.y;
6070       if (size.width == origSize.width && size.height == origSize.height)
6071         return;
6073       vettedSize = [[self delegate] windowWillResize: self toSize: size];
6074       [[NSNotificationCenter defaultCenter]
6075             postNotificationName: NSWindowDidResizeNotification
6076                           object: self];
6077     }
6078   else
6079     [super mouseDragged: theEvent];
6082 @end /* EmacsWindow */
6085 /* ==========================================================================
6087     EmacsScroller implementation
6089    ========================================================================== */
6092 @implementation EmacsScroller
6094 /* for repeat button push */
6095 #define SCROLL_BAR_FIRST_DELAY 0.5
6096 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6098 + (CGFloat) scrollerWidth
6100   /* TODO: if we want to allow variable widths, this is the place to do it,
6101            however neither GNUstep nor Cocoa support it very well */
6102   return [NSScroller scrollerWidth];
6106 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6108   NSTRACE (EmacsScroller_initFrame);
6110   r.size.width = [EmacsScroller scrollerWidth];
6111   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6112   [self setContinuous: YES];
6113   [self setEnabled: YES];
6115   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6116      locked against the top and bottom edges, and right edge on OS X, where
6117      scrollers are on right. */
6118 #ifdef NS_IMPL_GNUSTEP
6119   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6120 #else
6121   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6122 #endif
6124   win = nwin;
6125   condemned = NO;
6126   pixel_height = NSHeight (r);
6127   if (pixel_height == 0) pixel_height = 1;
6128   min_portion = 20 / pixel_height;
6130   frame = XFRAME (XWINDOW (win)->frame);
6131   if (FRAME_LIVE_P (frame))
6132     {
6133       int i;
6134       EmacsView *view = FRAME_NS_VIEW (frame);
6135       NSView *sview = [[view window] contentView];
6136       NSArray *subs = [sview subviews];
6138       /* disable optimization stopping redraw of other scrollbars */
6139       view->scrollbarsNeedingUpdate = 0;
6140       for (i =[subs count]-1; i >= 0; i--)
6141         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6142           view->scrollbarsNeedingUpdate++;
6143       [sview addSubview: self];
6144     }
6146 /*  [self setFrame: r]; */
6148   return self;
6152 - (void)setFrame: (NSRect)newRect
6154   NSTRACE (EmacsScroller_setFrame);
6155 /*  BLOCK_INPUT; */
6156   pixel_height = NSHeight (newRect);
6157   if (pixel_height == 0) pixel_height = 1;
6158   min_portion = 20 / pixel_height;
6159   [super setFrame: newRect];
6160   [self display];
6161 /*  UNBLOCK_INPUT; */
6165 - (void)dealloc
6167   NSTRACE (EmacsScroller_dealloc);
6168   if (!NILP (win))
6169     XWINDOW (win)->vertical_scroll_bar = Qnil;
6170   [super dealloc];
6174 - condemn
6176   NSTRACE (condemn);
6177   condemned =YES;
6178   return self;
6182 - reprieve
6184   NSTRACE (reprieve);
6185   condemned =NO;
6186   return self;
6190 - judge
6192   NSTRACE (judge);
6193   if (condemned)
6194     {
6195       EmacsView *view;
6196       BLOCK_INPUT;
6197       /* ensure other scrollbar updates after deletion */
6198       view = (EmacsView *)FRAME_NS_VIEW (frame);
6199       if (view != nil)
6200         view->scrollbarsNeedingUpdate++;
6201       [self removeFromSuperview];
6202       [self release];
6203       UNBLOCK_INPUT;
6204     }
6205   return self;
6209 - (void)resetCursorRects
6211   NSRect visible = [self visibleRect];
6212   NSTRACE (resetCursorRects);
6214   if (!NSIsEmptyRect (visible))
6215     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6216   [[NSCursor arrowCursor] setOnMouseEntered: YES];
6220 - (int) checkSamePosition: (int) position portion: (int) portion
6221                     whole: (int) whole
6223   return em_position ==position && em_portion ==portion && em_whole ==whole
6224     && portion != whole; /* needed for resize empty buf */
6228 - setPosition: (int)position portion: (int)portion whole: (int)whole
6230   NSTRACE (setPosition);
6232   em_position = position;
6233   em_portion = portion;
6234   em_whole = whole;
6236   if (portion >= whole)
6237     {
6238 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6239       [self setKnobProportion: 1.0];
6240       [self setDoubleValue: 1.0];
6241 #else
6242       [self setFloatValue: 0.0 knobProportion: 1.0];
6243 #endif
6244     }
6245   else
6246     {
6247       float pos, por;
6248       portion = max ((float)whole*min_portion/pixel_height, portion);
6249       pos = (float)position / (whole - portion);
6250       por = (float)portion/whole;
6251 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6252       [self setKnobProportion: por];
6253       [self setDoubleValue: pos];
6254 #else
6255       [self setFloatValue: pos knobProportion: por];
6256 #endif
6257     }
6258   return self;
6261 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6262      drag events will go directly to the EmacsScroller.  Leaving in for now. */
6263 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6264                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
6266   *part = last_hit_part;
6267   *window = win;
6268   XSETINT (*y, pixel_height);
6269   if ([self floatValue] > 0.999)
6270     XSETINT (*x, pixel_height);
6271   else
6272     XSETINT (*x, pixel_height * [self floatValue]);
6276 /* set up emacs_event */
6277 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6279   if (!emacs_event)
6280     return;
6282   emacs_event->part = last_hit_part;
6283   emacs_event->code = 0;
6284   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
6285   emacs_event->frame_or_window = win;
6286   emacs_event->timestamp = EV_TIMESTAMP (e);
6287   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
6288   emacs_event->arg = Qnil;
6289   XSETINT (emacs_event->x, loc * pixel_height);
6290   XSETINT (emacs_event->y, pixel_height-20);
6292   n_emacs_events_pending++;
6293   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
6294   EVENT_INIT (*emacs_event);
6295   ns_send_appdefined (-1);
6299 /* called manually thru timer to implement repeated button action w/hold-down */
6300 - repeatScroll: (NSTimer *)scrollEntry
6302   NSEvent *e = [[self window] currentEvent];
6303   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
6304   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
6306   /* clear timer if need be */
6307   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
6308     {
6309         [scroll_repeat_entry invalidate];
6310         [scroll_repeat_entry release];
6311         scroll_repeat_entry = nil;
6313         if (inKnob)
6314           return self;
6316         scroll_repeat_entry
6317           = [[NSTimer scheduledTimerWithTimeInterval:
6318                         SCROLL_BAR_CONTINUOUS_DELAY
6319                                             target: self
6320                                           selector: @selector (repeatScroll:)
6321                                           userInfo: 0
6322                                            repeats: YES]
6323               retain];
6324     }
6326   [self sendScrollEventAtLoc: 0 fromEvent: e];
6327   return self;
6331 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
6332    mouseDragged events without going into a modal loop. */
6333 - (void)mouseDown: (NSEvent *)e
6335   NSRect sr, kr;
6336   /* hitPart is only updated AFTER event is passed on */
6337   NSScrollerPart part = [self testPart: [e locationInWindow]];
6338   double inc = 0.0, loc, kloc, pos;
6339   int edge = 0;
6341   NSTRACE (EmacsScroller_mouseDown);
6343   switch (part)
6344     {
6345     case NSScrollerDecrementPage:
6346         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
6347     case NSScrollerIncrementPage:
6348         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
6349     case NSScrollerDecrementLine:
6350       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
6351     case NSScrollerIncrementLine:
6352       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
6353     case NSScrollerKnob:
6354       last_hit_part = scroll_bar_handle; break;
6355     case NSScrollerKnobSlot:  /* GNUstep-only */
6356       last_hit_part = scroll_bar_move_ratio; break;
6357     default:  /* NSScrollerNoPart? */
6358       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
6359                (long) part);
6360       return;
6361     }
6363   if (inc != 0.0)
6364     {
6365       pos = 0;      /* ignored */
6367       /* set a timer to repeat, as we can't let superclass do this modally */
6368       scroll_repeat_entry
6369         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
6370                                             target: self
6371                                           selector: @selector (repeatScroll:)
6372                                           userInfo: 0
6373                                            repeats: YES]
6374             retain];
6375     }
6376   else
6377     {
6378       /* handle, or on GNUstep possibly slot */
6379       NSEvent *fake_event;
6381       /* compute float loc in slot and mouse offset on knob */
6382       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6383                       toView: nil];
6384       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6385       if (loc <= 0.0)
6386         {
6387           loc = 0.0;
6388           edge = -1;
6389         }
6390       else if (loc >= NSHeight (sr))
6391         {
6392           loc = NSHeight (sr);
6393           edge = 1;
6394         }
6396       if (edge)
6397         kloc = 0.5 * edge;
6398       else
6399         {
6400           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
6401                           toView: nil];
6402           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
6403         }
6404       last_mouse_offset = kloc;
6406       /* if knob, tell emacs a location offset by knob pos
6407          (to indicate top of handle) */
6408       if (part == NSScrollerKnob)
6409           pos = (loc - last_mouse_offset) / NSHeight (sr);
6410       else
6411         /* else this is a slot click on GNUstep: go straight there */
6412         pos = loc / NSHeight (sr);
6414       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
6415       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
6416                                       location: [e locationInWindow]
6417                                  modifierFlags: [e modifierFlags]
6418                                      timestamp: [e timestamp]
6419                                   windowNumber: [e windowNumber]
6420                                        context: [e context]
6421                                    eventNumber: [e eventNumber]
6422                                     clickCount: [e clickCount]
6423                                       pressure: [e pressure]];
6424       [super mouseUp: fake_event];
6425     }
6427   if (part != NSScrollerKnob)
6428     [self sendScrollEventAtLoc: pos fromEvent: e];
6432 /* Called as we manually track scroller drags, rather than superclass. */
6433 - (void)mouseDragged: (NSEvent *)e
6435     NSRect sr;
6436     double loc, pos;
6437     int edge = 0;
6439     NSTRACE (EmacsScroller_mouseDragged);
6441       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6442                       toView: nil];
6443       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6445       if (loc <= 0.0)
6446         {
6447           loc = 0.0;
6448           edge = -1;
6449         }
6450       else if (loc >= NSHeight (sr) + last_mouse_offset)
6451         {
6452           loc = NSHeight (sr) + last_mouse_offset;
6453           edge = 1;
6454         }
6456       pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
6457       [self sendScrollEventAtLoc: pos fromEvent: e];
6461 - (void)mouseUp: (NSEvent *)e
6463   if (scroll_repeat_entry)
6464     {
6465       [scroll_repeat_entry invalidate];
6466       [scroll_repeat_entry release];
6467       scroll_repeat_entry = nil;
6468     }
6469   last_hit_part = 0;
6473 /* treat scrollwheel events in the bar as though they were in the main window */
6474 - (void) scrollWheel: (NSEvent *)theEvent
6476   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
6477   [view mouseDown: theEvent];
6480 @end  /* EmacsScroller */
6485 /* ==========================================================================
6487    Font-related functions; these used to be in nsfaces.m
6489    ========================================================================== */
6492 Lisp_Object
6493 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
6495   struct font *font = XFONT_OBJECT (font_object);
6497   if (fontset < 0)
6498     fontset = fontset_from_font (font_object);
6499   FRAME_FONTSET (f) = fontset;
6501   if (FRAME_FONT (f) == font)
6502     /* This font is already set in frame F.  There's nothing more to
6503        do.  */
6504     return font_object;
6506   FRAME_FONT (f) = font;
6508   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
6509   FRAME_COLUMN_WIDTH (f) = font->average_width;
6510   FRAME_SPACE_WIDTH (f) = font->space_width;
6511   FRAME_LINE_HEIGHT (f) = font->height;
6513   compute_fringe_widths (f, 1);
6515   /* Compute the scroll bar width in character columns.  */
6516   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6517     {
6518       int wid = FRAME_COLUMN_WIDTH (f);
6519       FRAME_CONFIG_SCROLL_BAR_COLS (f)
6520         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
6521     }
6522   else
6523     {
6524       int wid = FRAME_COLUMN_WIDTH (f);
6525       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6526     }
6528   /* Now make the frame display the given font.  */
6529   if (FRAME_NS_WINDOW (f) != 0)
6530         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6532   return font_object;
6536 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
6537 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
6538          in 1.43. */
6540 const char *
6541 ns_xlfd_to_fontname (const char *xlfd)
6542 /* --------------------------------------------------------------------------
6543     Convert an X font name (XLFD) to an NS font name.
6544     Only family is used.
6545     The string returned is temporarily allocated.
6546    -------------------------------------------------------------------------- */
6548   char *name = xmalloc (180);
6549   int i, len;
6550   const char *ret;
6552   if (!strncmp (xlfd, "--", 2))
6553     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
6554   else
6555     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
6557   /* stopgap for malformed XLFD input */
6558   if (strlen (name) == 0)
6559     strcpy (name, "Monaco");
6561   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
6562      also uppercase after '-' or ' ' */
6563   name[0] = toupper (name[0]);
6564   for (len =strlen (name), i =0; i<len; i++)
6565     {
6566       if (name[i] == '$')
6567         {
6568           name[i] = '-';
6569           if (i+1<len)
6570             name[i+1] = toupper (name[i+1]);
6571         }
6572       else if (name[i] == '_')
6573         {
6574           name[i] = ' ';
6575           if (i+1<len)
6576             name[i+1] = toupper (name[i+1]);
6577         }
6578     }
6579 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
6580   ret = [[NSString stringWithUTF8String: name] UTF8String];
6581   xfree (name);
6582   return ret;
6586 void
6587 syms_of_nsterm (void)
6589   NSTRACE (syms_of_nsterm);
6591   ns_antialias_threshold = 10.0;
6593   /* from 23+ we need to tell emacs what modifiers there are.. */
6594   DEFSYM (Qmodifier_value, "modifier-value");
6595   DEFSYM (Qalt, "alt");
6596   DEFSYM (Qhyper, "hyper");
6597   DEFSYM (Qmeta, "meta");
6598   DEFSYM (Qsuper, "super");
6599   DEFSYM (Qcontrol, "control");
6600   DEFSYM (Qnone, "none");
6601   DEFSYM (QUTF8_STRING, "UTF8_STRING");
6603   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
6604   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
6605   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
6606   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
6607   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
6609   DEFVAR_LISP ("ns-input-file", ns_input_file,
6610               "The file specified in the last NS event.");
6611   ns_input_file =Qnil;
6613   DEFVAR_LISP ("ns-input-text", ns_input_text,
6614               "The data received in the last NS text drag event.");
6615   ns_input_text =Qnil;
6617   DEFVAR_LISP ("ns-working-text", ns_working_text,
6618               "String for visualizing working composition sequence.");
6619   ns_working_text =Qnil;
6621   DEFVAR_LISP ("ns-input-font", ns_input_font,
6622               "The font specified in the last NS event.");
6623   ns_input_font =Qnil;
6625   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
6626               "The fontsize specified in the last NS event.");
6627   ns_input_fontsize =Qnil;
6629   DEFVAR_LISP ("ns-input-line", ns_input_line,
6630                "The line specified in the last NS event.");
6631   ns_input_line =Qnil;
6633   DEFVAR_LISP ("ns-input-color", ns_input_color,
6634                "The color specified in the last NS event.");
6635   ns_input_color =Qnil;
6637   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
6638                "The service name specified in the last NS event.");
6639   ns_input_spi_name =Qnil;
6641   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
6642                "The service argument specified in the last NS event.");
6643   ns_input_spi_arg =Qnil;
6645   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
6646                "This variable describes the behavior of the alternate or option key.\n\
6647 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6648 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6649 at all, allowing it to be used at a lower level for accented character entry.");
6650   ns_alternate_modifier = Qmeta;
6652   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
6653                "This variable describes the behavior of the right alternate or option key.\n\
6654 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6655 Set to left means be the same key as `ns-alternate-modifier'.\n\
6656 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6657 at all, allowing it to be used at a lower level for accented character entry.");
6658   ns_right_alternate_modifier = Qleft;
6660   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
6661                "This variable describes the behavior of the command key.\n\
6662 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6663   ns_command_modifier = Qsuper;
6665   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
6666                "This variable describes the behavior of the right command key.\n\
6667 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6668 Set to left means be the same key as `ns-command-modifier'.\n\
6669 Set to none means that the command / option key is not interpreted by Emacs\n\
6670 at all, allowing it to be used at a lower level for accented character entry.");
6671   ns_right_command_modifier = Qleft;
6673   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
6674                "This variable describes the behavior of the control key.\n\
6675 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6676   ns_control_modifier = Qcontrol;
6678   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
6679                "This variable describes the behavior of the right control key.\n\
6680 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6681 Set to left means be the same key as `ns-control-modifier'.\n\
6682 Set to none means that the control / option key is not interpreted by Emacs\n\
6683 at all, allowing it to be used at a lower level for accented character entry.");
6684   ns_right_control_modifier = Qleft;
6686   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
6687                "This variable describes the behavior of the function key (on laptops).\n\
6688 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6689 Set to none means that the function key is not interpreted by Emacs at all,\n\
6690 allowing it to be used at a lower level for accented character entry.");
6691   ns_function_modifier = Qnone;
6693   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
6694                "Non-nil (the default) means to render text antialiased. Only has an effect on OS X Panther and above.");
6695   ns_antialias_text = Qt;
6697   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
6698                "Whether to confirm application quit using dialog.");
6699   ns_confirm_quit = Qnil;
6701   staticpro (&ns_display_name_list);
6702   ns_display_name_list = Qnil;
6704   staticpro (&last_mouse_motion_frame);
6705   last_mouse_motion_frame = Qnil;
6707   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
6708                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
6709 Only works on OSX 10.6 or later.  */);
6710   ns_auto_hide_menu_bar = Qnil;
6712   /* TODO: move to common code */
6713   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
6714                doc: /* If not nil, Emacs uses toolkit scroll bars.  */);
6715 #ifdef USE_TOOLKIT_SCROLL_BARS
6716   Vx_toolkit_scroll_bars = Qt;
6717 #else
6718   Vx_toolkit_scroll_bars = Qnil;
6719 #endif
6721   DEFVAR_BOOL ("x-use-underline-position-properties",
6722                x_use_underline_position_properties,
6723      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
6724 A value of nil means ignore them.  If you encounter fonts with bogus
6725 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
6726 to 4.1, set this to nil. */);
6727   x_use_underline_position_properties = 0;
6729   DEFVAR_BOOL ("x-underline-at-descent-line",
6730                x_underline_at_descent_line,
6731      doc: /* Non-nil means to draw the underline at the same place as the descent line.
6732 A value of nil means to draw the underline according to the value of the
6733 variable `x-use-underline-position-properties', which is usually at the
6734 baseline level.  The default value is nil.  */);
6735   x_underline_at_descent_line = 0;
6737   /* Tell emacs about this window system. */
6738   Fprovide (intern ("ns"), Qnil);