Spelling fixes.
[emacs.git] / src / nsterm.m
blob7d26cba6d73a25a661b11ed42b4467432bdb3930
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];
1126 /* Free X resources of frame F.  */
1128 void
1129 x_free_frame_resources (struct frame *f)
1131   NSView *view = FRAME_NS_VIEW (f);
1132   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1133   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1134   NSTRACE (x_destroy_window);
1135   check_ns ();
1137   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1139   BLOCK_INPUT;
1141   free_frame_menubar (f);
1143   if (FRAME_FACE_CACHE (f))
1144     free_frame_faces (f);
1146   if (f == dpyinfo->x_focus_frame)
1147     dpyinfo->x_focus_frame = 0;
1148   if (f == dpyinfo->x_highlight_frame)
1149     dpyinfo->x_highlight_frame = 0;
1150   if (f == hlinfo->mouse_face_mouse_frame)
1151     {
1152       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
1153       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
1154       hlinfo->mouse_face_window = Qnil;
1155       hlinfo->mouse_face_deferred_gc = 0;
1156       hlinfo->mouse_face_mouse_frame = 0;
1157     }
1159   xfree (f->output_data.ns);
1161   [[view window] close];
1162   [view release];
1164   UNBLOCK_INPUT;
1167 void
1168 x_destroy_window (struct frame *f)
1169 /* --------------------------------------------------------------------------
1170      External: Delete the window
1171    -------------------------------------------------------------------------- */
1173   NSTRACE (x_destroy_window);
1174   check_ns ();
1175   x_free_frame_resources (f);
1176   ns_window_num--;
1180 void
1181 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1182 /* --------------------------------------------------------------------------
1183      External: Position the window
1184    -------------------------------------------------------------------------- */
1186   NSView *view = FRAME_NS_VIEW (f);
1187   NSArray *screens = [NSScreen screens];
1188   NSScreen *fscreen = [screens objectAtIndex: 0];
1189   NSScreen *screen = [[view window] screen];
1191   NSTRACE (x_set_offset);
1193   BLOCK_INPUT;
1195   f->left_pos = xoff;
1196   f->top_pos = yoff;
1198   if (view != nil && screen && fscreen)
1199     {
1200       f->left_pos = f->size_hint_flags & XNegative
1201         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1202         : f->left_pos;
1203       /* We use visibleFrame here to take menu bar into account.
1204          Ideally we should also adjust left/top with visibleFrame.origin.  */
1206       f->top_pos = f->size_hint_flags & YNegative
1207         ? ([screen visibleFrame].size.height + f->top_pos
1208            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1209            - FRAME_TOOLBAR_HEIGHT (f))
1210         : f->top_pos;
1211 #ifdef NS_IMPL_GNUSTEP
1212       if (f->left_pos < 100)
1213         f->left_pos = 100;  /* don't overlap menu */
1214 #endif
1215       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1216          menu bar.  */
1217       f->output_data.ns->dont_constrain = 0;
1218       [[view window] setFrameTopLeftPoint:
1219                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1220                                     SCREENMAXBOUND ([fscreen frame].size.height
1221                                                     - NS_TOP_POS (f)))];
1222       f->size_hint_flags &= ~(XNegative|YNegative);
1223     }
1225   UNBLOCK_INPUT;
1229 void
1230 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1231 /* --------------------------------------------------------------------------
1232      Adjust window pixel size based on given character grid size
1233      Impl is a bit more complex than other terms, need to do some
1234      internal clipping.
1235    -------------------------------------------------------------------------- */
1237   EmacsView *view = FRAME_NS_VIEW (f);
1238   EmacsToolbar *toolbar = [view toolbar];
1239   NSWindow *window = [view window];
1240   NSRect wr = [window frame];
1241   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1242   int pixelwidth, pixelheight;
1243   static int oldRows, oldCols, oldFontWidth, oldFontHeight;
1244   static int oldTB;
1245   static struct frame *oldF;
1247   NSTRACE (x_set_window_size);
1249   if (view == nil ||
1250       (f == oldF
1251        && rows == oldRows && cols == oldCols
1252        && oldFontWidth == FRAME_COLUMN_WIDTH (f)
1253        && oldFontHeight == FRAME_LINE_HEIGHT (f)
1254        && oldTB == tb))
1255     return;
1257 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1259   BLOCK_INPUT;
1261   check_frame_size (f, &rows, &cols);
1262   oldF = f;
1263   oldRows = rows;
1264   oldCols = cols;
1265   oldFontWidth = FRAME_COLUMN_WIDTH (f);
1266   oldFontHeight = FRAME_LINE_HEIGHT (f);
1267   oldTB = tb;
1269   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1270   compute_fringe_widths (f, 0);
1272   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1273   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1275   /* If we have a toolbar, take its height into account. */
1276   if (tb)
1277     /* NOTE: previously this would generate wrong result if toolbar not
1278              yet displayed and fixing toolbar_height=32 helped, but
1279              now (200903) seems no longer needed */
1280     FRAME_TOOLBAR_HEIGHT (f) =
1281       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1282         - FRAME_NS_TITLEBAR_HEIGHT (f);
1283   else
1284     FRAME_TOOLBAR_HEIGHT (f) = 0;
1286   wr.size.width = pixelwidth + f->border_width;
1287   wr.size.height = pixelheight + FRAME_NS_TITLEBAR_HEIGHT (f)
1288                   + FRAME_TOOLBAR_HEIGHT (f);
1290   /* Do not try to constrain to this screen.  We may have multiple
1291      screens, and want Emacs to span those.  Constraining to screen
1292      prevents that, and that is not nice to the user.  */
1293  if (f->output_data.ns->zooming)
1294    f->output_data.ns->zooming = 0;
1295  else
1296    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1298   [view setRows: rows andColumns: cols];
1299   [window setFrame: wr display: YES];
1301 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1303   /* This is a trick to compensate for Emacs' managing the scrollbar area
1304      as a fixed number of standard character columns.  Instead of leaving
1305      blank space for the extra, we chopped it off above.  Now for
1306      left-hand scrollbars, we shift all rendering to the left by the
1307      difference between the real width and Emacs' imagined one.  For
1308      right-hand bars, don't worry about it since the extra is never used.
1309      (Obviously doesn't work for vertically split windows tho..) */
1310   {
1311     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1312       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1313                      - NS_SCROLL_BAR_WIDTH (f), 0)
1314       : NSMakePoint (0, 0);
1315     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1316     [view setBoundsOrigin: origin];
1317   }
1319   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1320   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1321   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1322 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1324   mark_window_cursors_off (XWINDOW (f->root_window));
1325   cancel_mouse_face (f);
1327   UNBLOCK_INPUT;
1332 /* ==========================================================================
1334     Color management
1336    ========================================================================== */
1339 NSColor *
1340 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1342   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1343   if (idx < 1 || idx >= color_table->avail)
1344     return nil;
1345   return color_table->colors[idx];
1349 unsigned long
1350 ns_index_color (NSColor *color, struct frame *f)
1352   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1353   ptrdiff_t idx;
1354   NSNumber *index;
1356   if (!color_table->colors)
1357     {
1358       color_table->size = NS_COLOR_CAPACITY;
1359       color_table->avail = 1; /* skip idx=0 as marker */
1360       color_table->colors
1361         = (NSColor **)xmalloc (color_table->size * sizeof (NSColor *));
1362       color_table->colors[0] = nil;
1363       color_table->empty_indices = [[NSMutableSet alloc] init];
1364     }
1366   /* do we already have this color ? */
1367   {
1368     ptrdiff_t i;
1369     for (i = 1; i < color_table->avail; i++)
1370       {
1371         if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1372           {
1373             [color_table->colors[i] retain];
1374             return i;
1375           }
1376       }
1377   }
1379   if ([color_table->empty_indices count] > 0)
1380     {
1381       index = [color_table->empty_indices anyObject];
1382       [color_table->empty_indices removeObject: index];
1383       idx = [index unsignedLongValue];
1384     }
1385   else
1386     {
1387       if (color_table->avail == color_table->size)
1388         color_table->colors =
1389           xpalloc (color_table->colors, &color_table->size, 1,
1390                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1391       idx = color_table->avail++;
1392     }
1394   color_table->colors[idx] = color;
1395   [color retain];
1396 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1397   return idx;
1401 void
1402 ns_free_indexed_color (unsigned long idx, struct frame *f)
1404   struct ns_color_table *color_table;
1405   NSColor *color;
1406   NSNumber *index;
1408   if (!f)
1409     return;
1411   color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1413   if (idx <= 0 || idx >= color_table->size) {
1414     message1("ns_free_indexed_color: Color index out of range.\n");
1415     return;
1416   }
1418   index = [NSNumber numberWithUnsignedInt: idx];
1419   if ([color_table->empty_indices containsObject: index]) {
1420     message1("ns_free_indexed_color: attempt to free already freed color.\n");
1421     return;
1422   }
1424   color = color_table->colors[idx];
1425   [color release];
1426   color_table->colors[idx] = nil;
1427   [color_table->empty_indices addObject: [NSNumber numberWithUnsignedInt: idx]];
1428 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1432 static int
1433 ns_get_color (const char *name, NSColor **col)
1434 /* --------------------------------------------------------------------------
1435      Parse a color name
1436    -------------------------------------------------------------------------- */
1437 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1438    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1439    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1441   NSColor *new = nil;
1442   static char hex[20];
1443   int scaling;
1444   float r = -1.0, g, b;
1445   NSString *nsname = [NSString stringWithUTF8String: name];
1447 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1448   BLOCK_INPUT;
1450   if ([nsname isEqualToString: @"ns_selection_color"])
1451     {
1452       nsname = ns_selection_color;
1453       name = [ns_selection_color UTF8String];
1454     }
1456   /* First, check for some sort of numeric specification. */
1457   hex[0] = '\0';
1459   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1460     {
1461       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1462       [scanner scanFloat: &r];
1463       [scanner scanFloat: &g];
1464       [scanner scanFloat: &b];
1465     }
1466   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1467     {
1468       strncpy (hex, name + 4, 19);
1469       hex[19] = '\0';
1470       scaling = (strlen(hex) - 2) / 3;
1471     }
1472   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1473     {
1474       int len = (strlen(name) - 1);
1475       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1476       int i;
1477       scaling = strlen(name+start) / 3;
1478       for (i=0; i<3; i++) {
1479         strncpy(hex + i * (scaling + 1), name + start + i * scaling, scaling);
1480         hex[(i+1) * (scaling + 1) - 1] = '/';
1481       }
1482       hex[3 * (scaling + 1) - 1] = '\0';
1483     }
1485   if (hex[0])
1486     {
1487       int rr, gg, bb;
1488       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1489       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1490         {
1491           r = rr / fscale;
1492           g = gg / fscale;
1493           b = bb / fscale;
1494         }
1495     }
1497   if (r >= 0.0)
1498     {
1499       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1500       UNBLOCK_INPUT;
1501       return 0;
1502     }
1504   /* Otherwise, color is expected to be from a list */
1505   {
1506     NSEnumerator *lenum, *cenum;
1507     NSString *name;
1508     NSColorList *clist;
1510 #ifdef NS_IMPL_GNUSTEP
1511     /* XXX: who is wrong, the requestor or the implementation? */
1512     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1513         == NSOrderedSame)
1514       nsname = @"highlightColor";
1515 #endif
1517     lenum = [[NSColorList availableColorLists] objectEnumerator];
1518     while ( (clist = [lenum nextObject]) && new == nil)
1519       {
1520         cenum = [[clist allKeys] objectEnumerator];
1521         while ( (name = [cenum nextObject]) && new == nil )
1522           {
1523             if ([name compare: nsname
1524                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1525               new = [clist colorWithKey: name];
1526           }
1527       }
1528   }
1530   if (new)
1531     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1532   UNBLOCK_INPUT;
1533   return new ? 0 : 1;
1537 static NSColor *
1538 ns_get_color_default (const char *name, NSColor *dflt)
1539 /* --------------------------------------------------------------------------
1540      Parse a color or use a default value
1541    -------------------------------------------------------------------------- */
1543   NSColor * col;
1545   if (ns_get_color (name, &col))
1546     return dflt;
1547   else
1548     return col;
1553 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1554 /* --------------------------------------------------------------------------
1555      Convert a Lisp string object to a NS color
1556    -------------------------------------------------------------------------- */
1558   NSTRACE (ns_lisp_to_color);
1559   if (STRINGP (color))
1560     return ns_get_color (SDATA (color), col);
1561   else if (SYMBOLP (color))
1562     return ns_get_color (SDATA (SYMBOL_NAME (color)), col);
1563   return 1;
1567 Lisp_Object
1568 ns_color_to_lisp (NSColor *col)
1569 /* --------------------------------------------------------------------------
1570      Convert a color to a lisp string with the RGB equivalent
1571    -------------------------------------------------------------------------- */
1573   CGFloat red, green, blue, alpha, gray;
1574   char buf[1024];
1575   const char *str;
1576   NSTRACE (ns_color_to_lisp);
1578   BLOCK_INPUT;
1579   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1581       if ((str =[[col colorNameComponent] UTF8String]))
1582         {
1583           UNBLOCK_INPUT;
1584           return build_string ((char *)str);
1585         }
1587     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1588         getRed: &red green: &green blue: &blue alpha: &alpha];
1589   if (red ==green && red ==blue)
1590     {
1591       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1592             getWhite: &gray alpha: &alpha];
1593       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1594                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1595       UNBLOCK_INPUT;
1596       return build_string (buf);
1597     }
1599   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1600             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1602   UNBLOCK_INPUT;
1603   return build_string (buf);
1607 void
1608 ns_query_color(void *col, XColor *color_def, int setPixel)
1609 /* --------------------------------------------------------------------------
1610          Get ARGB values out of NSColor col and put them into color_def.
1611          If setPixel, set the pixel to a concatenated version.
1612          and set color_def pixel to the resulting index.
1613    -------------------------------------------------------------------------- */
1615   CGFloat r, g, b, a;
1617   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1618   color_def->red   = r * 65535;
1619   color_def->green = g * 65535;
1620   color_def->blue  = b * 65535;
1622   if (setPixel == YES)
1623     color_def->pixel
1624       = ARGB_TO_ULONG((int)(a*255),
1625                       (int)(r*255), (int)(g*255), (int)(b*255));
1630 ns_defined_color (struct frame *f,
1631                   const char *name,
1632                   XColor *color_def,
1633                   int alloc,
1634                   char makeIndex)
1635 /* --------------------------------------------------------------------------
1636          Return 1 if named color found, and set color_def rgb accordingly.
1637          If makeIndex and alloc are nonzero put the color in the color_table,
1638          and set color_def pixel to the resulting index.
1639          If makeIndex is zero, set color_def pixel to ARGB.
1640          Return 0 if not found
1641    -------------------------------------------------------------------------- */
1643   NSColor *col;
1644   NSTRACE (ns_defined_color);
1646   BLOCK_INPUT;
1647   if (ns_get_color (name, &col) != 0) /* Color not found  */
1648     {
1649       UNBLOCK_INPUT;
1650       return 0;
1651     }
1652   if (makeIndex && alloc)
1653     color_def->pixel = ns_index_color (col, f);
1654   ns_query_color (col, color_def, !makeIndex);
1655   UNBLOCK_INPUT;
1656   return 1;
1660 unsigned long
1661 ns_get_rgb_color (struct frame *f, float r, float g, float b, float a)
1662 /* --------------------------------------------------------------------------
1663     return an autoreleased RGB color
1664    -------------------------------------------------------------------------- */
1666 /*static int c = 1; fprintf (stderr, "color request %d\n", c++); */
1667   if (r < 0.0) r = 0.0;
1668   else if (r > 1.0) r = 1.0;
1669   if (g < 0.0) g = 0.0;
1670   else if (g > 1.0) g = 1.0;
1671   if (b < 0.0) b = 0.0;
1672   else if (b > 1.0) b = 1.0;
1673   if (a < 0.0) a = 0.0;
1674   else if (a > 1.0) a = 1.0;
1675   return (unsigned long) ns_index_color(
1676     [NSColor colorWithCalibratedRed: r green: g blue: b alpha: a], f);
1680 void
1681 x_set_frame_alpha (struct frame *f)
1682 /* --------------------------------------------------------------------------
1683      change the entire-frame transparency
1684    -------------------------------------------------------------------------- */
1686   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1687   EmacsView *view = FRAME_NS_VIEW (f);
1688   double alpha = 1.0;
1689   double alpha_min = 1.0;
1691   if (dpyinfo->x_highlight_frame == f)
1692     alpha = f->alpha[0];
1693   else
1694     alpha = f->alpha[1];
1696   if (FLOATP (Vframe_alpha_lower_limit))
1697     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1698   else if (INTEGERP (Vframe_alpha_lower_limit))
1699     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1701   if (alpha < 0.0)
1702     return;
1703   else if (1.0 < alpha)
1704     alpha = 1.0;
1705   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1706     alpha = alpha_min;
1708 #ifdef NS_IMPL_COCOA
1709   [[view window] setAlphaValue: alpha];
1710 #endif
1714 /* ==========================================================================
1716     Mouse handling
1718    ========================================================================== */
1721 void
1722 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1723 /* --------------------------------------------------------------------------
1724      Programmatically reposition mouse pointer in pixel coordinates
1725    -------------------------------------------------------------------------- */
1727   NSTRACE (x_set_mouse_pixel_position);
1728   ns_raise_frame (f);
1729 #if 0
1730   /* FIXME: this does not work, and what about GNUstep? */
1731 #ifdef NS_IMPL_COCOA
1732   [FRAME_NS_VIEW (f) lockFocus];
1733   PSsetmouse ((float)pix_x, (float)pix_y);
1734   [FRAME_NS_VIEW (f) unlockFocus];
1735 #endif
1736 #endif
1740 void
1741 x_set_mouse_position (struct frame *f, int h, int v)
1742 /* --------------------------------------------------------------------------
1743      Programmatically reposition mouse pointer in character coordinates
1744    -------------------------------------------------------------------------- */
1746   int pix_x, pix_y;
1748   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1749   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1751   if (pix_x < 0) pix_x = 0;
1752   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1754   if (pix_y < 0) pix_y = 0;
1755   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1757   x_set_mouse_pixel_position (f, pix_x, pix_y);
1761 static int
1762 note_mouse_movement (struct frame *frame, float x, float y)
1763 /*   ------------------------------------------------------------------------
1764      Called by EmacsView on mouseMovement events.  Passes on
1765      to emacs mainstream code if we moved off of a rect of interest
1766      known as last_mouse_glyph.
1767      ------------------------------------------------------------------------ */
1769 //  NSTRACE (note_mouse_movement);
1771   XSETFRAME (last_mouse_motion_frame, frame);
1773   /* Note, this doesn't get called for enter/leave, since we don't have a
1774      position.  Those are taken care of in the corresponding NSView methods. */
1776   /* has movement gone beyond last rect we were tracking? */
1777   if (x < last_mouse_glyph.origin.x ||
1778       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1779       y < last_mouse_glyph.origin.y ||
1780       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1781     {
1782       ns_update_begin(frame);
1783       frame->mouse_moved = 1;
1784       note_mouse_highlight (frame, x, y);
1785       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1786       ns_update_end(frame);
1787       return 1;
1788     }
1790   return 0;
1794 static void
1795 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1796                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1797                    Time *time)
1798 /* --------------------------------------------------------------------------
1799     External (hook): inform emacs about mouse position and hit parts.
1800     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1801     x & y should be position in the scrollbar (the whole bar, not the handle)
1802     and length of scrollbar respectively
1803    -------------------------------------------------------------------------- */
1805   id view;
1806   NSPoint position;
1807   int xchar, ychar;
1808   Lisp_Object frame, tail;
1809   struct frame *f;
1810   struct ns_display_info *dpyinfo;
1812   NSTRACE (ns_mouse_position);
1814   if (*fp == NULL)
1815     {
1816       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1817       return;
1818     }
1820   dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1822   BLOCK_INPUT;
1824   if (last_mouse_scroll_bar != nil && insist == 0)
1825     {
1826       /* TODO: we do not use this path at the moment because drag events will
1827            go directly to the EmacsScroller.  Leaving code in for now. */
1828       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1829                                               x: x y: y];
1830       if (time) *time = last_mouse_movement_time;
1831       last_mouse_scroll_bar = nil;
1832     }
1833   else
1834     {
1835       /* Clear the mouse-moved flag for every frame on this display.  */
1836       FOR_EACH_FRAME (tail, frame)
1837         if (FRAME_NS_P (XFRAME (frame))
1838             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1839           XFRAME (frame)->mouse_moved = 0;
1841       last_mouse_scroll_bar = nil;
1842       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1843         f = last_mouse_frame;
1844       else
1845         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1846                                     : SELECTED_FRAME ();
1848       if (f && f->output_data.ns)  /* TODO: 2nd check no longer needed? */
1849         {
1850           view = FRAME_NS_VIEW (*fp);
1852           position = [[view window] mouseLocationOutsideOfEventStream];
1853           position = [view convertPoint: position fromView: nil];
1854           remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1855 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1857           if (bar_window) *bar_window = Qnil;
1858           if (part) *part = 0; /*scroll_bar_handle; */
1860           if (x) XSETINT (*x, lrint (position.x));
1861           if (y) XSETINT (*y, lrint (position.y));
1862           if (time) *time = last_mouse_movement_time;
1863           *fp = f;
1864         }
1865     }
1867   UNBLOCK_INPUT;
1871 static void
1872 ns_frame_up_to_date (struct frame *f)
1873 /* --------------------------------------------------------------------------
1874     External (hook): Fix up mouse highlighting right after a full update.
1875     Some highlighting was deferred if GC was happening during
1876     note_mouse_highlight (), while other highlighting was deferred for update.
1877    -------------------------------------------------------------------------- */
1879   NSTRACE (ns_frame_up_to_date);
1881   if (FRAME_NS_P (f))
1882     {
1883       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1884       if ((hlinfo->mouse_face_deferred_gc || f ==hlinfo->mouse_face_mouse_frame)
1885       /*&& hlinfo->mouse_face_mouse_frame*/)
1886         {
1887           BLOCK_INPUT;
1888           ns_update_begin(f);
1889           if (hlinfo->mouse_face_mouse_frame)
1890             note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1891                                   hlinfo->mouse_face_mouse_x,
1892                                   hlinfo->mouse_face_mouse_y);
1893           hlinfo->mouse_face_deferred_gc = 0;
1894           ns_update_end(f);
1895           UNBLOCK_INPUT;
1896         }
1897     }
1901 void
1902 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1903 /* --------------------------------------------------------------------------
1904     External (RIF): set frame mouse pointer type.
1905    -------------------------------------------------------------------------- */
1907   NSTRACE (ns_define_frame_cursor);
1908   if (FRAME_POINTER_TYPE (f) != cursor)
1909     {
1910       EmacsView *view = FRAME_NS_VIEW (f);
1911       FRAME_POINTER_TYPE (f) = cursor;
1912       [[view window] invalidateCursorRectsForView: view];
1913       /* Redisplay assumes this function also draws the changed frame
1914          cursor, but this function doesn't, so do it explicitly.  */
1915       x_update_cursor (f, 1);
1916     }
1921 /* ==========================================================================
1923     Keyboard handling
1925    ========================================================================== */
1928 static unsigned
1929 ns_convert_key (unsigned code)
1930 /* --------------------------------------------------------------------------
1931     Internal call used by NSView-keyDown.
1932    -------------------------------------------------------------------------- */
1934   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1935                                 / sizeof (convert_ns_to_X_keysym[0]));
1936   unsigned keysym;
1937   /* An array would be faster, but less easy to read. */
1938   for (keysym = 0; keysym < last_keysym; keysym += 2)
1939     if (code == convert_ns_to_X_keysym[keysym])
1940       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1941   return 0;
1942 /* if decide to use keyCode and Carbon table, use this line:
1943      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1947 char *
1948 x_get_keysym_name (int keysym)
1949 /* --------------------------------------------------------------------------
1950     Called by keyboard.c.  Not sure if the return val is important, except
1951     that it be unique.
1952    -------------------------------------------------------------------------- */
1954   static char value[16];
1955   NSTRACE (x_get_keysym_name);
1956   sprintf (value, "%d", keysym);
1957   return value;
1962 /* ==========================================================================
1964     Block drawing operations
1966    ========================================================================== */
1969 static void
1970 ns_redraw_scroll_bars (struct frame *f)
1972   int i;
1973   id view;
1974   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1975   NSTRACE (ns_judge_scroll_bars);
1976   for (i =[subviews count]-1; i >= 0; i--)
1977     {
1978       view = [subviews objectAtIndex: i];
1979       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1980       [view display];
1981     }
1985 void
1986 ns_clear_frame (struct frame *f)
1987 /* --------------------------------------------------------------------------
1988       External (hook): Erase the entire frame
1989    -------------------------------------------------------------------------- */
1991   NSView *view = FRAME_NS_VIEW (f);
1992   NSRect r;
1994   NSTRACE (ns_clear_frame);
1995   if (ns_in_resize)
1996     return;
1998  /* comes on initial frame because we have
1999     after-make-frame-functions = select-frame */
2000  if (!FRAME_DEFAULT_FACE (f))
2001    return;
2003   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2005   output_cursor.hpos = output_cursor.vpos = 0;
2006   output_cursor.x = -1;
2008   r = [view bounds];
2010   BLOCK_INPUT;
2011   ns_focus (f, &r, 1);
2012   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2013   NSRectFill (r);
2014   ns_unfocus (f);
2016 #ifdef NS_IMPL_COCOA
2017   [[view window] display];  /* redraw resize handle */
2018 #endif
2020   /* as of 2006/11 or so this is now needed */
2021   ns_redraw_scroll_bars (f);
2022   UNBLOCK_INPUT;
2026 void
2027 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2028 /* --------------------------------------------------------------------------
2029     External (RIF):  Clear section of frame
2030    -------------------------------------------------------------------------- */
2032   NSRect r = NSMakeRect (x, y, width, height);
2033   NSView *view = FRAME_NS_VIEW (f);
2034   struct face *face = FRAME_DEFAULT_FACE (f);
2036   if (!view || !face)
2037     return;
2039   NSTRACE (ns_clear_frame_area);
2041   r = NSIntersectionRect (r, [view frame]);
2042   ns_focus (f, &r, 1);
2043   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2045 #ifdef NS_IMPL_COCOA
2046   {
2047     /* clip out the resize handle */
2048     NSWindow *window = [FRAME_NS_VIEW (f) window];
2049     NSRect ir
2050       = [view convertRect: ns_resize_handle_rect (window) fromView: nil];
2052     ir = NSIntersectionRect (r, ir);
2053     if (NSIsEmptyRect (ir))
2054       {
2055 #endif
2057   NSRectFill (r);
2059 #ifdef NS_IMPL_COCOA
2060       }
2061     else
2062       {
2063         NSRect r1 = r, r2 = r; /* upper and lower non-intersecting */
2064         r1.size.height -= ir.size.height;
2065         r2.origin.y += r1.size.height;
2066         r2.size.width -= ir.size.width;
2067         r2.size.height = ir.size.height;
2068         NSRectFill (r1);
2069         NSRectFill (r2);
2070       }
2071   }
2072 #endif
2074   ns_unfocus (f);
2075   return;
2079 static void
2080 ns_scroll_run (struct window *w, struct run *run)
2081 /* --------------------------------------------------------------------------
2082     External (RIF):  Insert or delete n lines at line vpos
2083    -------------------------------------------------------------------------- */
2085   struct frame *f = XFRAME (w->frame);
2086   int x, y, width, height, from_y, to_y, bottom_y;
2088   NSTRACE (ns_scroll_run);
2090   /* begin copy from other terms */
2091   /* Get frame-relative bounding box of the text display area of W,
2092      without mode lines.  Include in this box the left and right
2093      fringe of W.  */
2094   window_box (w, -1, &x, &y, &width, &height);
2096   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2097   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2098   bottom_y = y + height;
2100   if (to_y < from_y)
2101     {
2102       /* Scrolling up.  Make sure we don't copy part of the mode
2103          line at the bottom.  */
2104       if (from_y + run->height > bottom_y)
2105         height = bottom_y - from_y;
2106       else
2107         height = run->height;
2108     }
2109   else
2110     {
2111       /* Scolling down.  Make sure we don't copy over the mode line.
2112          at the bottom.  */
2113       if (to_y + run->height > bottom_y)
2114         height = bottom_y - to_y;
2115       else
2116         height = run->height;
2117     }
2118   /* end copy from other terms */
2120   if (height == 0)
2121       return;
2123   BLOCK_INPUT;
2125   updated_window = w;
2126   x_clear_cursor (w);
2128   {
2129     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2130     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2131     NSPoint dstOrigin = NSMakePoint (x, to_y);
2133     ns_focus (f, &dstRect, 1);
2134     NSCopyBits (0, srcRect , dstOrigin);
2135     ns_unfocus (f);
2136   }
2138   UNBLOCK_INPUT;
2142 static void
2143 ns_after_update_window_line (struct glyph_row *desired_row)
2144 /* --------------------------------------------------------------------------
2145     External (RIF): preparatory to fringe update after text was updated
2146    -------------------------------------------------------------------------- */
2148   struct window *w = updated_window;
2149   struct frame *f;
2150   int width, height;
2152   NSTRACE (ns_after_update_window_line);
2154   /* begin copy from other terms */
2155   xassert (w);
2157   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2158     desired_row->redraw_fringe_bitmaps_p = 1;
2160   /* When a window has disappeared, make sure that no rest of
2161      full-width rows stays visible in the internal border.
2162      Under NS this is drawn inside the fringes. */
2163   if (windows_or_buffers_changed
2164       && (f = XFRAME (w->frame),
2165           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2166           width != 0)
2167       && (height = desired_row->visible_height,
2168           height > 0))
2169     {
2170       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2172       /* Internal border is drawn below the tool bar.  */
2173       if (WINDOWP (f->tool_bar_window)
2174           && w == XWINDOW (f->tool_bar_window))
2175         y -= width;
2176       /* end copy from other terms */
2178       BLOCK_INPUT;
2179       if (!desired_row->full_width_p)
2180         {
2181           int x1 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2182             + WINDOW_LEFT_FRINGE_WIDTH (w);
2183           int x2 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2184             + FRAME_PIXEL_WIDTH (f) - NS_SCROLL_BAR_WIDTH (f)
2185             - WINDOW_RIGHT_FRINGE_WIDTH (w)
2186             - FRAME_INTERNAL_BORDER_WIDTH (f);
2187           ns_clear_frame_area (f, x1, y, width, height);
2188           ns_clear_frame_area (f, x2, y, width, height);
2189         }
2190       UNBLOCK_INPUT;
2191     }
2195 static void
2196 ns_shift_glyphs_for_insert (struct frame *f,
2197                            int x, int y, int width, int height,
2198                            int shift_by)
2199 /* --------------------------------------------------------------------------
2200     External (RIF): copy an area horizontally, don't worry about clearing src
2201    -------------------------------------------------------------------------- */
2203   NSRect srcRect = NSMakeRect (x, y, width, height);
2204   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2205   NSPoint dstOrigin = dstRect.origin;
2207   NSTRACE (ns_shift_glyphs_for_insert);
2209   ns_focus (f, &dstRect, 1);
2210   NSCopyBits (0, srcRect, dstOrigin);
2211   ns_unfocus (f);
2216 /* ==========================================================================
2218     Character encoding and metrics
2220    ========================================================================== */
2223 static inline void
2224 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2225 /* --------------------------------------------------------------------------
2226      External (RIF); compute left/right overhang of whole string and set in s
2227    -------------------------------------------------------------------------- */
2229   struct face *face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2230   struct font *font = s->font; /*face->font; */
2232   if (s->char2b)
2233     {
2234       struct font_metrics metrics;
2235       unsigned int codes[2];
2236       codes[0] = *(s->char2b);
2237       codes[1] = *(s->char2b + s->nchars - 1);
2239       font->driver->text_extents (font, codes, 2, &metrics);
2240       s->left_overhang = -metrics.lbearing;
2241       s->right_overhang
2242         = metrics.rbearing > metrics.width
2243         ? metrics.rbearing - metrics.width : 0;
2244     }
2245   else
2246     {
2247       s->left_overhang = 0;
2248       s->right_overhang = ((struct nsfont_info *)font)->ital ?
2249         FONT_HEIGHT (font) * 0.2 : 0;
2250     }
2255 /* ==========================================================================
2257     Fringe and cursor drawing
2259    ========================================================================== */
2262 extern int max_used_fringe_bitmap;
2263 static void
2264 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2265                       struct draw_fringe_bitmap_params *p)
2266 /* --------------------------------------------------------------------------
2267     External (RIF); fringe-related
2268    -------------------------------------------------------------------------- */
2270   struct frame *f = XFRAME (WINDOW_FRAME (w));
2271   struct face *face = p->face;
2272   int rowY;
2273   static EmacsImage **bimgs = NULL;
2274   static int nBimgs = 0;
2275   /* NS-specific: move internal border inside fringe */
2276   int x = p->bx < 0 ? p->x : p->bx;
2277   int wd = p->bx < 0 ? p->wd : p->nx;
2278   BOOL fringeOnVeryLeft
2279     = x - WINDOW_LEFT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w)
2280       - FRAME_INTERNAL_BORDER_WIDTH (f) < 10;
2281   BOOL fringeOnVeryRight
2282     = FRAME_PIXEL_WIDTH (f) - x - wd - FRAME_INTERNAL_BORDER_WIDTH (f)
2283       - WINDOW_RIGHT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w) < 10;
2284   int xAdjust = FRAME_INTERNAL_BORDER_WIDTH (f) *
2285     (fringeOnVeryLeft ? -1 : (fringeOnVeryRight ? 1 : 0));
2287   /* grow bimgs if needed */
2288   if (nBimgs < max_used_fringe_bitmap)
2289     {
2290       EmacsImage **newBimgs
2291         = xmalloc (max_used_fringe_bitmap * sizeof (EmacsImage *));
2292       memset (newBimgs, 0, max_used_fringe_bitmap * sizeof (EmacsImage *));
2294       if (nBimgs)
2295         {
2296           memcpy (newBimgs, bimgs, nBimgs * sizeof (EmacsImage *));
2297           xfree (bimgs);
2298         }
2300       bimgs = newBimgs;
2301       nBimgs = max_used_fringe_bitmap;
2302     }
2304   /* Must clip because of partially visible lines.  */
2305   rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2306   ns_clip_to_row (w, row, -1, YES);
2308   if (p->bx >= 0 && !p->overlay_p)
2309     {
2310       int yAdjust = rowY - FRAME_INTERNAL_BORDER_WIDTH (f) < 5 ?
2311         -FRAME_INTERNAL_BORDER_WIDTH (f) : 0;
2312       int yIncr = FRAME_PIXEL_HEIGHT (f) - (p->by+yAdjust + p->ny) < 5 ?
2313         FRAME_INTERNAL_BORDER_WIDTH (f) : 0
2314         + (yAdjust ? FRAME_INTERNAL_BORDER_WIDTH (f) : 0);
2315       NSRect r = NSMakeRect (p->bx+xAdjust, p->by+yAdjust, p->nx, p->ny+yIncr);
2316       NSRectClip (r);
2317       [ns_lookup_indexed_color(face->background, f) set];
2318       NSRectFill (r);
2319     }
2321   if (p->which)
2322     {
2323       NSRect r = NSMakeRect (p->x+xAdjust, p->y, p->wd, p->h);
2324       NSPoint pt = r.origin;
2325       EmacsImage *img = bimgs[p->which - 1];
2327       if (!img)
2328         {
2329           unsigned short *bits = p->bits + p->dh;
2330           int len = p->h;
2331           int i;
2332           unsigned char *cbits = xmalloc (len);
2334           for (i =0; i<len; i++)
2335             cbits[i] = ~(bits[i] & 0xff);
2336           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2337                                            flip: NO];
2338           bimgs[p->which - 1] = img;
2339           xfree (cbits);
2340         }
2342       NSRectClip (r);
2343       /* Since we composite the bitmap instead of just blitting it, we need
2344          to erase the whole background. */
2345       [ns_lookup_indexed_color(face->background, f) set];
2346       NSRectFill (r);
2347       pt.y += p->h;
2348       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2349       [img compositeToPoint: pt operation: NSCompositeSourceOver];
2350     }
2351   ns_unfocus (f);
2355 void
2356 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2357                        int x, int y, int cursor_type, int cursor_width,
2358                        int on_p, int active_p)
2359 /* --------------------------------------------------------------------------
2360      External call (RIF): draw cursor.
2361      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2362    -------------------------------------------------------------------------- */
2364   NSRect r, s;
2365   int fx, fy, h, cursor_height;
2366   struct frame *f = WINDOW_XFRAME (w);
2367   struct glyph *phys_cursor_glyph;
2368   int overspill;
2369   struct glyph *cursor_glyph;
2370   struct face *face;
2371   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2373   /* If cursor is out of bounds, don't draw garbage.  This can happen
2374      in mini-buffer windows when switching between echo area glyphs
2375      and mini-buffer.  */
2377   NSTRACE (dumpcursor);
2379   if (!on_p)
2380     return;
2382   w->phys_cursor_type = cursor_type;
2383   w->phys_cursor_on_p = on_p;
2385   if (cursor_type == NO_CURSOR)
2386     {
2387       w->phys_cursor_width = 0;
2388       return;
2389     }
2391   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2392     {
2393       if (glyph_row->exact_window_width_line_p
2394           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2395         {
2396           glyph_row->cursor_in_fringe_p = 1;
2397           draw_fringe_bitmap (w, glyph_row, 0);
2398         }
2399       return;
2400     }
2402   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2403      (other terminals do it the other way round).  We must set
2404      w->phys_cursor_width to the cursor width.  For bar cursors, that
2405      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2406   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2408   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2409      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2410   if (cursor_type == BAR_CURSOR)
2411     {
2412       if (cursor_width < 1)
2413         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2414       w->phys_cursor_width = cursor_width;
2415     }
2416   /* If we have an HBAR, "cursor_width" MAY specify height. */
2417   else if (cursor_type == HBAR_CURSOR)
2418     {
2419       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2420       fy += h - cursor_height;
2421       h = cursor_height;
2422     }
2424   r.origin.x = fx, r.origin.y = fy;
2425   r.size.height = h;
2426   r.size.width = w->phys_cursor_width;
2428   /* FIXME: if we overwrite the internal border area, it does not get erased;
2429      fix by truncating cursor, but better would be to erase properly */
2430   overspill = r.origin.x + r.size.width -
2431     WINDOW_TEXT_TO_FRAME_PIXEL_X (w, WINDOW_BOX_RIGHT_EDGE_X (w)
2432       - WINDOW_TOTAL_FRINGE_WIDTH (w) - FRAME_INTERNAL_BORDER_WIDTH (f));
2433   if (overspill > 0)
2434     r.size.width -= overspill;
2436   /* TODO: only needed in rare cases with last-resort font in HELLO..
2437      should we do this more efficiently? */
2438   ns_clip_to_row (w, glyph_row, -1, NO); /* do ns_focus(f, &r, 1); if remove */
2441   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2442   if (face && NS_FACE_BACKGROUND (face)
2443       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2444     {
2445       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2446       hollow_color = FRAME_CURSOR_COLOR (f);
2447     }
2448   else
2449     [FRAME_CURSOR_COLOR (f) set];
2451 #ifdef NS_IMPL_COCOA
2452   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2453            atomic.  Cleaner ways of doing this should be investigated.
2454            One way would be to set a global variable DRAWING_CURSOR
2455            when making the call to draw_phys..(), don't focus in that
2456            case, then move the ns_unfocus() here after that call. */
2457   NSDisableScreenUpdates ();
2458 #endif
2460   switch (cursor_type)
2461     {
2462     case NO_CURSOR:
2463       break;
2464     case FILLED_BOX_CURSOR:
2465       NSRectFill (r);
2466       break;
2467     case HOLLOW_BOX_CURSOR:
2468       NSRectFill (r);
2469       [hollow_color set];
2470       NSRectFill (NSInsetRect (r, 1, 1));
2471       [FRAME_CURSOR_COLOR (f) set];
2472       break;
2473     case HBAR_CURSOR:
2474       NSRectFill (r);
2475       break;
2476     case BAR_CURSOR:
2477       s = r;
2478       /* If the character under cursor is R2L, draw the bar cursor
2479          on the right of its glyph, rather than on the left.  */
2480       cursor_glyph = get_phys_cursor_glyph (w);
2481       if ((cursor_glyph->resolved_level & 1) != 0)
2482         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2484       NSRectFill (s);
2485       break;
2486     }
2487   ns_unfocus (f);
2489   /* draw the character under the cursor */
2490   if (cursor_type != NO_CURSOR)
2491     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2493 #ifdef NS_IMPL_COCOA
2494   NSEnableScreenUpdates ();
2495 #endif
2500 static void
2501 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2502 /* --------------------------------------------------------------------------
2503      External (RIF): Draw a vertical line.
2504    -------------------------------------------------------------------------- */
2506   struct frame *f = XFRAME (WINDOW_FRAME (w));
2507   struct face *face;
2508   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2510   NSTRACE (ns_draw_vertical_window_border);
2512   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2513   if (face)
2514       [ns_lookup_indexed_color(face->foreground, f) set];
2516   ns_focus (f, &r, 1);
2517   NSRectFill(r);
2518   ns_unfocus (f);
2522 void
2523 show_hourglass (struct atimer *timer)
2525   if (hourglass_shown_p)
2526     return;
2528   BLOCK_INPUT;
2530   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2532   hourglass_shown_p = 1;
2533   UNBLOCK_INPUT;
2537 void
2538 hide_hourglass (void)
2540   if (!hourglass_shown_p)
2541     return;
2543   BLOCK_INPUT;
2545   /* TODO: remove NSProgressIndicator from all frames */
2547   hourglass_shown_p = 0;
2548   UNBLOCK_INPUT;
2553 /* ==========================================================================
2555     Glyph drawing operations
2557    ========================================================================== */
2560 static inline NSRect
2561 ns_fix_rect_ibw (NSRect r, int fibw, int frame_pixel_width)
2562 /* --------------------------------------------------------------------------
2563     Under NS we draw internal borders inside fringes, and want full-width
2564     rendering to go all the way to edge.  This function makes that correction.
2565    -------------------------------------------------------------------------- */
2567   if (r.origin.y <= fibw+1)
2568     {
2569       r.size.height += r.origin.y;
2570       r.origin.y = 0;
2571     }
2572   if (r.origin.x <= fibw+1)
2573     {
2574       r.size.width += r.origin.x;
2575       r.origin.x = 0;
2576     }
2577   if (frame_pixel_width - (r.origin.x+r.size.width) <= fibw+1)
2578     r.size.width += fibw;
2580   return r;
2584 static int
2585 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2586 /* --------------------------------------------------------------------------
2587     Wrapper utility to account for internal border width on full-width lines,
2588     and allow top full-width rows to hit the frame top.  nr should be pointer
2589     to two successive NSRects.  Number of rects actually used is returned.
2590    -------------------------------------------------------------------------- */
2592   int n = get_glyph_string_clip_rects (s, nr, 2);
2593   if (s->row->full_width_p)
2594     {
2595       *nr = ns_fix_rect_ibw (*nr, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2596                             FRAME_PIXEL_WIDTH (s->f));
2597       if (n == 2)
2598         *nr = ns_fix_rect_ibw (*(nr+1), FRAME_INTERNAL_BORDER_WIDTH (s->f),
2599                               FRAME_PIXEL_WIDTH (s->f));
2600     }
2601   return n;
2604 void
2605 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2606                          NSColor *defaultCol, CGFloat width, CGFloat x)
2607 /* --------------------------------------------------------------------------
2608    Draw underline, overline, and strike-through on glyph string s.
2609    -------------------------------------------------------------------------- */
2611   if (s->for_overlaps)
2612     return;
2614   /* Do underline. */
2615   if (face->underline_p)
2616     {
2617       NSRect r;
2618       unsigned long thickness, position;
2620       /* If the prev was underlined, match its appearance. */
2621       if (s->prev && s->prev->face->underline_p
2622           && s->prev->underline_thickness > 0)
2623         {
2624           thickness = s->prev->underline_thickness;
2625           position = s->prev->underline_position;
2626         }
2627       else
2628         {
2629           struct font *font;
2630           unsigned long descent;
2632           font=s->font;
2633           descent = s->y + s->height - s->ybase;
2635           /* Use underline thickness of font, defaulting to 1. */
2636           thickness = (font && font->underline_thickness > 0)
2637             ? font->underline_thickness : 1;
2639           /* Determine the offset of underlining from the baseline. */
2640           if (x_underline_at_descent_line)
2641             position = descent - thickness;
2642           else if (x_use_underline_position_properties
2643                    && font && font->underline_position >= 0)
2644             position = font->underline_position;
2645           else if (font)
2646             position = lround (font->descent / 2);
2647           else
2648             position = underline_minimum_offset;
2650           position = max (position, underline_minimum_offset);
2652           /* Ensure underlining is not cropped. */
2653           if (descent <= position)
2654             {
2655               position = descent - 1;
2656               thickness = 1;
2657             }
2658           else if (descent < position + thickness)
2659             thickness = 1;
2660         }
2662       s->underline_thickness = thickness;
2663       s->underline_position = position;
2665       r = NSMakeRect (x, s->ybase + position, width, thickness);
2667       if (face->underline_defaulted_p)
2668         [defaultCol set];
2669       else
2670         [ns_lookup_indexed_color (face->underline_color, s->f) set];
2671       NSRectFill (r);
2672     }
2674   /* Do overline. We follow other terms in using a thickness of 1
2675      and ignoring overline_margin. */
2676   if (face->overline_p)
2677     {
2678       NSRect r;
2679       r = NSMakeRect (x, s->y, width, 1);
2681       if (face->overline_color_defaulted_p)
2682         [defaultCol set];
2683       else
2684         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2685       NSRectFill (r);
2686     }
2688   /* Do strike-through.  We follow other terms for thickness and
2689      vertical position.*/
2690   if (face->strike_through_p)
2691     {
2692       NSRect r;
2693       unsigned long dy;
2695       dy = lrint ((s->height - 1) / 2);
2696       r = NSMakeRect (x, s->y + dy, width, 1);
2698       if (face->strike_through_color_defaulted_p)
2699         [defaultCol set];
2700       else
2701         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2702       NSRectFill (r);
2703     }
2706 static void
2707 ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char right_p)
2708 /* --------------------------------------------------------------------------
2709     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2710     Note we can't just use an NSDrawRect command, because of the possibility
2711     of some sides not being drawn, and because the rect will be filled.
2712    -------------------------------------------------------------------------- */
2714   NSRect s = r;
2715   [col set];
2717   /* top, bottom */
2718   s.size.height = thickness;
2719   NSRectFill (s);
2720   s.origin.y += r.size.height - thickness;
2721   NSRectFill (s);
2723   s.size.height = r.size.height;
2724   s.origin.y = r.origin.y;
2726   /* left, right (optional) */
2727   s.size.width = thickness;
2728   if (left_p)
2729     NSRectFill (s);
2730   if (right_p)
2731     {
2732       s.origin.x += r.size.width - thickness;
2733       NSRectFill (s);
2734     }
2738 static void
2739 ns_draw_relief (NSRect r, int thickness, char raised_p,
2740                char top_p, char bottom_p, char left_p, char right_p,
2741                struct glyph_string *s)
2742 /* --------------------------------------------------------------------------
2743     Draw a relief rect inside r, optionally leaving some sides open.
2744     Note we can't just use an NSDrawBezel command, because of the possibility
2745     of some sides not being drawn, and because the rect will be filled.
2746    -------------------------------------------------------------------------- */
2748   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2749   NSColor *newBaseCol = nil;
2750   NSRect sr = r;
2752   NSTRACE (ns_draw_relief);
2754   /* set up colors */
2756   if (s->face->use_box_color_for_shadows_p)
2757     {
2758       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2759     }
2760 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2761            && s->img->pixmap
2762            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2763        {
2764          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2765        } */
2766   else
2767     {
2768       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2769     }
2771   if (newBaseCol == nil)
2772     newBaseCol = [NSColor grayColor];
2774   if (newBaseCol != baseCol)  /* TODO: better check */
2775     {
2776       [baseCol release];
2777       baseCol = [newBaseCol retain];
2778       [lightCol release];
2779       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2780       [darkCol release];
2781       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2782     }
2784   [(raised_p ? lightCol : darkCol) set];
2786   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2788   /* top */
2789   sr.size.height = thickness;
2790   if (top_p) NSRectFill (sr);
2792   /* left */
2793   sr.size.height = r.size.height;
2794   sr.size.width = thickness;
2795   if (left_p) NSRectFill (sr);
2797   [(raised_p ? darkCol : lightCol) set];
2799   /* bottom */
2800   sr.size.width = r.size.width;
2801   sr.size.height = thickness;
2802   sr.origin.y += r.size.height - thickness;
2803   if (bottom_p) NSRectFill (sr);
2805   /* right */
2806   sr.size.height = r.size.height;
2807   sr.origin.y = r.origin.y;
2808   sr.size.width = thickness;
2809   sr.origin.x += r.size.width - thickness;
2810   if (right_p) NSRectFill (sr);
2814 static void
2815 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2816 /* --------------------------------------------------------------------------
2817       Function modeled after x_draw_glyph_string_box ().
2818       Sets up parameters for drawing.
2819    -------------------------------------------------------------------------- */
2821   int right_x, last_x;
2822   char left_p, right_p;
2823   struct glyph *last_glyph;
2824   NSRect r;
2825   int thickness;
2826   struct face *face;
2828   if (s->hl == DRAW_MOUSE_FACE)
2829     {
2830       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2831       if (!face)
2832         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2833     }
2834   else
2835     face = s->face;
2837   thickness = face->box_line_width;
2839   NSTRACE (ns_dumpglyphs_box_or_relief);
2841   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2842             ? WINDOW_RIGHT_EDGE_X (s->w)
2843             : window_box_right (s->w, s->area));
2844   last_glyph = (s->cmp || s->img
2845                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2847   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2848               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2850   left_p = (s->first_glyph->left_box_line_p
2851             || (s->hl == DRAW_MOUSE_FACE
2852                 && (s->prev == NULL || s->prev->hl != s->hl)));
2853   right_p = (last_glyph->right_box_line_p
2854              || (s->hl == DRAW_MOUSE_FACE
2855                  && (s->next == NULL || s->next->hl != s->hl)));
2857   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2859   /* expand full-width row over internal borders */
2860   if (s->row->full_width_p)
2861     r = ns_fix_rect_ibw (r, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2862                         FRAME_PIXEL_WIDTH (s->f));
2864   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2865   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2866     {
2867       ns_draw_box (r, abs (thickness),
2868                    ns_lookup_indexed_color (face->box_color, s->f),
2869                   left_p, right_p);
2870     }
2871   else
2872     {
2873       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2874                      1, 1, left_p, right_p, s);
2875     }
2879 static void
2880 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2881 /* --------------------------------------------------------------------------
2882       Modeled after x_draw_glyph_string_background, which draws BG in
2883       certain cases.  Others are left to the text rendering routine.
2884    -------------------------------------------------------------------------- */
2886   NSTRACE (ns_maybe_dumpglyphs_background);
2888   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2889     {
2890       int box_line_width = max (s->face->box_line_width, 0);
2891       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2892           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2893         {
2894           struct face *face;
2895           if (s->hl == DRAW_MOUSE_FACE)
2896             {
2897               face = FACE_FROM_ID (s->f,
2898                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2899               if (!face)
2900                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2901             }
2902           else
2903             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2904           if (!face->stipple)
2905             [(NS_FACE_BACKGROUND (face) != 0
2906               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2907               : FRAME_BACKGROUND_COLOR (s->f)) set];
2908           else
2909             {
2910               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2911               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2912             }
2914           if (s->hl != DRAW_CURSOR)
2915             {
2916               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2917                                     s->background_width,
2918                                     s->height-2*box_line_width);
2920               /* expand full-width row over internal borders */
2921               if (s->row->full_width_p)
2922                 {
2923                   int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2924                   if (r.origin.y <= fibw+1 + box_line_width)
2925                     {
2926                       r.size.height += r.origin.y;
2927                       r.origin.y = 0;
2928                     }
2929                   if (r.origin.x <= fibw+1)
2930                     {
2931                       r.size.width += 2*r.origin.x;
2932                       r.origin.x = 0;
2933                     }
2934                   if (FRAME_PIXEL_WIDTH (s->f) - (r.origin.x + r.size.width)
2935                       <= fibw+1)
2936                     r.size.width += fibw;
2937                 }
2939               NSRectFill (r);
2940             }
2942           s->background_filled_p = 1;
2943         }
2944     }
2948 static void
2949 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2950 /* --------------------------------------------------------------------------
2951       Renders an image and associated borders.
2952    -------------------------------------------------------------------------- */
2954   EmacsImage *img = s->img->pixmap;
2955   int box_line_vwidth = max (s->face->box_line_width, 0);
2956   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2957   int bg_x, bg_y, bg_height;
2958   int th;
2959   char raised_p;
2960   NSRect br;
2961   struct face *face;
2962   NSColor *tdCol;
2964   NSTRACE (ns_dumpglyphs_image);
2966   if (s->face->box != FACE_NO_BOX
2967       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2968     x += abs (s->face->box_line_width);
2970   bg_x = x;
2971   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2972   bg_height = s->height;
2973   /* other terms have this, but was causing problems w/tabbar mode */
2974   /* - 2 * box_line_vwidth; */
2976   if (s->slice.x == 0) x += s->img->hmargin;
2977   if (s->slice.y == 0) y += s->img->vmargin;
2979   /* Draw BG: if we need larger area than image itself cleared, do that,
2980      otherwise, since we composite the image under NS (instead of mucking
2981      with its background color), we must clear just the image area. */
2982   if (s->hl == DRAW_MOUSE_FACE)
2983     {
2984       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2985       if (!face)
2986        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2987     }
2988   else
2989     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2991   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2993   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2994       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2995     {
2996       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
2997       s->background_filled_p = 1;
2998     }
2999   else
3000     {
3001       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3002     }
3004   /* expand full-width row over internal borders */
3005   if (s->row->full_width_p)
3006     {
3007       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
3008       if (br.origin.y <= fibw+1 + box_line_vwidth)
3009         {
3010           br.size.height += br.origin.y;
3011           br.origin.y = 0;
3012         }
3013       if (br.origin.x <= fibw+1 + box_line_vwidth)
3014         {
3015           br.size.width += br.origin.x;
3016           br.origin.x = 0;
3017         }
3018       if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) <= fibw+1)
3019         br.size.width += fibw;
3020     }
3022   NSRectFill (br);
3024   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3025   if (img != nil)
3026     [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3027                 operation: NSCompositeSourceOver];
3029   if (s->hl == DRAW_CURSOR)
3030     {
3031     [FRAME_CURSOR_COLOR (s->f) set];
3032     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3033       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3034     else
3035       /* Currently on NS img->mask is always 0. Since
3036          get_window_cursor_type specifies a hollow box cursor when on
3037          a non-masked image we never reach this clause. But we put it
3038          in in anticipation of better support for image masks on
3039          NS. */
3040       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3041     }
3042   else
3043     {
3044       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3045     }
3047   /* Draw underline, overline, strike-through. */
3048   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3050   /* Draw relief, if requested */
3051   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3052     {
3053       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3054         {
3055           th = tool_bar_button_relief >= 0 ?
3056             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3057           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3058         }
3059       else
3060         {
3061           th = abs (s->img->relief);
3062           raised_p = (s->img->relief > 0);
3063         }
3065       r.origin.x = x - th;
3066       r.origin.y = y - th;
3067       r.size.width = s->slice.width + 2*th-1;
3068       r.size.height = s->slice.height + 2*th-1;
3069       ns_draw_relief (r, th, raised_p,
3070                       s->slice.y == 0,
3071                       s->slice.y + s->slice.height == s->img->height,
3072                       s->slice.x == 0,
3073                       s->slice.x + s->slice.width == s->img->width, s);
3074     }
3076   /* If there is no mask, the background won't be seen,
3077      so draw a rectangle on the image for the cursor.
3078      Do this for all images, getting trancparency right is not reliable.  */
3079   if (s->hl == DRAW_CURSOR)
3080     {
3081       int thickness = abs (s->img->relief);
3082       if (thickness == 0) thickness = 1;
3083       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3084     }
3088 static void
3089 ns_dumpglyphs_stretch (struct glyph_string *s)
3091   NSRect r[2];
3092   int n, i;
3093   struct face *face;
3094   NSColor *fgCol, *bgCol;
3096   if (!s->background_filled_p)
3097     {
3098       n = ns_get_glyph_string_clip_rect (s, r);
3099       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3101       ns_focus (s->f, r, n);
3103       if (s->hl == DRAW_MOUSE_FACE)
3104        {
3105          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3106          if (!face)
3107            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3108        }
3109       else
3110        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3112       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3113       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3115       for (i=0; i<n; i++)
3116         {
3117           if (!s->row->full_width_p)
3118             {
3119               int overrun, leftoverrun;
3121               /* truncate to avoid overwriting fringe and/or scrollbar */
3122               overrun = max (0, (s->x + s->background_width)
3123                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3124                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3125               r[i].size.width -= overrun;
3127               /* truncate to avoid overwriting to left of the window box */
3128               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3129                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3131               if (leftoverrun > 0)
3132                 {
3133                   r[i].origin.x += leftoverrun;
3134                   r[i].size.width -= leftoverrun;
3135                 }
3137               /* XXX: Try to work between problem where a stretch glyph on
3138                  a partially-visible bottom row will clear part of the
3139                  modeline, and another where list-buffers headers and similar
3140                  rows erroneously have visible_height set to 0.  Not sure
3141                  where this is coming from as other terms seem not to show. */
3142               r[i].size.height = min (s->height, s->row->visible_height);
3143             }
3145           /* expand full-width rows over internal borders */
3146           else
3147             {
3148               r[i] = ns_fix_rect_ibw (r[i], FRAME_INTERNAL_BORDER_WIDTH (s->f),
3149                                       FRAME_PIXEL_WIDTH (s->f));
3150             }
3152           [bgCol set];
3154           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3155              overwriting cursor (usually when cursor on a tab) */
3156           if (s->hl == DRAW_CURSOR)
3157             {
3158               CGFloat x, width;
3160               x = r[i].origin.x;
3161               width = s->w->phys_cursor_width;
3162               r[i].size.width -= width;
3163               r[i].origin.x += width;
3165               NSRectFill (r[i]);
3167               /* Draw overlining, etc. on the cursor. */
3168               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3169                 ns_draw_text_decoration (s, face, bgCol, width, x);
3170               else
3171                 ns_draw_text_decoration (s, face, fgCol, width, x);
3172             }
3173           else
3174             {
3175               NSRectFill (r[i]);
3176             }
3178           /* Draw overlining, etc. on the stretch glyph (or the part
3179              of the stretch glyph after the cursor). */
3180           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3181                                    r[i].origin.x);
3182         }
3183       ns_unfocus (s->f);
3184       s->background_filled_p = 1;
3185     }
3189 static void
3190 ns_draw_glyph_string (struct glyph_string *s)
3191 /* --------------------------------------------------------------------------
3192       External (RIF): Main draw-text call.
3193    -------------------------------------------------------------------------- */
3195   /* TODO (optimize): focus for box and contents draw */
3196   NSRect r[2];
3197   int n;
3198   char box_drawn_p = 0;
3200   NSTRACE (ns_draw_glyph_string);
3202   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3203     {
3204       int width;
3205       struct glyph_string *next;
3207       for (width = 0, next = s->next;
3208            next && width < s->right_overhang;
3209            width += next->width, next = next->next)
3210         if (next->first_glyph->type != IMAGE_GLYPH)
3211           {
3212             if (next->first_glyph->type != STRETCH_GLYPH)
3213               {
3214                 n = ns_get_glyph_string_clip_rect (s->next, r);
3215                 ns_focus (s->f, r, n);
3216                 ns_maybe_dumpglyphs_background (s->next, 1);
3217                 ns_unfocus (s->f);
3218               }
3219             else
3220               {
3221                 ns_dumpglyphs_stretch (s->next);
3222               }
3223             next->num_clips = 0;
3224           }
3225     }
3227   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3228         && (s->first_glyph->type == CHAR_GLYPH
3229             || s->first_glyph->type == COMPOSITE_GLYPH))
3230     {
3231       n = ns_get_glyph_string_clip_rect (s, r);
3232       ns_focus (s->f, r, n);
3233       ns_maybe_dumpglyphs_background (s, 1);
3234       ns_dumpglyphs_box_or_relief (s);
3235       ns_unfocus (s->f);
3236       box_drawn_p = 1;
3237     }
3239   switch (s->first_glyph->type)
3240     {
3242     case IMAGE_GLYPH:
3243       n = ns_get_glyph_string_clip_rect (s, r);
3244       ns_focus (s->f, r, n);
3245       ns_dumpglyphs_image (s, r[0]);
3246       ns_unfocus (s->f);
3247       break;
3249     case STRETCH_GLYPH:
3250       ns_dumpglyphs_stretch (s);
3251       break;
3253     case CHAR_GLYPH:
3254     case COMPOSITE_GLYPH:
3255       n = ns_get_glyph_string_clip_rect (s, r);
3256       ns_focus (s->f, r, n);
3258       if (s->for_overlaps || (s->cmp_from > 0
3259                               && ! s->first_glyph->u.cmp.automatic))
3260         s->background_filled_p = 1;
3261       else
3262         ns_maybe_dumpglyphs_background
3263           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3265       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3266                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3267                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3268                       NS_DUMPGLYPH_NORMAL));
3269       ns_tmp_font = (struct nsfont_info *)s->face->font;
3270       if (ns_tmp_font == NULL)
3271           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
3273       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3274         {
3275           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3276           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3277           NS_FACE_FOREGROUND (s->face) = tmp;
3278         }
3280       ns_tmp_font->font.driver->draw
3281         (s, 0, s->nchars, s->x, s->y,
3282          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3283          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
3285       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3286         {
3287           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3288           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3289           NS_FACE_FOREGROUND (s->face) = tmp;
3290         }
3292       ns_unfocus (s->f);
3293       break;
3295     case GLYPHLESS_GLYPH:
3296       n = ns_get_glyph_string_clip_rect (s, r);
3297       ns_focus (s->f, r, n);
3299       if (s->for_overlaps || (s->cmp_from > 0
3300                               && ! s->first_glyph->u.cmp.automatic))
3301         s->background_filled_p = 1;
3302       else
3303         ns_maybe_dumpglyphs_background
3304           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3305       /* ... */
3306       /* Not yet implemented.  */
3307       /* ... */
3308       ns_unfocus (s->f);
3309       break;
3311     default:
3312       abort ();
3313     }
3315   /* Draw box if not done already. */
3316   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3317     {
3318       n = ns_get_glyph_string_clip_rect (s, r);
3319       ns_focus (s->f, r, n);
3320       ns_dumpglyphs_box_or_relief (s);
3321       ns_unfocus (s->f);
3322     }
3324   s->num_clips = 0;
3329 /* ==========================================================================
3331     Event loop
3333    ========================================================================== */
3336 static void
3337 ns_send_appdefined (int value)
3338 /* --------------------------------------------------------------------------
3339     Internal: post an appdefined event which EmacsApp-sendEvent will
3340               recognize and take as a command to halt the event loop.
3341    -------------------------------------------------------------------------- */
3343   /*NSTRACE (ns_send_appdefined); */
3345   /* Only post this event if we haven't already posted one.  This will end
3346        the [NXApp run] main loop after having processed all events queued at
3347        this moment.  */
3348   if (send_appdefined)
3349     {
3350       NSEvent *nxev;
3352       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3353       send_appdefined = NO;
3355       /* Don't need wakeup timer any more */
3356       if (timed_entry)
3357         {
3358           [timed_entry invalidate];
3359           [timed_entry release];
3360           timed_entry = nil;
3361         }
3363       /* Ditto for file descriptor poller */
3364       if (fd_entry)
3365         {
3366           [fd_entry invalidate];
3367           [fd_entry release];
3368           fd_entry = nil;
3369         }
3371       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3372                                 location: NSMakePoint (0, 0)
3373                            modifierFlags: 0
3374                                timestamp: 0
3375                             windowNumber: [[NSApp mainWindow] windowNumber]
3376                                  context: [NSApp context]
3377                                  subtype: 0
3378                                    data1: value
3379                                    data2: 0];
3381       /* Post an application defined event on the event queue.  When this is
3382          received the [NXApp run] will return, thus having processed all
3383          events which are currently queued.  */
3384       [NSApp postEvent: nxev atStart: NO];
3385     }
3389 static int
3390 ns_read_socket (struct terminal *terminal, int expected,
3391                 struct input_event *hold_quit)
3392 /* --------------------------------------------------------------------------
3393      External (hook): Post an event to ourself and keep reading events until
3394      we read it back again.  In effect process all events which were waiting.
3395      From 21+ we have to manage the event buffer ourselves.
3396    -------------------------------------------------------------------------- */
3398   struct input_event ev;
3399   int nevents;
3401 /* NSTRACE (ns_read_socket); */
3403   if (interrupt_input_blocked)
3404     {
3405       interrupt_input_pending = 1;
3406 #ifdef SYNC_INPUT
3407       pending_signals = 1;
3408 #endif
3409       return -1;
3410     }
3412   interrupt_input_pending = 0;
3413 #ifdef SYNC_INPUT
3414   pending_signals = pending_atimers;
3415 #endif
3417   BLOCK_INPUT;
3418   n_emacs_events_pending = 0;
3419   EVENT_INIT (ev);
3420   emacs_event = &ev;
3421   q_event_ptr = hold_quit;
3423   /* we manage autorelease pools by allocate/reallocate each time around
3424      the loop; strict nesting is occasionally violated but seems not to
3425      matter.. earlier methods using full nesting caused major memory leaks */
3426   [outerpool release];
3427   outerpool = [[NSAutoreleasePool alloc] init];
3429   /* If have pending open-file requests, attend to the next one of those. */
3430   if (ns_pending_files && [ns_pending_files count] != 0
3431       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3432     {
3433       [ns_pending_files removeObjectAtIndex: 0];
3434     }
3435   /* Deal with pending service requests. */
3436   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3437     && [(EmacsApp *)
3438          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3439                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3440     {
3441       [ns_pending_service_names removeObjectAtIndex: 0];
3442       [ns_pending_service_args removeObjectAtIndex: 0];
3443     }
3444   else
3445     {
3446       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3447          to ourself, otherwise [NXApp run] will never exit.  */
3448       send_appdefined = YES;
3450       /* If called via ns_select, this is called once with expected=1,
3451          because we expect either the timeout or file descriptor activity.
3452          In this case the first event through will either be real input or
3453          one of these.  read_avail_input() then calls once more with expected=0
3454          and in that case we need to return quickly if there is nothing.
3455          If we're being called outside of that, it's also OK to return quickly
3456          after one iteration through the event loop, since other terms do
3457          this and emacs expects it. */
3458       if (!(inNsSelect && expected))
3459         {
3460           /* Post an application defined event on the event queue.  When this is
3461              received the [NXApp run] will return, thus having processed all
3462              events which are currently queued, if any.  */
3463           ns_send_appdefined (-1);
3464         }
3466       [NSApp run];
3467     }
3469   nevents = n_emacs_events_pending;
3470   n_emacs_events_pending = 0;
3471   emacs_event = q_event_ptr = NULL;
3472   UNBLOCK_INPUT;
3474   return nevents;
3479 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3480            fd_set *exceptfds, struct timeval *timeout)
3481 /* --------------------------------------------------------------------------
3482      Replacement for select, checking for events
3483    -------------------------------------------------------------------------- */
3485   int result;
3486   double time;
3487   NSEvent *ev;
3488 /*  NSTRACE (ns_select); */
3490   if (NSApp == nil || inNsSelect == 1 /* || ([NSApp isActive] == NO &&
3491                       [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil
3492  inMode:NSDefaultRunLoopMode dequeue:NO] == nil) */)
3493     return select (nfds, readfds, writefds, exceptfds, timeout);
3495   /* Save file descriptor set, which gets overwritten in calls to select ()
3496      Note, this is called from process.c, and only readfds is ever set */
3497   if (readfds)
3498     {
3499       memcpy (&select_readfds, readfds, sizeof (fd_set));
3500       select_nfds = nfds;
3501     }
3502   else
3503     select_nfds = 0;
3505     /* Try an initial select for pending data on input files */
3506   select_timeout.tv_sec = select_timeout.tv_usec = 0;
3507   result = select (nfds, readfds, writefds, exceptfds, &select_timeout);
3508   if (result)
3509     return result;
3511   /* if (!timeout || timed_entry || fd_entry)
3512        fprintf (stderr, "assertion failed: timeout null or timed_entry/fd_entry non-null in ns_select\n"); */
3514     /* set a timeout and run the main AppKit event loop while continuing
3515        to monitor the files */
3516   time = ((double) timeout->tv_sec) + ((double) timeout->tv_usec)/1000000.0;
3517   timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3518                                            target: NSApp
3519                                          selector: @selector (timeout_handler:)
3520                                          userInfo: 0
3521                                           repeats: YES] /* for safe removal */
3522                                                          retain];
3524   /* set a periodic task to try the select () again */
3525   fd_entry = [[NSTimer scheduledTimerWithTimeInterval: 0.1
3526                                                target: NSApp
3527                                              selector: @selector (fd_handler:)
3528                                              userInfo: 0
3529                                               repeats: YES]
3530                retain];
3532   /* Let Application dispatch events until it receives an event of the type
3533      NX_APPDEFINED, which should only be sent by timeout_handler.
3534      We tell read_avail_input() that input is "expected" because we do expect
3535      either the timeout or fd handler to fire, and if they don't, the original
3536      call from process.c that got us here expects us to wait until some input
3537      comes. */
3538   inNsSelect = 1;
3539   gobble_input (1);
3540   ev = last_appdefined_event;
3541   inNsSelect = 0;
3543   if (ev)
3544     {
3545       int t;
3546       if ([ev type] != NSApplicationDefined)
3547         abort ();
3549       t = [ev data1];
3550       last_appdefined_event = 0;
3552       if (t == -2)
3553         {
3554           /* The NX_APPDEFINED event we received was a timeout. */
3555           return 0;
3556         }
3557       else if (t == -1)
3558         {
3559           /* The NX_APPDEFINED event we received was the result of
3560              at least one real input event arriving.  */
3561           errno = EINTR;
3562           return -1;
3563         }
3564       else
3565         {
3566           /* Received back from select () in fd_handler; copy the results */
3567           if (readfds)
3568             memcpy (readfds, &select_readfds, sizeof (fd_set));
3569           return t;
3570         }
3571     }
3572   /* never reached, shut compiler up */
3573   return 0;
3578 /* ==========================================================================
3580     Scrollbar handling
3582    ========================================================================== */
3585 static void
3586 ns_set_vertical_scroll_bar (struct window *window,
3587                            int portion, int whole, int position)
3588 /* --------------------------------------------------------------------------
3589       External (hook): Update or add scrollbar
3590    -------------------------------------------------------------------------- */
3592   Lisp_Object win;
3593   NSRect r, v;
3594   struct frame *f = XFRAME (WINDOW_FRAME (window));
3595   EmacsView *view = FRAME_NS_VIEW (f);
3596   int window_y, window_height;
3597   BOOL barOnVeryLeft, barOnVeryRight;
3598   int top, left, height, width, sb_width, sb_left;
3599   EmacsScroller *bar;
3600 static int count = 0;
3602   /* optimization; display engine sends WAY too many of these.. */
3603   if (!NILP (window->vertical_scroll_bar))
3604     {
3605       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3606       if ([bar checkSamePosition: position portion: portion whole: whole])
3607         {
3608           if (view->scrollbarsNeedingUpdate == 0)
3609             {
3610               if (!windows_or_buffers_changed)
3611                   return;
3612             }
3613           else
3614             view->scrollbarsNeedingUpdate--;
3615         }
3616     }
3618   NSTRACE (ns_set_vertical_scroll_bar);
3620   /* Get dimensions.  */
3621   window_box (window, -1, 0, &window_y, 0, &window_height);
3622   top = window_y;
3623   height = window_height;
3624   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3625   left = WINDOW_SCROLL_BAR_AREA_X (window);
3627   if (top < 5) /* top scrollbar adjustment */
3628     {
3629       top -= FRAME_INTERNAL_BORDER_WIDTH (f);
3630       height += FRAME_INTERNAL_BORDER_WIDTH (f);
3631     }
3633   /* allow for displaying a skinnier scrollbar than char area allotted */
3634   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3635     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3637   barOnVeryLeft = left < 5;
3638   barOnVeryRight = FRAME_PIXEL_WIDTH (f) - left - width < 5;
3639   sb_left = left + FRAME_INTERNAL_BORDER_WIDTH (f)
3640       * (barOnVeryLeft ? -1 : (barOnVeryRight ? 1 : 0));
3642   r = NSMakeRect (sb_left, top, sb_width, height);
3643   /* the parent view is flipped, so we need to flip y value */
3644   v = [view frame];
3645   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3647   XSETWINDOW (win, window);
3648   BLOCK_INPUT;
3650   /* we want at least 5 lines to display a scrollbar */
3651   if (WINDOW_TOTAL_LINES (window) < 5)
3652     {
3653       if (!NILP (window->vertical_scroll_bar))
3654         {
3655           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3656           [bar removeFromSuperview];
3657           window->vertical_scroll_bar = Qnil;
3658         }
3659       ns_clear_frame_area (f, sb_left, top, width, height);
3660       UNBLOCK_INPUT;
3661       return;
3662     }
3664   if (NILP (window->vertical_scroll_bar))
3665     {
3666       ns_clear_frame_area (f, sb_left, top, width, height);
3667       bar = [[EmacsScroller alloc] initFrame: r window: win];
3668       window->vertical_scroll_bar = make_save_value (bar, 0);
3669     }
3670   else
3671     {
3672       NSRect oldRect;
3673       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3674       oldRect = [bar frame];
3675       r.size.width = oldRect.size.width;
3676       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3677         {
3678           if (oldRect.origin.x != r.origin.x)
3679               ns_clear_frame_area (f, sb_left, top, width, height);
3680           [bar setFrame: r];
3681         }
3682     }
3684   [bar setPosition: position portion: portion whole: whole];
3685   UNBLOCK_INPUT;
3689 static void
3690 ns_condemn_scroll_bars (struct frame *f)
3691 /* --------------------------------------------------------------------------
3692      External (hook): arrange for all frame's scrollbars to be removed
3693      at next call to judge_scroll_bars, except for those redeemed.
3694    -------------------------------------------------------------------------- */
3696   int i;
3697   id view;
3698   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3700   NSTRACE (ns_condemn_scroll_bars);
3702   for (i =[subviews count]-1; i >= 0; i--)
3703     {
3704       view = [subviews objectAtIndex: i];
3705       if ([view isKindOfClass: [EmacsScroller class]])
3706         [view condemn];
3707     }
3711 static void
3712 ns_redeem_scroll_bar (struct window *window)
3713 /* --------------------------------------------------------------------------
3714      External (hook): arrange to spare this window's scrollbar
3715      at next call to judge_scroll_bars.
3716    -------------------------------------------------------------------------- */
3718   id bar;
3719   NSTRACE (ns_redeem_scroll_bar);
3720   if (!NILP (window->vertical_scroll_bar))
3721     {
3722       bar =XNS_SCROLL_BAR (window->vertical_scroll_bar);
3723       [bar reprieve];
3724     }
3728 static void
3729 ns_judge_scroll_bars (struct frame *f)
3730 /* --------------------------------------------------------------------------
3731      External (hook): destroy all scrollbars on frame that weren't
3732      redeemed after call to condemn_scroll_bars.
3733    -------------------------------------------------------------------------- */
3735   int i;
3736   id view;
3737   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3738   NSTRACE (ns_judge_scroll_bars);
3739   for (i =[subviews count]-1; i >= 0; i--)
3740     {
3741       view = [subviews objectAtIndex: i];
3742       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3743       [view judge];
3744     }
3748 void
3749 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
3751   /* XXX irrelevant under NS */
3756 /* ==========================================================================
3758     Initialization
3760    ========================================================================== */
3763 x_display_pixel_height (struct ns_display_info *dpyinfo)
3765   NSScreen *screen = [NSScreen mainScreen];
3766   return [screen frame].size.height;
3770 x_display_pixel_width (struct ns_display_info *dpyinfo)
3772   NSScreen *screen = [NSScreen mainScreen];
3773   return [screen frame].size.width;
3777 static Lisp_Object ns_string_to_lispmod (const char *s)
3778 /* --------------------------------------------------------------------------
3779      Convert modifier name to lisp symbol
3780    -------------------------------------------------------------------------- */
3782   if (!strncmp (SDATA (SYMBOL_NAME (Qmeta)), s, 10))
3783     return Qmeta;
3784   else if (!strncmp (SDATA (SYMBOL_NAME (Qsuper)), s, 10))
3785     return Qsuper;
3786   else if (!strncmp (SDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3787     return Qcontrol;
3788   else if (!strncmp (SDATA (SYMBOL_NAME (Qalt)), s, 10))
3789     return Qalt;
3790   else if (!strncmp (SDATA (SYMBOL_NAME (Qhyper)), s, 10))
3791     return Qhyper;
3792   else if (!strncmp (SDATA (SYMBOL_NAME (Qnone)), s, 10))
3793     return Qnone;
3794   else
3795     return Qnil;
3799 static Lisp_Object ns_mod_to_lisp (int m)
3800 /* --------------------------------------------------------------------------
3801      Convert modifier code (see lisp.h) to lisp symbol
3802    -------------------------------------------------------------------------- */
3804   if (m == CHAR_META)
3805     return Qmeta;
3806   else if (m == CHAR_SUPER)
3807     return Qsuper;
3808   else if (m == CHAR_CTL)
3809     return Qcontrol;
3810   else if (m == CHAR_ALT)
3811     return Qalt;
3812   else if (m == CHAR_HYPER)
3813     return Qhyper;
3814   else /* if (m == 0) */
3815     return Qnone;
3819 static void
3820 ns_default (const char *parameter, Lisp_Object *result,
3821            Lisp_Object yesval, Lisp_Object noval,
3822            BOOL is_float, BOOL is_modstring)
3823 /* --------------------------------------------------------------------------
3824       Check a parameter value in user's preferences
3825    -------------------------------------------------------------------------- */
3827   const char *value;
3829   if ( (value =[[[NSUserDefaults standardUserDefaults]
3830                    stringForKey: [NSString stringWithUTF8String: parameter]]
3831                 UTF8String]) )
3832     {
3833       double f;
3834       char *pos;
3835       if (strcasecmp (value, "YES") == 0)
3836         *result = yesval;
3837       else if (strcasecmp (value, "NO") == 0)
3838         *result = noval;
3839       else if (is_float && (f = strtod (value, &pos), pos != value))
3840         *result = make_float (f);
3841       else if (is_modstring && value)
3842         *result = ns_string_to_lispmod (value);
3843       else fprintf (stderr,
3844                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3845     }
3849 void
3850 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3851 /* --------------------------------------------------------------------------
3852       Initialize global info and storage for display.
3853    -------------------------------------------------------------------------- */
3855     NSScreen *screen = [NSScreen mainScreen];
3856     NSWindowDepth depth = [screen depth];
3857     Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
3859     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3860     dpyinfo->resy = 72.27;
3861     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3862                                                   NSColorSpaceFromDepth (depth)]
3863                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3864                                                  NSColorSpaceFromDepth (depth)];
3865     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3866     dpyinfo->image_cache = make_image_cache ();
3867     dpyinfo->color_table
3868       = (struct ns_color_table *)xmalloc (sizeof (struct ns_color_table));
3869     dpyinfo->color_table->colors = NULL;
3870     dpyinfo->root_window = 42; /* a placeholder.. */
3872     hlinfo->mouse_face_mouse_frame = NULL;
3873     hlinfo->mouse_face_deferred_gc = 0;
3874     hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
3875     hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
3876     hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
3877     hlinfo->mouse_face_window = hlinfo->mouse_face_overlay = Qnil;
3878     hlinfo->mouse_face_hidden = 0;
3880     hlinfo->mouse_face_mouse_x = hlinfo->mouse_face_mouse_y = 0;
3881     hlinfo->mouse_face_defer = 0;
3883     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3885     dpyinfo->n_fonts = 0;
3886     dpyinfo->smallest_font_height = 1;
3887     dpyinfo->smallest_char_width = 1;
3891 /* This and next define (many of the) public functions in this file. */
3892 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3893          with using despite presence in the "system dependent" redisplay
3894          interface.  In addition, many of the ns_ methods have code that is
3895          shared with all terms, indicating need for further refactoring. */
3896 extern frame_parm_handler ns_frame_parm_handlers[];
3897 static struct redisplay_interface ns_redisplay_interface =
3899   ns_frame_parm_handlers,
3900   x_produce_glyphs,
3901   x_write_glyphs,
3902   x_insert_glyphs,
3903   x_clear_end_of_line,
3904   ns_scroll_run,
3905   ns_after_update_window_line,
3906   ns_update_window_begin,
3907   ns_update_window_end,
3908   x_cursor_to,
3909   ns_flush,
3910   0, /* flush_display_optional */
3911   x_clear_window_mouse_face,
3912   x_get_glyph_overhangs,
3913   x_fix_overlapping_area,
3914   ns_draw_fringe_bitmap,
3915   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3916   0, /* destroy_fringe_bitmap */
3917   ns_compute_glyph_string_overhangs,
3918   ns_draw_glyph_string, /* interface to nsfont.m */
3919   ns_define_frame_cursor,
3920   ns_clear_frame_area,
3921   ns_draw_window_cursor,
3922   ns_draw_vertical_window_border,
3923   ns_shift_glyphs_for_insert
3927 static void
3928 ns_delete_display (struct ns_display_info *dpyinfo)
3930   /* TODO... */
3934 /* This function is called when the last frame on a display is deleted. */
3935 static void
3936 ns_delete_terminal (struct terminal *terminal)
3938   struct ns_display_info *dpyinfo = terminal->display_info.ns;
3939   int i;
3941   /* Protect against recursive calls.  delete_frame in
3942      delete_terminal calls us back when it deletes our last frame.  */
3943   if (!terminal->name)
3944     return;
3946   BLOCK_INPUT;
3948   x_destroy_all_bitmaps (dpyinfo);
3949   ns_delete_display (dpyinfo);
3950   UNBLOCK_INPUT;
3954 static struct terminal *
3955 ns_create_terminal (struct ns_display_info *dpyinfo)
3956 /* --------------------------------------------------------------------------
3957       Set up use of NS before we make the first connection.
3958    -------------------------------------------------------------------------- */
3960   struct terminal *terminal;
3962   NSTRACE (ns_create_terminal);
3964   terminal = create_terminal ();
3966   terminal->type = output_ns;
3967   terminal->display_info.ns = dpyinfo;
3968   dpyinfo->terminal = terminal;
3970   terminal->rif = &ns_redisplay_interface;
3972   terminal->clear_frame_hook = ns_clear_frame;
3973   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
3974   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
3975   terminal->ring_bell_hook = ns_ring_bell;
3976   terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
3977   terminal->set_terminal_modes_hook = ns_set_terminal_modes;
3978   terminal->update_begin_hook = ns_update_begin;
3979   terminal->update_end_hook = ns_update_end;
3980   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
3981   terminal->read_socket_hook = ns_read_socket;
3982   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
3983   terminal->mouse_position_hook = ns_mouse_position;
3984   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
3985   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
3987   terminal->fullscreen_hook = 0; /* see XTfullscreen_hook */
3989   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
3990   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
3991   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
3992   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
3994   terminal->delete_frame_hook = x_destroy_window;
3995   terminal->delete_terminal_hook = ns_delete_terminal;
3997   terminal->scroll_region_ok = 1;
3998   terminal->char_ins_del_ok = 1;
3999   terminal->line_ins_del_ok = 1;
4000   terminal->fast_clear_end_of_line = 1;
4001   terminal->memory_below_frame = 0;
4003   return terminal;
4007 struct ns_display_info *
4008 ns_term_init (Lisp_Object display_name)
4009 /* --------------------------------------------------------------------------
4010      Start the Application and get things rolling.
4011    -------------------------------------------------------------------------- */
4013   struct terminal *terminal;
4014   struct ns_display_info *dpyinfo;
4015   static int ns_initialized = 0;
4016   Lisp_Object tmp;
4018   NSTRACE (ns_term_init);
4020   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4021   /*GSDebugAllocationActive (YES); */
4022   BLOCK_INPUT;
4023   handling_signal = 0;
4025   if (!ns_initialized)
4026     {
4027       baud_rate = 38400;
4028       Fset_input_interrupt_mode (Qnil);
4029       ns_initialized = 1;
4030     }
4032   ns_pending_files = [[NSMutableArray alloc] init];
4033   ns_pending_service_names = [[NSMutableArray alloc] init];
4034   ns_pending_service_args = [[NSMutableArray alloc] init];
4036   /* Start app and create the main menu, window, view.
4037      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4038      The view will then ask the NSApp to stop and return to Emacs. */
4039   [EmacsApp sharedApplication];
4040   if (NSApp == nil)
4041     return NULL;
4042   [NSApp setDelegate: NSApp];
4044   /* debugging: log all notifications */
4045   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4046                                          selector: @selector (logNotification:)
4047                                              name: nil object: nil]; */
4049   dpyinfo = (struct ns_display_info *)xmalloc (sizeof (struct ns_display_info));
4050   memset (dpyinfo, 0, sizeof (struct ns_display_info));
4052   ns_initialize_display_info (dpyinfo);
4053   terminal = ns_create_terminal (dpyinfo);
4055   terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
4056   init_kboard (terminal->kboard);
4057   KVAR (terminal->kboard, Vwindow_system) = Qns;
4058   terminal->kboard->next_kboard = all_kboards;
4059   all_kboards = terminal->kboard;
4060   /* Don't let the initial kboard remain current longer than necessary.
4061      That would cause problems if a file loaded on startup tries to
4062      prompt in the mini-buffer.  */
4063   if (current_kboard == initial_kboard)
4064     current_kboard = terminal->kboard;
4065   terminal->kboard->reference_count++;
4067   dpyinfo->next = x_display_list;
4068   x_display_list = dpyinfo;
4070   /* Put it on ns_display_name_list */
4071   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
4072                                 ns_display_name_list);
4073   dpyinfo->name_list_element = XCAR (ns_display_name_list);
4075   /* Set the name of the terminal. */
4076   terminal->name = (char *) xmalloc (SBYTES (display_name) + 1);
4077   strncpy (terminal->name, SDATA (display_name), SBYTES (display_name));
4078   terminal->name[SBYTES (display_name)] = 0;
4080   UNBLOCK_INPUT;
4082   if (!inhibit_x_resources)
4083     {
4084       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4085                  Qt, Qnil, NO, NO);
4086       tmp = Qnil;
4087       /* this is a standard variable */
4088       ns_default ("AppleAntiAliasingThreshold", &tmp,
4089                  make_float (10.0), make_float (6.0), YES, NO);
4090       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4091     }
4093   ns_selection_color = [[NSUserDefaults standardUserDefaults]
4094                          stringForKey: @"AppleHighlightColor"];
4095   if (ns_selection_color == nil)
4096     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
4098   {
4099     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4101     if ( cl == nil )
4102       {
4103         Lisp_Object color_file, color_map, color;
4104         int r,g,b;
4105         unsigned long c;
4106         char *name;
4108         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4109                          Fsymbol_value (intern ("data-directory")));
4110         if (NILP (Ffile_readable_p (color_file)))
4111           fatal ("Could not find %s.\n", SDATA (color_file));
4113         color_map = Fx_load_color_file (color_file);
4114         if (NILP (color_map))
4115           fatal ("Could not read %s.\n", SDATA (color_file));
4117         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4118         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4119           {
4120             color = XCAR (color_map);
4121             name = SDATA (XCAR (color));
4122             c = XINT (XCDR (color));
4123             [cl setColor:
4124                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4125                                             green: GREEN_FROM_ULONG (c) / 255.0
4126                                              blue: BLUE_FROM_ULONG (c) / 255.0
4127                                             alpha: 1.0]
4128                   forKey: [NSString stringWithUTF8String: name]];
4129           }
4130         [cl writeToFile: nil];
4131       }
4132   }
4134   {
4135     char c[128];
4136 #ifdef NS_IMPL_GNUSTEP
4137     strncpy (c, gnustep_base_version, sizeof (c));
4138 #else
4139     /*PSnextrelease (128, c); */
4140     snprintf (c, sizeof (c), "%g", NSAppKitVersionNumber);
4141 #endif
4142     Vwindow_system_version = build_string (c);
4143   }
4145   delete_keyboard_wait_descriptor (0);
4147   ns_app_name = [[NSProcessInfo processInfo] processName];
4149 /* Set up OS X app menu */
4150 #ifdef NS_IMPL_COCOA
4151   {
4152     NSMenu *appMenu;
4153     NSMenuItem *item;
4154     /* set up the application menu */
4155     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4156     [svcsMenu setAutoenablesItems: NO];
4157     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4158     [appMenu setAutoenablesItems: NO];
4159     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4160     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4162     [appMenu insertItemWithTitle: @"About Emacs"
4163                           action: @selector (orderFrontStandardAboutPanel:)
4164                    keyEquivalent: @""
4165                          atIndex: 0];
4166     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4167     [appMenu insertItemWithTitle: @"Preferences..."
4168                           action: @selector (showPreferencesWindow:)
4169                    keyEquivalent: @","
4170                          atIndex: 2];
4171     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4172     item = [appMenu insertItemWithTitle: @"Services"
4173                                  action: @selector (menuDown:)
4174                           keyEquivalent: @""
4175                                 atIndex: 4];
4176     [appMenu setSubmenu: svcsMenu forItem: item];
4177     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4178     [appMenu insertItemWithTitle: @"Hide Emacs"
4179                           action: @selector (hide:)
4180                    keyEquivalent: @"h"
4181                          atIndex: 6];
4182     item =  [appMenu insertItemWithTitle: @"Hide Others"
4183                           action: @selector (hideOtherApplications:)
4184                    keyEquivalent: @"h"
4185                          atIndex: 7];
4186     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4187     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4188     [appMenu insertItemWithTitle: @"Quit Emacs"
4189                           action: @selector (terminate:)
4190                    keyEquivalent: @"q"
4191                          atIndex: 9];
4193     item = [mainMenu insertItemWithTitle: ns_app_name
4194                                   action: @selector (menuDown:)
4195                            keyEquivalent: @""
4196                                  atIndex: 0];
4197     [mainMenu setSubmenu: appMenu forItem: item];
4198     [dockMenu insertItemWithTitle: @"New Frame"
4199                            action: @selector (newFrame:)
4200                     keyEquivalent: @""
4201                           atIndex: 0];
4203     [NSApp setMainMenu: mainMenu];
4204     [NSApp setAppleMenu: appMenu];
4205     [NSApp setServicesMenu: svcsMenu];
4206     /* Needed at least on Cocoa, to get dock menu to show windows */
4207     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4208   }
4209 #endif /* MAC OS X menu setup */
4211   [NSApp run];
4213   return dpyinfo;
4217 void
4218 ns_term_shutdown (int sig)
4220   [[NSUserDefaults standardUserDefaults] synchronize];
4222   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4223   if (STRINGP (Vauto_save_list_file_name))
4224     unlink (SDATA (Vauto_save_list_file_name));
4226   if (sig == 0 || sig == SIGTERM)
4227     {
4228       [NSApp terminate: NSApp];
4229     }
4230   else // force a stack trace to happen
4231     {
4232       abort();
4233     }
4237 /* ==========================================================================
4239     EmacsApp implementation
4241    ========================================================================== */
4244 @implementation EmacsApp
4246 - (void)logNotification: (NSNotification *)notification
4248   const char *name = [[notification name] UTF8String];
4249   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4250       && !strstr (name, "WindowNumber"))
4251     NSLog (@"notification: '%@'", [notification name]);
4255 - (void)sendEvent: (NSEvent *)theEvent
4256 /* --------------------------------------------------------------------------
4257      Called when NSApp is running for each event received.  Used to stop
4258      the loop when we choose, since there's no way to just run one iteration.
4259    -------------------------------------------------------------------------- */
4261   int type = [theEvent type];
4262   NSWindow *window = [theEvent window];
4263 /*  NSTRACE (sendEvent); */
4264 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4266 #ifdef NS_IMPL_COCOA
4267   if (type == NSApplicationDefined
4268       && [theEvent data2] == NSAPP_DATA2_RUNASSCRIPT)
4269     {
4270       ns_run_ascript ();
4271       [self stop: self];
4272       return;
4273     }
4274 #endif
4276   if (type == NSCursorUpdate && window == nil)
4277     {
4278       fprintf (stderr, "Dropping external cursor update event.\n");
4279       return;
4280     }
4282 #ifdef NS_IMPL_COCOA
4283   /* pass mouse down in resize handle and subsequent drags directly to
4284      EmacsWindow so we can generate continuous redisplays */
4285   if (ns_in_resize)
4286     {
4287       if (type == NSLeftMouseDragged)
4288         {
4289           [window mouseDragged: theEvent];
4290           return;
4291         }
4292       else if (type == NSLeftMouseUp)
4293         {
4294           [window mouseUp: theEvent];
4295           return;
4296         }
4297     }
4298   else if (type == NSLeftMouseDown)
4299     {
4300       NSRect r = ns_resize_handle_rect (window);
4301       if (NSPointInRect ([theEvent locationInWindow], r))
4302         {
4303           ns_in_resize = YES;
4304           [window mouseDown: theEvent];
4305           return;
4306         }
4307     }
4308 #endif
4310   if (type == NSApplicationDefined)
4311     {
4312       /* Events posted by ns_send_appdefined interrupt the run loop here.
4313          But, if a modal window is up, an appdefined can still come through,
4314          (e.g., from a makeKeyWindow event) but stopping self also stops the
4315          modal loop. Just defer it until later. */
4316       if ([NSApp modalWindow] == nil)
4317         {
4318           last_appdefined_event = theEvent;
4319           [self stop: self];
4320         }
4321       else
4322         {
4323           send_appdefined = YES;
4324         }
4325     }
4327   [super sendEvent: theEvent];
4331 - (void)showPreferencesWindow: (id)sender
4333   struct frame *emacsframe = SELECTED_FRAME ();
4334   NSEvent *theEvent = [NSApp currentEvent];
4336   if (!emacs_event)
4337     return;
4338   emacs_event->kind = NS_NONKEY_EVENT;
4339   emacs_event->code = KEY_NS_SHOW_PREFS;
4340   emacs_event->modifiers = 0;
4341   EV_TRAILER (theEvent);
4345 - (void)newFrame: (id)sender
4347   struct frame *emacsframe = SELECTED_FRAME ();
4348   NSEvent *theEvent = [NSApp currentEvent];
4350   if (!emacs_event)
4351     return;
4352   emacs_event->kind = NS_NONKEY_EVENT;
4353   emacs_event->code = KEY_NS_NEW_FRAME;
4354   emacs_event->modifiers = 0;
4355   EV_TRAILER (theEvent);
4359 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4360 - (BOOL) openFile: (NSString *)fileName
4362   struct frame *emacsframe = SELECTED_FRAME ();
4363   NSEvent *theEvent = [NSApp currentEvent];
4365   if (!emacs_event)
4366     return NO;
4368   emacs_event->kind = NS_NONKEY_EVENT;
4369   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4370   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4371   ns_input_line = Qnil; /* can be start or cons start,end */
4372   emacs_event->modifiers =0;
4373   EV_TRAILER (theEvent);
4375   return YES;
4379 /* **************************************************************************
4381       EmacsApp delegate implementation
4383    ************************************************************************** */
4385 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4386 /* --------------------------------------------------------------------------
4387      When application is loaded, terminate event loop in ns_term_init
4388    -------------------------------------------------------------------------- */
4390   NSTRACE (applicationDidFinishLaunching);
4391   [NSApp setServicesProvider: NSApp];
4392   ns_send_appdefined (-2);
4396 /* Termination sequences:
4397     C-x C-c:
4398     Cmd-Q:
4399     MenuBar | File | Exit:
4400     Select Quit from App menubar:
4401         -terminate
4402         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4403         ns_term_shutdown()
4405     Select Quit from Dock menu:
4406     Logout attempt:
4407         -appShouldTerminate
4408           Cancel -> Nothing else
4409           Accept ->
4411           -terminate
4412           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4413           ns_term_shutdown()
4417 - (void) terminate: (id)sender
4419   struct frame *emacsframe = SELECTED_FRAME ();
4421   if (!emacs_event)
4422     return;
4424   emacs_event->kind = NS_NONKEY_EVENT;
4425   emacs_event->code = KEY_NS_POWER_OFF;
4426   emacs_event->arg = Qt; /* mark as non-key event */
4427   EV_TRAILER ((id)nil);
4431 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4433   int ret;
4435   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4436     return NSTerminateNow;
4438     ret = NSRunAlertPanel(ns_app_name,
4439                           [NSString stringWithUTF8String:"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?"],
4440                           @"Save Buffers and Exit", @"Cancel", nil);
4442     if (ret == NSAlertDefaultReturn)
4443         return NSTerminateNow;
4444     else if (ret == NSAlertAlternateReturn)
4445         return NSTerminateCancel;
4446     return NSTerminateNow;  /* just in case */
4450 /*   Notification from the Workspace to open a file */
4451 - (BOOL)application: sender openFile: (NSString *)file
4453   [ns_pending_files addObject: file];
4454   return YES;
4458 /*   Open a file as a temporary file */
4459 - (BOOL)application: sender openTempFile: (NSString *)file
4461   [ns_pending_files addObject: file];
4462   return YES;
4466 /*   Notification from the Workspace to open a file noninteractively (?) */
4467 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4469   [ns_pending_files addObject: file];
4470   return YES;
4474 /*   Notification from the Workspace to open multiple files */
4475 - (void)application: sender openFiles: (NSArray *)fileList
4477   NSEnumerator *files = [fileList objectEnumerator];
4478   NSString *file;
4479   while ((file = [files nextObject]) != nil)
4480     [ns_pending_files addObject: file];
4482   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4487 /* Handle dock menu requests.  */
4488 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4490   return dockMenu;
4494 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4495 - (void)applicationWillBecomeActive: (NSNotification *)notification
4497   //ns_app_active=YES;
4499 - (void)applicationDidBecomeActive: (NSNotification *)notification
4501   NSTRACE (applicationDidBecomeActive);
4503   //ns_app_active=YES;
4505   ns_update_auto_hide_menu_bar ();
4506   // No constrining takes place when the application is not active.
4507   ns_constrain_all_frames ();
4509 - (void)applicationDidResignActive: (NSNotification *)notification
4511   //ns_app_active=NO;
4512   ns_send_appdefined (-1);
4517 /* ==========================================================================
4519     EmacsApp aux handlers for managing event loop
4521    ========================================================================== */
4524 - (void)timeout_handler: (NSTimer *)timedEntry
4525 /* --------------------------------------------------------------------------
4526      The timeout specified to ns_select has passed.
4527    -------------------------------------------------------------------------- */
4529   /*NSTRACE (timeout_handler); */
4530   ns_send_appdefined (-2);
4533 - (void)fd_handler: (NSTimer *) fdEntry
4534 /* --------------------------------------------------------------------------
4535      Check data waiting on file descriptors and terminate if so
4536    -------------------------------------------------------------------------- */
4538   int result;
4539   /* NSTRACE (fd_handler); */
4541   if (select_nfds == 0)
4542     return;
4544   memcpy (&t_readfds, &select_readfds, sizeof (fd_set));
4546   select_timeout.tv_sec = select_timeout.tv_usec = 0;
4547   result = select (select_nfds, &t_readfds, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
4548                   &select_timeout);
4549   if (result)
4550     {
4551       memcpy (&select_readfds, &t_readfds, sizeof (fd_set));
4552       ns_send_appdefined (result);
4553     }
4558 /* ==========================================================================
4560     Service provision
4562    ========================================================================== */
4564 /* called from system: queue for next pass through event loop */
4565 - (void)requestService: (NSPasteboard *)pboard
4566               userData: (NSString *)userData
4567                  error: (NSString **)error
4569   [ns_pending_service_names addObject: userData];
4570   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4571       SDATA (ns_string_from_pasteboard (pboard))]];
4575 /* called from ns_read_socket to clear queue */
4576 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4578   struct frame *emacsframe = SELECTED_FRAME ();
4579   NSEvent *theEvent = [NSApp currentEvent];
4581   if (!emacs_event)
4582     return NO;
4584   emacs_event->kind = NS_NONKEY_EVENT;
4585   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4586   ns_input_spi_name = build_string ([name UTF8String]);
4587   ns_input_spi_arg = build_string ([arg UTF8String]);
4588   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4589   EV_TRAILER (theEvent);
4591   return YES;
4595 @end  /* EmacsApp */
4599 /* ==========================================================================
4601     EmacsView implementation
4603    ========================================================================== */
4606 @implementation EmacsView
4608 /* needed to inform when window closed from LISP */
4609 - (void) setWindowClosing: (BOOL)closing
4611   windowClosing = closing;
4615 - (void)dealloc
4617   NSTRACE (EmacsView_dealloc);
4618   [toolbar release];
4619   [super dealloc];
4623 /* called on font panel selection */
4624 - (void)changeFont: (id)sender
4626   NSEvent *e =[[self window] currentEvent];
4627   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4628   id newFont;
4629   float size;
4631   NSTRACE (changeFont);
4632   if (!emacs_event)
4633     return;
4635   if (newFont = [sender convertFont:
4636                            ((struct nsfont_info *)face->font)->nsfont])
4637     {
4638       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4640       emacs_event->kind = NS_NONKEY_EVENT;
4641       emacs_event->modifiers = 0;
4642       emacs_event->code = KEY_NS_CHANGE_FONT;
4644       size = [newFont pointSize];
4645       ns_input_fontsize = make_number (lrint (size));
4646       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4647       EV_TRAILER (e);
4648     }
4652 - (BOOL)acceptsFirstResponder
4654   NSTRACE (acceptsFirstResponder);
4655   return YES;
4659 - (void)resetCursorRects
4661   NSRect visible = [self visibleRect];
4662   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4663   NSTRACE (resetCursorRects);
4665   if (currentCursor == nil)
4666     currentCursor = [NSCursor arrowCursor];
4668   if (!NSIsEmptyRect (visible))
4669     [self addCursorRect: visible cursor: currentCursor];
4670   [currentCursor setOnMouseEntered: YES];
4675 /*****************************************************************************/
4676 /* Keyboard handling. */
4677 #define NS_KEYLOG 0
4679 - (void)keyDown: (NSEvent *)theEvent
4681   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4682   int code;
4683   unsigned fnKeysym = 0;
4684   int flags;
4685   static NSMutableArray *nsEvArray;
4686 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4687   static BOOL firstTime = YES;
4688 #endif
4689   int left_is_none;
4691   NSTRACE (keyDown);
4693   /* Rhapsody and OS X give up and down events for the arrow keys */
4694   if (ns_fake_keydown == YES)
4695     ns_fake_keydown = NO;
4696   else if ([theEvent type] != NSKeyDown)
4697     return;
4699   if (!emacs_event)
4700     return;
4702  if (![[self window] isKeyWindow]
4703      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4704      /* we must avoid an infinite loop here. */
4705      && (EmacsView *)[[theEvent window] delegate] != self)
4706    {
4707      /* XXX: There is an occasional condition in which, when Emacs display
4708          updates a different frame from the current one, and temporarily
4709          selects it, then processes some interrupt-driven input
4710          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4711          for some reason that window has its first responder set to the NSView
4712          most recently updated (I guess), which is not the correct one. */
4713      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4714      return;
4715    }
4717   if (nsEvArray == nil)
4718     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4720   [NSCursor setHiddenUntilMouseMoves: YES];
4722   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4723     {
4724       clear_mouse_face (hlinfo);
4725       hlinfo->mouse_face_hidden = 1;
4726     }
4728   if (!processingCompose)
4729     {
4730       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4731         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4732       /* (Carbon way: [theEvent keyCode]) */
4734       /* is it a "function key"? */
4735       fnKeysym = ns_convert_key (code);
4736       if (fnKeysym)
4737         {
4738           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4739              because Emacs treats Delete and KP-Delete same (in simple.el). */
4740           if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4741             code = 0xFF08; /* backspace */
4742           else
4743             code = fnKeysym;
4744         }
4746       /* are there modifiers? */
4747       emacs_event->modifiers = 0;
4748       flags = [theEvent modifierFlags];
4750       if (flags & NSHelpKeyMask)
4751           emacs_event->modifiers |= hyper_modifier;
4753       if (flags & NSShiftKeyMask)
4754         emacs_event->modifiers |= shift_modifier;
4756       if ((flags & NSRightCommandKeyMask) == NSRightCommandKeyMask)
4757         emacs_event->modifiers |= parse_solitary_modifier
4758           (EQ (ns_right_command_modifier, Qleft)
4759            ? ns_command_modifier
4760            : ns_right_command_modifier);
4762       if ((flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask)
4763         {
4764           emacs_event->modifiers |= parse_solitary_modifier
4765             (ns_command_modifier);
4767           /* if super (default), take input manager's word so things like
4768              dvorak / qwerty layout work */
4769           if (EQ (ns_command_modifier, Qsuper)
4770               && !fnKeysym
4771               && [[theEvent characters] length] != 0)
4772             {
4773               /* XXX: the code we get will be unshifted, so if we have
4774                  a shift modifier, must convert ourselves */
4775               if (!(flags & NSShiftKeyMask))
4776                 code = [[theEvent characters] characterAtIndex: 0];
4777 #if 0
4778               /* this is ugly and also requires linking w/Carbon framework
4779                  (for LMGetKbdType) so for now leave this rare (?) case
4780                  undealt with.. in future look into CGEvent methods */
4781               else
4782                 {
4783                   long smv = GetScriptManagerVariable (smKeyScript);
4784                   Handle uchrHandle = GetResource
4785                     ('uchr', GetScriptVariable (smv, smScriptKeys));
4786                   UInt32 dummy = 0;
4787                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
4788                                  [[theEvent characters] characterAtIndex: 0],
4789                                  kUCKeyActionDisplay,
4790                                  (flags & ~NSCommandKeyMask) >> 8,
4791                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
4792                                  &dummy, 1, &dummy, &code);
4793                   code &= 0xFF;
4794                 }
4795 #endif
4796             }
4797         }
4799       if ((flags & NSRightControlKeyMask) == NSRightControlKeyMask)
4800           emacs_event->modifiers |= parse_solitary_modifier
4801               (EQ (ns_right_control_modifier, Qleft)
4802                ? ns_control_modifier
4803                : ns_right_control_modifier);
4805       if ((flags & NSLeftControlKeyMask) == NSLeftControlKeyMask)
4806         emacs_event->modifiers |= parse_solitary_modifier
4807           (ns_control_modifier);
4809       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
4810           emacs_event->modifiers |=
4811             parse_solitary_modifier (ns_function_modifier);
4813       left_is_none = NILP (ns_alternate_modifier)
4814         || EQ (ns_alternate_modifier, Qnone);
4816       if ((flags & NSRightAlternateKeyMask) == NSRightAlternateKeyMask)
4817         {
4818           if ((NILP (ns_right_alternate_modifier)
4819                || EQ (ns_right_alternate_modifier, Qnone)
4820                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
4821               && !fnKeysym)
4822             {   /* accept pre-interp alt comb */
4823               if ([[theEvent characters] length] > 0)
4824                 code = [[theEvent characters] characterAtIndex: 0];
4825               /*HACK: clear lone shift modifier to stop next if from firing */
4826               if (emacs_event->modifiers == shift_modifier)
4827                 emacs_event->modifiers = 0;
4828             }
4829           else
4830             emacs_event->modifiers |= parse_solitary_modifier
4831               (EQ (ns_right_alternate_modifier, Qleft)
4832                ? ns_alternate_modifier
4833                : ns_right_alternate_modifier);
4834         }
4836       if ((flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask) /* default = meta */
4837         {
4838           if (left_is_none && !fnKeysym)
4839             {   /* accept pre-interp alt comb */
4840               if ([[theEvent characters] length] > 0)
4841                 code = [[theEvent characters] characterAtIndex: 0];
4842               /*HACK: clear lone shift modifier to stop next if from firing */
4843               if (emacs_event->modifiers == shift_modifier)
4844                 emacs_event->modifiers = 0;
4845             }
4846           else
4847               emacs_event->modifiers |=
4848                 parse_solitary_modifier (ns_alternate_modifier);
4849         }
4851   if (NS_KEYLOG)
4852     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
4853              code, fnKeysym, flags, emacs_event->modifiers);
4855       /* if it was a function key or had modifiers, pass it directly to emacs */
4856       if (fnKeysym || (emacs_event->modifiers
4857                        && (emacs_event->modifiers != shift_modifier)
4858                        && [[theEvent charactersIgnoringModifiers] length] > 0))
4859 /*[[theEvent characters] length] */
4860         {
4861           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4862           if (code < 0x20)
4863             code |= (1<<28)|(3<<16);
4864           else if (code == 0x7f)
4865             code |= (1<<28)|(3<<16);
4866           else if (!fnKeysym)
4867             emacs_event->kind = code > 0xFF
4868               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4870           emacs_event->code = code;
4871           EV_TRAILER (theEvent);
4872           return;
4873         }
4874     }
4877 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4878   /* if we get here we should send the key for input manager processing */
4879   if (firstTime && [[NSInputManager currentInputManager]
4880                      wantsToDelayTextChangeNotifications] == NO)
4881     fprintf (stderr,
4882           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
4883   firstTime = NO;
4884 #endif
4885   if (NS_KEYLOG && !processingCompose)
4886     fprintf (stderr, "keyDown: Begin compose sequence.\n");
4888   processingCompose = YES;
4889   [nsEvArray addObject: theEvent];
4890   [self interpretKeyEvents: nsEvArray];
4891   [nsEvArray removeObject: theEvent];
4895 #ifdef NS_IMPL_COCOA
4896 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
4897    decided not to send key-down for.
4898    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
4899    This only applies on Tiger and earlier.
4900    If it matches one of these, send it on to keyDown. */
4901 -(void)keyUp: (NSEvent *)theEvent
4903   int flags = [theEvent modifierFlags];
4904   int code = [theEvent keyCode];
4905   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
4906       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
4907     {
4908       if (NS_KEYLOG)
4909         fprintf (stderr, "keyUp: passed test");
4910       ns_fake_keydown = YES;
4911       [self keyDown: theEvent];
4912     }
4914 #endif
4917 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
4920 /* <NSTextInput>: called when done composing;
4921    NOTE: also called when we delete over working text, followed immed.
4922          by doCommandBySelector: deleteBackward: */
4923 - (void)insertText: (id)aString
4925   int code;
4926   int len = [(NSString *)aString length];
4927   int i;
4929   if (NS_KEYLOG)
4930     NSLog (@"insertText '%@'\tlen = %d", aString, len);
4931   processingCompose = NO;
4933   if (!emacs_event)
4934     return;
4936   /* first, clear any working text */
4937   if (workingText != nil)
4938     [self deleteWorkingText];
4940   /* now insert the string as keystrokes */
4941   for (i =0; i<len; i++)
4942     {
4943       code = [aString characterAtIndex: i];
4944       /* TODO: still need this? */
4945       if (code == 0x2DC)
4946         code = '~'; /* 0x7E */
4947       emacs_event->modifiers = 0;
4948       emacs_event->kind
4949         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4950       emacs_event->code = code;
4951       EV_TRAILER ((id)nil);
4952     }
4956 /* <NSTextInput>: inserts display of composing characters */
4957 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
4959   NSString *str = [aString respondsToSelector: @selector (string)] ?
4960     [aString string] : aString;
4961   if (NS_KEYLOG)
4962     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
4963            selRange.length, selRange.location);
4965   if (workingText != nil)
4966     [self deleteWorkingText];
4967   if ([str length] == 0)
4968     return;
4970   if (!emacs_event)
4971     return;
4973   processingCompose = YES;
4974   workingText = [str copy];
4975   ns_working_text = build_string ([workingText UTF8String]);
4977   emacs_event->kind = NS_TEXT_EVENT;
4978   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
4979   EV_TRAILER ((id)nil);
4983 /* delete display of composing characters [not in <NSTextInput>] */
4984 - (void)deleteWorkingText
4986   if (workingText == nil)
4987     return;
4988   if (NS_KEYLOG)
4989     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
4990   [workingText release];
4991   workingText = nil;
4992   processingCompose = NO;
4994   if (!emacs_event)
4995     return;
4997   emacs_event->kind = NS_TEXT_EVENT;
4998   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
4999   EV_TRAILER ((id)nil);
5003 - (BOOL)hasMarkedText
5005   return workingText != nil;
5009 - (NSRange)markedRange
5011   NSRange rng = workingText != nil
5012     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5013   if (NS_KEYLOG)
5014     NSLog (@"markedRange request");
5015   return rng;
5019 - (void)unmarkText
5021   if (NS_KEYLOG)
5022     NSLog (@"unmark (accept) text");
5023   [self deleteWorkingText];
5024   processingCompose = NO;
5028 /* used to position char selection windows, etc. */
5029 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5031   NSRect rect;
5032   NSPoint pt;
5033   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5034   if (NS_KEYLOG)
5035     NSLog (@"firstRectForCharRange request");
5037   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5038   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5039   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5040   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5041                                        +FRAME_LINE_HEIGHT (emacsframe));
5043   pt = [self convertPoint: pt toView: nil];
5044   pt = [[self window] convertBaseToScreen: pt];
5045   rect.origin = pt;
5046   return rect;
5050 - (long)conversationIdentifier
5052   return (long)self;
5056 - (void)doCommandBySelector: (SEL)aSelector
5058   if (NS_KEYLOG)
5059     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5061   if (aSelector == @selector (deleteBackward:))
5062     {
5063       /* happens when user backspaces over an ongoing composition:
5064          throw a 'delete' into the event queue */
5065       if (!emacs_event)
5066         return;
5067       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5068       emacs_event->code = 0xFF08;
5069       EV_TRAILER ((id)nil);
5070     }
5073 - (NSArray *)validAttributesForMarkedText
5075   static NSArray *arr = nil;
5076   if (arr == nil) arr = [NSArray new];
5077  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5078   return arr;
5081 - (NSRange)selectedRange
5083   if (NS_KEYLOG)
5084     NSLog (@"selectedRange request");
5085   return NSMakeRange (NSNotFound, 0);
5088 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5090   if (NS_KEYLOG)
5091     NSLog (@"characterIndexForPoint request");
5092   return 0;
5095 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5097   static NSAttributedString *str = nil;
5098   if (str == nil) str = [NSAttributedString new];
5099   if (NS_KEYLOG)
5100     NSLog (@"attributedSubstringFromRange request");
5101   return str;
5104 /* End <NSTextInput> impl. */
5105 /*****************************************************************************/
5108 /* This is what happens when the user presses a mouse button.  */
5109 - (void)mouseDown: (NSEvent *)theEvent
5111   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5112   Lisp_Object window;
5114   NSTRACE (mouseDown);
5116   [self deleteWorkingText];
5118   if (!emacs_event)
5119     return;
5121   last_mouse_frame = emacsframe;
5122   /* appears to be needed to prevent spurious movement events generated on
5123      button clicks */
5124   last_mouse_frame->mouse_moved = 0;
5126   if ([theEvent type] == NSScrollWheel)
5127     {
5128       float delta = [theEvent deltaY];
5129       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5130       if (delta == 0)
5131         return;
5132       emacs_event->kind = WHEEL_EVENT;
5133       emacs_event->code = 0;
5134       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5135         ((delta > 0) ? up_modifier : down_modifier);
5136     }
5137   else
5138     {
5139       emacs_event->kind = MOUSE_CLICK_EVENT;
5140       emacs_event->code = EV_BUTTON (theEvent);
5141       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5142                              | EV_UDMODIFIERS (theEvent);
5143     }
5144   XSETINT (emacs_event->x, lrint (p.x));
5145   XSETINT (emacs_event->y, lrint (p.y));
5146   EV_TRAILER (theEvent);
5150 - (void)rightMouseDown: (NSEvent *)theEvent
5152   NSTRACE (rightMouseDown);
5153   [self mouseDown: theEvent];
5157 - (void)otherMouseDown: (NSEvent *)theEvent
5159   NSTRACE (otherMouseDown);
5160   [self mouseDown: theEvent];
5164 - (void)mouseUp: (NSEvent *)theEvent
5166   NSTRACE (mouseUp);
5167   [self mouseDown: theEvent];
5171 - (void)rightMouseUp: (NSEvent *)theEvent
5173   NSTRACE (rightMouseUp);
5174   [self mouseDown: theEvent];
5178 - (void)otherMouseUp: (NSEvent *)theEvent
5180   NSTRACE (otherMouseUp);
5181   [self mouseDown: theEvent];
5185 - (void) scrollWheel: (NSEvent *)theEvent
5187   NSTRACE (scrollWheel);
5188   [self mouseDown: theEvent];
5192 /* Tell emacs the mouse has moved. */
5193 - (void)mouseMoved: (NSEvent *)e
5195   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5196   Lisp_Object frame;
5198 //  NSTRACE (mouseMoved);
5200   last_mouse_movement_time = EV_TIMESTAMP (e);
5201   last_mouse_motion_position
5202     = [self convertPoint: [e locationInWindow] fromView: nil];
5204   /* update any mouse face */
5205   if (hlinfo->mouse_face_hidden)
5206     {
5207       hlinfo->mouse_face_hidden = 0;
5208       clear_mouse_face (hlinfo);
5209     }
5211   /* tooltip handling */
5212   previous_help_echo_string = help_echo_string;
5213   help_echo_string = Qnil;
5215   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
5216                             last_mouse_motion_position.y))
5217     help_echo_string = previous_help_echo_string;
5219   XSETFRAME (frame, emacsframe);
5220   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5221     {
5222       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5223          (note_mouse_highlight), which is called through the
5224          note_mouse_movement () call above */
5225       gen_help_event (help_echo_string, frame, help_echo_window,
5226                       help_echo_object, help_echo_pos);
5227     }
5228   else
5229     {
5230       help_echo_string = Qnil;
5231       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5232     }
5234   if (emacsframe->mouse_moved && send_appdefined)
5235     ns_send_appdefined (-1);
5239 - (void)mouseDragged: (NSEvent *)e
5241   NSTRACE (mouseDragged);
5242   [self mouseMoved: e];
5246 - (void)rightMouseDragged: (NSEvent *)e
5248   NSTRACE (rightMouseDragged);
5249   [self mouseMoved: e];
5253 - (void)otherMouseDragged: (NSEvent *)e
5255   NSTRACE (otherMouseDragged);
5256   [self mouseMoved: e];
5260 - (BOOL)windowShouldClose: (id)sender
5262   NSEvent *e =[[self window] currentEvent];
5264   NSTRACE (windowShouldClose);
5265   windowClosing = YES;
5266   if (!emacs_event)
5267     return NO;
5268   emacs_event->kind = DELETE_WINDOW_EVENT;
5269   emacs_event->modifiers = 0;
5270   emacs_event->code = 0;
5271   EV_TRAILER (e);
5272   /* Don't close this window, let this be done from lisp code.  */
5273   return NO;
5277 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5278 /* normalize frame to gridded text size */
5280   NSTRACE (windowWillResize);
5281 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5283   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5284 #ifdef NS_IMPL_GNUSTEP
5285                                         frameSize.width + 3);
5286 #else
5287                                         frameSize.width);
5288 #endif
5289   if (cols < MINWIDTH)
5290     cols = MINWIDTH;
5292   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, frameSize.height
5293 #ifdef NS_IMPL_GNUSTEP
5294       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + 3
5295         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5296 #else
5297       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5298         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5299 #endif
5300   if (rows < MINHEIGHT)
5301     rows = MINHEIGHT;
5302 #ifdef NS_IMPL_COCOA
5303   {
5304     /* this sets window title to have size in it; the wm does this under GS */
5305     NSRect r = [[self window] frame];
5306     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5307       {
5308         if (old_title != 0)
5309           {
5310             xfree (old_title);
5311             old_title = 0;
5312           }
5313       }
5314     else
5315       {
5316         char *size_title;
5317         NSWindow *window = [self window];
5318         if (old_title == 0)
5319           {
5320             const char *t = [[[self window] title] UTF8String];
5321             char *pos = strstr (t, "  â€”  ");
5322             if (pos)
5323               *pos = '\0';
5324             old_title = (char *) xmalloc (strlen (t) + 1);
5325             strcpy (old_title, t);
5326           }
5327         size_title = xmalloc (strlen (old_title) + 40);
5328         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5329         [window setTitle: [NSString stringWithUTF8String: size_title]];
5330         [window display];
5331         xfree (size_title);
5332       }
5333   }
5334 #endif /* NS_IMPL_COCOA */
5335 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5337   return frameSize;
5341 - (void)windowDidResize: (NSNotification *)notification
5343   NSWindow *theWindow = [notification object];
5345 #ifdef NS_IMPL_GNUSTEP
5346    /* in GNUstep, at least currently, it's possible to get a didResize
5347       without getting a willResize.. therefore we need to act as if we got
5348       the willResize now */
5349   NSSize sz = [theWindow frame].size;
5350   sz = [self windowWillResize: theWindow toSize: sz];
5351 #endif /* NS_IMPL_GNUSTEP */
5353   NSTRACE (windowDidResize);
5354 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5356 #ifdef NS_IMPL_COCOA
5357   if (old_title != 0)
5358     {
5359       xfree (old_title);
5360       old_title = 0;
5361     }
5362 #endif /* NS_IMPL_COCOA */
5364   /* Avoid loop under GNUstep due to call at beginning of this function.
5365      (x_set_window_size causes a resize which causes
5366      a "windowDidResize" which calls x_set_window_size).  */
5367 #ifndef NS_IMPL_GNUSTEP
5368   if (cols > 0 && rows > 0)
5369     {
5370       if (ns_in_resize)
5371         x_set_window_size (emacsframe, 0, cols, rows);
5372       else
5373         {
5374           NSWindow *window = [self window];
5375           NSRect wr = [window frame];
5376           FRAME_PIXEL_WIDTH (emacsframe) = (int)wr.size.width
5377             - emacsframe->border_width;
5378           FRAME_PIXEL_HEIGHT (emacsframe) = (int)wr.size.height
5379             - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5380             - FRAME_TOOLBAR_HEIGHT (emacsframe);
5381           change_frame_size (emacsframe, rows, cols, 0, 0, 1);
5382           SET_FRAME_GARBAGED (emacsframe);
5383           cancel_mouse_face (emacsframe);
5384         }
5385     }
5386 #endif
5388   ns_send_appdefined (-1);
5392 - (void)windowDidBecomeKey: (NSNotification *)notification
5393 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5395   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5396   struct frame *old_focus = dpyinfo->x_focus_frame;
5398   NSTRACE (windowDidBecomeKey);
5400   if (emacsframe != old_focus)
5401     dpyinfo->x_focus_frame = emacsframe;
5403   ns_frame_rehighlight (emacsframe);
5405   if (emacs_event)
5406     {
5407       emacs_event->kind = FOCUS_IN_EVENT;
5408       EV_TRAILER ((id)nil);
5409     }
5413 - (void)windowDidResignKey: (NSNotification *)notification
5414 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5416   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5417   NSTRACE (windowDidResignKey);
5419   if (dpyinfo->x_focus_frame == emacsframe)
5420     dpyinfo->x_focus_frame = 0;
5422   ns_frame_rehighlight (emacsframe);
5424   /* FIXME: for some reason needed on second and subsequent clicks away
5425             from sole-frame Emacs to get hollow box to show */
5426   if (!windowClosing && [[self window] isVisible] == YES)
5427     {
5428       x_update_cursor (emacsframe, 1);
5429       x_set_frame_alpha (emacsframe);
5430     }
5432   if (emacs_event)
5433     {
5434       [self deleteWorkingText];
5435       emacs_event->kind = FOCUS_IN_EVENT;
5436       EV_TRAILER ((id)nil);
5437     }
5441 - (void)windowWillMiniaturize: sender
5443   NSTRACE (windowWillMiniaturize);
5447 - (BOOL)isFlipped
5449   return YES;
5453 - (BOOL)isOpaque
5455   return NO;
5459 - initFrameFromEmacs: (struct frame *)f
5461   NSRect r, wr;
5462   Lisp_Object tem;
5463   NSWindow *win;
5464   NSButton *toggleButton;
5465   int vbextra = NS_SCROLL_BAR_WIDTH (f);
5466   NSSize sz;
5467   NSColor *col;
5468   NSString *name;
5470   NSTRACE (initFrameFromEmacs);
5472   windowClosing = NO;
5473   processingCompose = NO;
5474   scrollbarsNeedingUpdate = 0;
5476 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5478   ns_userRect = NSMakeRect (0, 0, 0, 0);
5479   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5480                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5481   [self initWithFrame: r];
5482   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5484   FRAME_NS_VIEW (f) = self;
5485   emacsframe = f;
5486   old_title = 0;
5488   win = [[EmacsWindow alloc]
5489             initWithContentRect: r
5490                       styleMask: (NSResizableWindowMask |
5491 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5492                                   NSTitledWindowMask |
5493 #endif
5494                                   NSMiniaturizableWindowMask |
5495                                   NSClosableWindowMask)
5496                         backing: NSBackingStoreBuffered
5497                           defer: YES];
5499   wr = [win frame];
5500   f->border_width = wr.size.width - r.size.width;
5501   FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5503   [win setAcceptsMouseMovedEvents: YES];
5504   [win setDelegate: self];
5505   [win useOptimizedDrawing: YES];
5507   sz.width = FRAME_COLUMN_WIDTH (f);
5508   sz.height = FRAME_LINE_HEIGHT (f);
5509   [win setResizeIncrements: sz];
5511   [[win contentView] addSubview: self];
5513   if (ns_drag_types)
5514     [self registerForDraggedTypes: ns_drag_types];
5516   tem = f->name;
5517   name = [NSString stringWithUTF8String:
5518                    NILP (tem) ? (unsigned char *)"Emacs" : SDATA (tem)];
5519   [win setTitle: name];
5521   /* toolbar support */
5522   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5523                          [NSString stringWithFormat: @"Emacs Frame %d",
5524                                    ns_window_num]];
5525   [win setToolbar: toolbar];
5526   [toolbar setVisible: NO];
5527 #ifdef NS_IMPL_COCOA
5528   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5529   [toggleButton setTarget: self];
5530   [toggleButton setAction: @selector (toggleToolbar: )];
5531 #endif
5532   FRAME_TOOLBAR_HEIGHT (f) = 0;
5534   tem = f->icon_name;
5535   if (!NILP (tem))
5536     [win setMiniwindowTitle:
5537            [NSString stringWithUTF8String: SDATA (tem)]];
5539   {
5540     NSScreen *screen = [win screen];
5542     if (screen != 0)
5543       [win setFrameTopLeftPoint: NSMakePoint
5544            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5545             IN_BOUND (-SCREENMAX,
5546                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5547   }
5549   [win makeFirstResponder: self];
5551   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5552                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5553   [win setBackgroundColor: col];
5554   if ([col alphaComponent] != 1.0)
5555     [win setOpaque: NO];
5557   [self allocateGState];
5559   [NSApp registerServicesMenuSendTypes: ns_send_types
5560                            returnTypes: nil];
5562   ns_window_num++;
5563   return self;
5567 - (void)windowDidMove: sender
5569   NSWindow *win = [self window];
5570   NSRect r = [win frame];
5571   NSArray *screens = [NSScreen screens];
5572   NSScreen *screen = [screens objectAtIndex: 0];
5574   NSTRACE (windowDidMove);
5576   if (!emacsframe->output_data.ns)
5577     return;
5578   if (screen != nil)
5579     {
5580       emacsframe->left_pos = r.origin.x;
5581       emacsframe->top_pos =
5582         [screen frame].size.height - (r.origin.y + r.size.height);
5583     }
5587 /* Called AFTER method below, but before our windowWillResize call there leads
5588    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5589    location so set_window_size moves the frame. */
5590 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5592   emacsframe->output_data.ns->zooming = 1;
5593   return YES;
5597 /* Override to do something slightly nonstandard, but nice.  First click on
5598    zoom button will zoom vertically.  Second will zoom completely.  Third
5599    returns to original. */
5600 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5601                         defaultFrame:(NSRect)defaultFrame
5603   NSRect result = [sender frame];
5605   NSTRACE (windowWillUseStandardFrame);
5607   if (abs (defaultFrame.size.height - result.size.height)
5608       > FRAME_LINE_HEIGHT (emacsframe))
5609     {
5610       /* first click */
5611       ns_userRect = result;
5612       result.size.height = defaultFrame.size.height;
5613       result.origin.y = defaultFrame.origin.y;
5614     }
5615   else
5616     {
5617       if (abs (defaultFrame.size.width - result.size.width)
5618           > FRAME_COLUMN_WIDTH (emacsframe))
5619         result = defaultFrame;  /* second click */
5620       else
5621         {
5622           /* restore */
5623           result = ns_userRect.size.height ? ns_userRect : result;
5624           ns_userRect = NSMakeRect (0, 0, 0, 0);
5625         }
5626     }
5628   [self windowWillResize: sender toSize: result.size];
5629   return result;
5633 - (void)windowDidDeminiaturize: sender
5635   NSTRACE (windowDidDeminiaturize);
5636   if (!emacsframe->output_data.ns)
5637     return;
5638   emacsframe->async_iconified = 0;
5639   emacsframe->async_visible   = 1;
5640   windows_or_buffers_changed++;
5642   if (emacs_event)
5643     {
5644       emacs_event->kind = ICONIFY_EVENT;
5645       EV_TRAILER ((id)nil);
5646     }
5650 - (void)windowDidExpose: sender
5652   NSTRACE (windowDidExpose);
5653   if (!emacsframe->output_data.ns)
5654     return;
5655   emacsframe->async_visible = 1;
5656   SET_FRAME_GARBAGED (emacsframe);
5658   if (send_appdefined)
5659     ns_send_appdefined (-1);
5663 - (void)windowDidMiniaturize: sender
5665   NSTRACE (windowDidMiniaturize);
5666   if (!emacsframe->output_data.ns)
5667     return;
5669   emacsframe->async_iconified = 1;
5670   emacsframe->async_visible = 0;
5672   if (emacs_event)
5673     {
5674       emacs_event->kind = ICONIFY_EVENT;
5675       EV_TRAILER ((id)nil);
5676     }
5680 - (void)mouseEntered: (NSEvent *)theEvent
5682   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5683   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5684   NSTRACE (mouseEntered);
5686   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5690 - (void)mouseExited: (NSEvent *)theEvent
5692   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5693   NSRect r;
5694   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
5696   NSTRACE (mouseExited);
5698   if (!hlinfo)
5699     return;
5701   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5703   if (emacsframe == hlinfo->mouse_face_mouse_frame)
5704     {
5705       clear_mouse_face (hlinfo);
5706       hlinfo->mouse_face_mouse_frame = 0;
5707     }
5711 - menuDown: sender
5713   NSTRACE (menuDown);
5714   if (context_menu_value == -1)
5715     context_menu_value = [sender tag];
5716   else
5717     find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
5718                                   emacsframe->menu_bar_vector,
5719                                   (void *)[sender tag]);
5720   ns_send_appdefined (-1);
5721   return self;
5725 - (EmacsToolbar *)toolbar
5727   return toolbar;
5731 /* this gets called on toolbar button click */
5732 - toolbarClicked: (id)item
5734   NSEvent *theEvent;
5735   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
5737   NSTRACE (toolbarClicked);
5739   if (!emacs_event)
5740     return self;
5742   /* send first event (for some reason two needed) */
5743   theEvent = [[self window] currentEvent];
5744   emacs_event->kind = TOOL_BAR_EVENT;
5745   XSETFRAME (emacs_event->arg, emacsframe);
5746   EV_TRAILER (theEvent);
5748   emacs_event->kind = TOOL_BAR_EVENT;
5749 /*   XSETINT (emacs_event->code, 0); */
5750   emacs_event->arg = AREF (emacsframe->tool_bar_items,
5751                           idx + TOOL_BAR_ITEM_KEY);
5752   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5753   EV_TRAILER (theEvent);
5754   return self;
5758 - toggleToolbar: (id)sender
5760   if (!emacs_event)
5761     return self;
5763   emacs_event->kind = NS_NONKEY_EVENT;
5764   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
5765   EV_TRAILER ((id)nil);
5766   return self;
5770 - (void)drawRect: (NSRect)rect
5772   int x = NSMinX (rect), y = NSMinY (rect);
5773   int width = NSWidth (rect), height = NSHeight (rect);
5775   NSTRACE (drawRect);
5777   if (!emacsframe || !emacsframe->output_data.ns || ns_in_resize)
5778     return;
5780   ns_clear_frame_area (emacsframe, x, y, width, height);
5781   expose_frame (emacsframe, x, y, width, height);
5783   /*
5784     drawRect: may be called (at least in OS X 10.5) for invisible
5785     views as well for some reason.  Thus, do not infer visibility
5786     here.
5788     emacsframe->async_visible = 1;
5789     emacsframe->async_iconified = 0;
5790   */
5794 /* NSDraggingDestination protocol methods.  Actually this is not really a
5795    protocol, but a category of Object.  O well...  */
5797 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
5799   NSTRACE (draggingEntered);
5800   return NSDragOperationGeneric;
5804 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
5806   return YES;
5810 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
5812   id pb;
5813   int x, y;
5814   NSString *type;
5815   NSEvent *theEvent = [[self window] currentEvent];
5816   NSPoint position;
5818   NSTRACE (performDragOperation);
5820   if (!emacs_event)
5821     return NO;
5823   position = [self convertPoint: [sender draggingLocation] fromView: nil];
5824   x = lrint (position.x);  y = lrint (position.y);
5826   pb = [sender draggingPasteboard];
5827   type = [pb availableTypeFromArray: ns_drag_types];
5828   if (type == 0)
5829     {
5830       return NO;
5831     }
5832   else if ([type isEqualToString: NSFilenamesPboardType])
5833     {
5834       NSArray *files;
5835       NSEnumerator *fenum;
5836       NSString *file;
5838       if (!(files = [pb propertyListForType: type]))
5839         return NO;
5841       fenum = [files objectEnumerator];
5842       while ( (file = [fenum nextObject]) )
5843         {
5844           emacs_event->kind = NS_NONKEY_EVENT;
5845           emacs_event->code = KEY_NS_DRAG_FILE;
5846           XSETINT (emacs_event->x, x);
5847           XSETINT (emacs_event->y, y);
5848           ns_input_file = append2 (ns_input_file,
5849                                    build_string ([file UTF8String]));
5850           emacs_event->modifiers = EV_MODIFIERS (theEvent);
5851           EV_TRAILER (theEvent);
5852         }
5853       return YES;
5854     }
5855   else if ([type isEqualToString: NSURLPboardType])
5856     {
5857       NSString *file;
5858       NSURL *fileURL;
5860       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
5861           [fileURL isFileURL] == NO)
5862         return NO;
5864       file = [fileURL path];
5865       emacs_event->kind = NS_NONKEY_EVENT;
5866       emacs_event->code = KEY_NS_DRAG_FILE;
5867       XSETINT (emacs_event->x, x);
5868       XSETINT (emacs_event->y, y);
5869       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
5870       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5871       EV_TRAILER (theEvent);
5872       return YES;
5873     }
5874   else if ([type isEqualToString: NSStringPboardType]
5875            || [type isEqualToString: NSTabularTextPboardType])
5876     {
5877       NSString *data;
5879       if (! (data = [pb stringForType: type]))
5880         return NO;
5882       emacs_event->kind = NS_NONKEY_EVENT;
5883       emacs_event->code = KEY_NS_DRAG_TEXT;
5884       XSETINT (emacs_event->x, x);
5885       XSETINT (emacs_event->y, y);
5886       ns_input_text = build_string ([data UTF8String]);
5887       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5888       EV_TRAILER (theEvent);
5889       return YES;
5890     }
5891   else if ([type isEqualToString: NSColorPboardType])
5892     {
5893       NSColor *c = [NSColor colorFromPasteboard: pb];
5894       emacs_event->kind = NS_NONKEY_EVENT;
5895       emacs_event->code = KEY_NS_DRAG_COLOR;
5896       XSETINT (emacs_event->x, x);
5897       XSETINT (emacs_event->y, y);
5898       ns_input_color = ns_color_to_lisp (c);
5899       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5900       EV_TRAILER (theEvent);
5901       return YES;
5902     }
5903   else if ([type isEqualToString: NSFontPboardType])
5904     {
5905       /* impl based on GNUstep NSTextView.m */
5906       NSData *data = [pb dataForType: NSFontPboardType];
5907       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
5908       NSFont *font = [dict objectForKey: NSFontAttributeName];
5909       char fontSize[10];
5911       if (font == nil)
5912         return NO;
5914       emacs_event->kind = NS_NONKEY_EVENT;
5915       emacs_event->code = KEY_NS_CHANGE_FONT;
5916       XSETINT (emacs_event->x, x);
5917       XSETINT (emacs_event->y, y);
5918       ns_input_font = build_string ([[font fontName] UTF8String]);
5919       snprintf (fontSize, 10, "%f", [font pointSize]);
5920       ns_input_fontsize = build_string (fontSize);
5921       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5922       EV_TRAILER (theEvent);
5923       return YES;
5924     }
5925   else
5926     {
5927       error ("Invalid data type in dragging pasteboard.");
5928       return NO;
5929     }
5933 - (id) validRequestorForSendType: (NSString *)typeSent
5934                       returnType: (NSString *)typeReturned
5936   NSTRACE (validRequestorForSendType);
5937   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
5938       && typeReturned == nil)
5939     {
5940       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
5941         return self;
5942     }
5944   return [super validRequestorForSendType: typeSent
5945                                returnType: typeReturned];
5949 /* The next two methods are part of NSServicesRequests informal protocol,
5950    supposedly called when a services menu item is chosen from this app.
5951    But this should not happen because we override the services menu with our
5952    own entries which call ns-perform-service.
5953    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
5954    So let's at least stub them out until further investigation can be done. */
5956 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
5958   /* we could call ns_string_from_pasteboard(pboard) here but then it should
5959      be written into the buffer in place of the existing selection..
5960      ordinary service calls go through functions defined in ns-win.el */
5961   return NO;
5964 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
5966   NSArray *typesDeclared;
5967   Lisp_Object val;
5969   /* We only support NSStringPboardType */
5970   if ([types containsObject:NSStringPboardType] == NO) {
5971     return NO;
5972   }
5974   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
5975   if (CONSP (val) && SYMBOLP (XCAR (val)))
5976     {
5977       val = XCDR (val);
5978       if (CONSP (val) && NILP (XCDR (val)))
5979         val = XCAR (val);
5980     }
5981   if (! STRINGP (val))
5982     return NO;
5984   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
5985   [pb declareTypes:typesDeclared owner:nil];
5986   ns_string_to_pasteboard (pb, val);
5987   return YES;
5991 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
5992    (gives a miniaturized version of the window); currently we use the latter for
5993    frames whose active buffer doesn't correspond to any file
5994    (e.g., '*scratch*') */
5995 - setMiniwindowImage: (BOOL) setMini
5997   id image = [[self window] miniwindowImage];
5998   NSTRACE (setMiniwindowImage);
6000   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6001      about "AppleDockIconEnabled" notwithstanding, however the set message
6002      below has its effect nonetheless. */
6003   if (image != emacsframe->output_data.ns->miniimage)
6004     {
6005       if (image && [image isKindOfClass: [EmacsImage class]])
6006         [image release];
6007       [[self window] setMiniwindowImage:
6008                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6009     }
6011   return self;
6015 - (void) setRows: (int) r andColumns: (int) c
6017   rows = r;
6018   cols = c;
6021 @end  /* EmacsView */
6025 /* ==========================================================================
6027     EmacsWindow implementation
6029    ========================================================================== */
6031 @implementation EmacsWindow
6033 /* If we have multiple monitors, one above the other, we don't want to
6034    restrict the height to just one monitor.  So we override this.  */
6035 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6037   /* When making the frame visible for the first time, we want to
6038      constrain.  Other times not.  */
6039   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6040   NSTRACE (constrainFrameRect);
6042   if (f->output_data.ns->dont_constrain
6043       || ns_menu_bar_should_be_hidden ())
6044     return frameRect;
6046   f->output_data.ns->dont_constrain = 1;
6047   return [super constrainFrameRect:frameRect toScreen:screen];
6051 /* called only on resize clicks by special case in EmacsApp-sendEvent */
6052 - (void)mouseDown: (NSEvent *)theEvent
6054   if (ns_in_resize)
6055     {
6056       NSSize size = [[theEvent window] frame].size;
6057       grabOffset = [theEvent locationInWindow];
6058       grabOffset.x = size.width - grabOffset.x;
6059     }
6060   else
6061     [super mouseDown: theEvent];
6065 /* stop resizing */
6066 - (void)mouseUp: (NSEvent *)theEvent
6068   if (ns_in_resize)
6069     {
6070       struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6071       ns_in_resize = NO;
6072       ns_set_name_as_filename (f);
6073       [self display];
6074       ns_send_appdefined (-1);
6075     }
6076   else
6077     [super mouseUp: theEvent];
6081 /* send resize events */
6082 - (void)mouseDragged: (NSEvent *)theEvent
6084   if (ns_in_resize)
6085     {
6086       NSPoint p = [theEvent locationInWindow];
6087       NSSize size, vettedSize, origSize = [self frame].size;
6089       size.width = p.x + grabOffset.x;
6090       size.height = origSize.height - p.y + grabOffset.y;
6092       if (size.width == origSize.width && size.height == origSize.height)
6093         return;
6095       vettedSize = [[self delegate] windowWillResize: self toSize: size];
6096       [[NSNotificationCenter defaultCenter]
6097             postNotificationName: NSWindowDidResizeNotification
6098                           object: self];
6099     }
6100   else
6101     [super mouseDragged: theEvent];
6104 @end /* EmacsWindow */
6107 /* ==========================================================================
6109     EmacsScroller implementation
6111    ========================================================================== */
6114 @implementation EmacsScroller
6116 /* for repeat button push */
6117 #define SCROLL_BAR_FIRST_DELAY 0.5
6118 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6120 + (CGFloat) scrollerWidth
6122   /* TODO: if we want to allow variable widths, this is the place to do it,
6123            however neither GNUstep nor Cocoa support it very well */
6124   return [NSScroller scrollerWidth];
6128 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6130   NSTRACE (EmacsScroller_initFrame);
6132   r.size.width = [EmacsScroller scrollerWidth];
6133   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6134   [self setContinuous: YES];
6135   [self setEnabled: YES];
6137   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6138      locked against the top and bottom edges, and right edge on OS X, where
6139      scrollers are on right. */
6140 #ifdef NS_IMPL_GNUSTEP
6141   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6142 #else
6143   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6144 #endif
6146   win = nwin;
6147   condemned = NO;
6148   pixel_height = NSHeight (r);
6149   if (pixel_height == 0) pixel_height = 1;
6150   min_portion = 20 / pixel_height;
6152   frame = XFRAME (XWINDOW (win)->frame);
6153   if (FRAME_LIVE_P (frame))
6154     {
6155       int i;
6156       EmacsView *view = FRAME_NS_VIEW (frame);
6157       NSView *sview = [[view window] contentView];
6158       NSArray *subs = [sview subviews];
6160       /* disable optimization stopping redraw of other scrollbars */
6161       view->scrollbarsNeedingUpdate = 0;
6162       for (i =[subs count]-1; i >= 0; i--)
6163         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6164           view->scrollbarsNeedingUpdate++;
6165       [sview addSubview: self];
6166     }
6168 /*  [self setFrame: r]; */
6170   return self;
6174 - (void)setFrame: (NSRect)newRect
6176   NSTRACE (EmacsScroller_setFrame);
6177 /*  BLOCK_INPUT; */
6178   pixel_height = NSHeight (newRect);
6179   if (pixel_height == 0) pixel_height = 1;
6180   min_portion = 20 / pixel_height;
6181   [super setFrame: newRect];
6182   [self display];
6183 /*  UNBLOCK_INPUT; */
6187 - (void)dealloc
6189   NSTRACE (EmacsScroller_dealloc);
6190   if (!NILP (win))
6191     XWINDOW (win)->vertical_scroll_bar = Qnil;
6192   [super dealloc];
6196 - condemn
6198   NSTRACE (condemn);
6199   condemned =YES;
6200   return self;
6204 - reprieve
6206   NSTRACE (reprieve);
6207   condemned =NO;
6208   return self;
6212 - judge
6214   NSTRACE (judge);
6215   if (condemned)
6216     {
6217       EmacsView *view;
6218       BLOCK_INPUT;
6219       /* ensure other scrollbar updates after deletion */
6220       view = (EmacsView *)FRAME_NS_VIEW (frame);
6221       if (view != nil)
6222         view->scrollbarsNeedingUpdate++;
6223       [self removeFromSuperview];
6224       [self release];
6225       UNBLOCK_INPUT;
6226     }
6227   return self;
6231 - (void)resetCursorRects
6233   NSRect visible = [self visibleRect];
6234   NSTRACE (resetCursorRects);
6236   if (!NSIsEmptyRect (visible))
6237     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6238   [[NSCursor arrowCursor] setOnMouseEntered: YES];
6242 - (int) checkSamePosition: (int) position portion: (int) portion
6243                     whole: (int) whole
6245   return em_position ==position && em_portion ==portion && em_whole ==whole
6246     && portion != whole; /* needed for resize empty buf */
6250 - setPosition: (int)position portion: (int)portion whole: (int)whole
6252   NSTRACE (setPosition);
6254   em_position = position;
6255   em_portion = portion;
6256   em_whole = whole;
6258   if (portion >= whole)
6259     {
6260 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6261       [self setKnobProportion: 1.0];
6262       [self setDoubleValue: 1.0];
6263 #else
6264       [self setFloatValue: 0.0 knobProportion: 1.0];
6265 #endif
6266     }
6267   else
6268     {
6269       float pos, por;
6270       portion = max ((float)whole*min_portion/pixel_height, portion);
6271       pos = (float)position / (whole - portion);
6272       por = (float)portion/whole;
6273 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6274       [self setKnobProportion: por];
6275       [self setDoubleValue: pos];
6276 #else
6277       [self setFloatValue: pos knobProportion: por];
6278 #endif
6279     }
6280   return self;
6283 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6284      drag events will go directly to the EmacsScroller.  Leaving in for now. */
6285 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6286                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
6288   *part = last_hit_part;
6289   *window = win;
6290   XSETINT (*y, pixel_height);
6291   if ([self floatValue] > 0.999)
6292     XSETINT (*x, pixel_height);
6293   else
6294     XSETINT (*x, pixel_height * [self floatValue]);
6298 /* set up emacs_event */
6299 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6301   if (!emacs_event)
6302     return;
6304   emacs_event->part = last_hit_part;
6305   emacs_event->code = 0;
6306   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
6307   emacs_event->frame_or_window = win;
6308   emacs_event->timestamp = EV_TIMESTAMP (e);
6309   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
6310   emacs_event->arg = Qnil;
6311   XSETINT (emacs_event->x, loc * pixel_height);
6312   XSETINT (emacs_event->y, pixel_height-20);
6314   n_emacs_events_pending++;
6315   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
6316   EVENT_INIT (*emacs_event);
6317   ns_send_appdefined (-1);
6321 /* called manually thru timer to implement repeated button action w/hold-down */
6322 - repeatScroll: (NSTimer *)scrollEntry
6324   NSEvent *e = [[self window] currentEvent];
6325   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
6326   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
6328   /* clear timer if need be */
6329   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
6330     {
6331         [scroll_repeat_entry invalidate];
6332         [scroll_repeat_entry release];
6333         scroll_repeat_entry = nil;
6335         if (inKnob)
6336           return self;
6338         scroll_repeat_entry
6339           = [[NSTimer scheduledTimerWithTimeInterval:
6340                         SCROLL_BAR_CONTINUOUS_DELAY
6341                                             target: self
6342                                           selector: @selector (repeatScroll:)
6343                                           userInfo: 0
6344                                            repeats: YES]
6345               retain];
6346     }
6348   [self sendScrollEventAtLoc: 0 fromEvent: e];
6349   return self;
6353 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
6354    mouseDragged events without going into a modal loop. */
6355 - (void)mouseDown: (NSEvent *)e
6357   NSRect sr, kr;
6358   /* hitPart is only updated AFTER event is passed on */
6359   NSScrollerPart part = [self testPart: [e locationInWindow]];
6360   double inc = 0.0, loc, kloc, pos;
6361   int edge = 0;
6363   NSTRACE (EmacsScroller_mouseDown);
6365   switch (part)
6366     {
6367     case NSScrollerDecrementPage:
6368         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
6369     case NSScrollerIncrementPage:
6370         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
6371     case NSScrollerDecrementLine:
6372       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
6373     case NSScrollerIncrementLine:
6374       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
6375     case NSScrollerKnob:
6376       last_hit_part = scroll_bar_handle; break;
6377     case NSScrollerKnobSlot:  /* GNUstep-only */
6378       last_hit_part = scroll_bar_move_ratio; break;
6379     default:  /* NSScrollerNoPart? */
6380       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
6381                (long) part);
6382       return;
6383     }
6385   if (inc != 0.0)
6386     {
6387       pos = 0;      /* ignored */
6389       /* set a timer to repeat, as we can't let superclass do this modally */
6390       scroll_repeat_entry
6391         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
6392                                             target: self
6393                                           selector: @selector (repeatScroll:)
6394                                           userInfo: 0
6395                                            repeats: YES]
6396             retain];
6397     }
6398   else
6399     {
6400       /* handle, or on GNUstep possibly slot */
6401       NSEvent *fake_event;
6403       /* compute float loc in slot and mouse offset on knob */
6404       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6405                       toView: nil];
6406       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6407       if (loc <= 0.0)
6408         {
6409           loc = 0.0;
6410           edge = -1;
6411         }
6412       else if (loc >= NSHeight (sr))
6413         {
6414           loc = NSHeight (sr);
6415           edge = 1;
6416         }
6418       if (edge)
6419         kloc = 0.5 * edge;
6420       else
6421         {
6422           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
6423                           toView: nil];
6424           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
6425         }
6426       last_mouse_offset = kloc;
6428       /* if knob, tell emacs a location offset by knob pos
6429          (to indicate top of handle) */
6430       if (part == NSScrollerKnob)
6431           pos = (loc - last_mouse_offset) / NSHeight (sr);
6432       else
6433         /* else this is a slot click on GNUstep: go straight there */
6434         pos = loc / NSHeight (sr);
6436       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
6437       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
6438                                       location: [e locationInWindow]
6439                                  modifierFlags: [e modifierFlags]
6440                                      timestamp: [e timestamp]
6441                                   windowNumber: [e windowNumber]
6442                                        context: [e context]
6443                                    eventNumber: [e eventNumber]
6444                                     clickCount: [e clickCount]
6445                                       pressure: [e pressure]];
6446       [super mouseUp: fake_event];
6447     }
6449   if (part != NSScrollerKnob)
6450     [self sendScrollEventAtLoc: pos fromEvent: e];
6454 /* Called as we manually track scroller drags, rather than superclass. */
6455 - (void)mouseDragged: (NSEvent *)e
6457     NSRect sr;
6458     double loc, pos;
6459     int edge = 0;
6461     NSTRACE (EmacsScroller_mouseDragged);
6463       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6464                       toView: nil];
6465       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6467       if (loc <= 0.0)
6468         {
6469           loc = 0.0;
6470           edge = -1;
6471         }
6472       else if (loc >= NSHeight (sr) + last_mouse_offset)
6473         {
6474           loc = NSHeight (sr) + last_mouse_offset;
6475           edge = 1;
6476         }
6478       pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
6479       [self sendScrollEventAtLoc: pos fromEvent: e];
6483 - (void)mouseUp: (NSEvent *)e
6485   if (scroll_repeat_entry)
6486     {
6487       [scroll_repeat_entry invalidate];
6488       [scroll_repeat_entry release];
6489       scroll_repeat_entry = nil;
6490     }
6491   last_hit_part = 0;
6495 /* treat scrollwheel events in the bar as though they were in the main window */
6496 - (void) scrollWheel: (NSEvent *)theEvent
6498   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
6499   [view mouseDown: theEvent];
6502 @end  /* EmacsScroller */
6507 /* ==========================================================================
6509    Font-related functions; these used to be in nsfaces.m
6511    ========================================================================== */
6514 Lisp_Object
6515 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
6517   struct font *font = XFONT_OBJECT (font_object);
6519   if (fontset < 0)
6520     fontset = fontset_from_font (font_object);
6521   FRAME_FONTSET (f) = fontset;
6523   if (FRAME_FONT (f) == font)
6524     /* This font is already set in frame F.  There's nothing more to
6525        do.  */
6526     return font_object;
6528   FRAME_FONT (f) = font;
6530   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
6531   FRAME_COLUMN_WIDTH (f) = font->average_width;
6532   FRAME_SPACE_WIDTH (f) = font->space_width;
6533   FRAME_LINE_HEIGHT (f) = font->height;
6535   compute_fringe_widths (f, 1);
6537   /* Compute the scroll bar width in character columns.  */
6538   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6539     {
6540       int wid = FRAME_COLUMN_WIDTH (f);
6541       FRAME_CONFIG_SCROLL_BAR_COLS (f)
6542         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
6543     }
6544   else
6545     {
6546       int wid = FRAME_COLUMN_WIDTH (f);
6547       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6548     }
6550   /* Now make the frame display the given font.  */
6551   if (FRAME_NS_WINDOW (f) != 0)
6552         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6554   return font_object;
6558 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
6559 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
6560          in 1.43. */
6562 const char *
6563 ns_xlfd_to_fontname (const char *xlfd)
6564 /* --------------------------------------------------------------------------
6565     Convert an X font name (XLFD) to an NS font name.
6566     Only family is used.
6567     The string returned is temporarily allocated.
6568    -------------------------------------------------------------------------- */
6570   char *name = xmalloc (180);
6571   int i, len;
6572   const char *ret;
6574   if (!strncmp (xlfd, "--", 2))
6575     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
6576   else
6577     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
6579   /* stopgap for malformed XLFD input */
6580   if (strlen (name) == 0)
6581     strcpy (name, "Monaco");
6583   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
6584      also uppercase after '-' or ' ' */
6585   name[0] = toupper (name[0]);
6586   for (len =strlen (name), i =0; i<len; i++)
6587     {
6588       if (name[i] == '$')
6589         {
6590           name[i] = '-';
6591           if (i+1<len)
6592             name[i+1] = toupper (name[i+1]);
6593         }
6594       else if (name[i] == '_')
6595         {
6596           name[i] = ' ';
6597           if (i+1<len)
6598             name[i+1] = toupper (name[i+1]);
6599         }
6600     }
6601 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
6602   ret = [[NSString stringWithUTF8String: name] UTF8String];
6603   xfree (name);
6604   return ret;
6608 void
6609 syms_of_nsterm (void)
6611   NSTRACE (syms_of_nsterm);
6613   ns_antialias_threshold = 10.0;
6615   /* from 23+ we need to tell emacs what modifiers there are.. */
6616   DEFSYM (Qmodifier_value, "modifier-value");
6617   DEFSYM (Qalt, "alt");
6618   DEFSYM (Qhyper, "hyper");
6619   DEFSYM (Qmeta, "meta");
6620   DEFSYM (Qsuper, "super");
6621   DEFSYM (Qcontrol, "control");
6622   DEFSYM (Qnone, "none");
6623   DEFSYM (QUTF8_STRING, "UTF8_STRING");
6625   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
6626   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
6627   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
6628   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
6629   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
6631   DEFVAR_LISP ("ns-input-file", ns_input_file,
6632               "The file specified in the last NS event.");
6633   ns_input_file =Qnil;
6635   DEFVAR_LISP ("ns-input-text", ns_input_text,
6636               "The data received in the last NS text drag event.");
6637   ns_input_text =Qnil;
6639   DEFVAR_LISP ("ns-working-text", ns_working_text,
6640               "String for visualizing working composition sequence.");
6641   ns_working_text =Qnil;
6643   DEFVAR_LISP ("ns-input-font", ns_input_font,
6644               "The font specified in the last NS event.");
6645   ns_input_font =Qnil;
6647   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
6648               "The fontsize specified in the last NS event.");
6649   ns_input_fontsize =Qnil;
6651   DEFVAR_LISP ("ns-input-line", ns_input_line,
6652                "The line specified in the last NS event.");
6653   ns_input_line =Qnil;
6655   DEFVAR_LISP ("ns-input-color", ns_input_color,
6656                "The color specified in the last NS event.");
6657   ns_input_color =Qnil;
6659   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
6660                "The service name specified in the last NS event.");
6661   ns_input_spi_name =Qnil;
6663   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
6664                "The service argument specified in the last NS event.");
6665   ns_input_spi_arg =Qnil;
6667   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
6668                "This variable describes the behavior of the alternate or option key.\n\
6669 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6670 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6671 at all, allowing it to be used at a lower level for accented character entry.");
6672   ns_alternate_modifier = Qmeta;
6674   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
6675                "This variable describes the behavior of the right alternate or option key.\n\
6676 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6677 Set to left means be the same key as `ns-alternate-modifier'.\n\
6678 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6679 at all, allowing it to be used at a lower level for accented character entry.");
6680   ns_right_alternate_modifier = Qleft;
6682   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
6683                "This variable describes the behavior of the command key.\n\
6684 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6685   ns_command_modifier = Qsuper;
6687   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
6688                "This variable describes the behavior of the right command key.\n\
6689 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6690 Set to left means be the same key as `ns-command-modifier'.\n\
6691 Set to none means that the command / option key is not interpreted by Emacs\n\
6692 at all, allowing it to be used at a lower level for accented character entry.");
6693   ns_right_command_modifier = Qleft;
6695   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
6696                "This variable describes the behavior of the control key.\n\
6697 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6698   ns_control_modifier = Qcontrol;
6700   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
6701                "This variable describes the behavior of the right control key.\n\
6702 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6703 Set to left means be the same key as `ns-control-modifier'.\n\
6704 Set to none means that the control / option key is not interpreted by Emacs\n\
6705 at all, allowing it to be used at a lower level for accented character entry.");
6706   ns_right_control_modifier = Qleft;
6708   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
6709                "This variable describes the behavior of the function key (on laptops).\n\
6710 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6711 Set to none means that the function key is not interpreted by Emacs at all,\n\
6712 allowing it to be used at a lower level for accented character entry.");
6713   ns_function_modifier = Qnone;
6715   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
6716                "Non-nil (the default) means to render text antialiased. Only has an effect on OS X Panther and above.");
6717   ns_antialias_text = Qt;
6719   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
6720                "Whether to confirm application quit using dialog.");
6721   ns_confirm_quit = Qnil;
6723   staticpro (&ns_display_name_list);
6724   ns_display_name_list = Qnil;
6726   staticpro (&last_mouse_motion_frame);
6727   last_mouse_motion_frame = Qnil;
6729   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
6730                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
6731 Only works on OSX 10.6 or later.  */);
6732   ns_auto_hide_menu_bar = Qnil;
6734   /* TODO: move to common code */
6735   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
6736                doc: /* If not nil, Emacs uses toolkit scroll bars.  */);
6737 #ifdef USE_TOOLKIT_SCROLL_BARS
6738   Vx_toolkit_scroll_bars = Qt;
6739 #else
6740   Vx_toolkit_scroll_bars = Qnil;
6741 #endif
6743   DEFVAR_BOOL ("x-use-underline-position-properties",
6744                x_use_underline_position_properties,
6745      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
6746 A value of nil means ignore them.  If you encounter fonts with bogus
6747 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
6748 to 4.1, set this to nil. */);
6749   x_use_underline_position_properties = 0;
6751   DEFVAR_BOOL ("x-underline-at-descent-line",
6752                x_underline_at_descent_line,
6753      doc: /* Non-nil means to draw the underline at the same place as the descent line.
6754 A value of nil means to draw the underline according to the value of the
6755 variable `x-use-underline-position-properties', which is usually at the
6756 baseline level.  The default value is nil.  */);
6757   x_underline_at_descent_line = 0;
6759   /* Tell emacs about this window system. */
6760   Fprovide (intern ("ns"), Qnil);