Fix bug #10129: add positional information to "C-u C-x =".
[emacs.git] / src / nsterm.m
blob70d3cc0e8b86449171160a0945819fc7059a0978
1 /* NeXT/Open/GNUstep / MacOSX communication module.
2    Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2012
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            * constraint 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   if (f->output_data.ns->miniimage != nil)
1162     [f->output_data.ns->miniimage release];
1164   [[view window] close];
1165   [view release];
1167   UNBLOCK_INPUT;
1170 void
1171 x_destroy_window (struct frame *f)
1172 /* --------------------------------------------------------------------------
1173      External: Delete the window
1174    -------------------------------------------------------------------------- */
1176   NSTRACE (x_destroy_window);
1177   check_ns ();
1178   x_free_frame_resources (f);
1179   ns_window_num--;
1183 void
1184 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1185 /* --------------------------------------------------------------------------
1186      External: Position the window
1187    -------------------------------------------------------------------------- */
1189   NSView *view = FRAME_NS_VIEW (f);
1190   NSArray *screens = [NSScreen screens];
1191   NSScreen *fscreen = [screens objectAtIndex: 0];
1192   NSScreen *screen = [[view window] screen];
1194   NSTRACE (x_set_offset);
1196   BLOCK_INPUT;
1198   f->left_pos = xoff;
1199   f->top_pos = yoff;
1201   if (view != nil && screen && fscreen)
1202     {
1203       f->left_pos = f->size_hint_flags & XNegative
1204         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1205         : f->left_pos;
1206       /* We use visibleFrame here to take menu bar into account.
1207          Ideally we should also adjust left/top with visibleFrame.origin.  */
1209       f->top_pos = f->size_hint_flags & YNegative
1210         ? ([screen visibleFrame].size.height + f->top_pos
1211            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1212            - FRAME_TOOLBAR_HEIGHT (f))
1213         : f->top_pos;
1214 #ifdef NS_IMPL_GNUSTEP
1215       if (f->left_pos < 100)
1216         f->left_pos = 100;  /* don't overlap menu */
1217 #endif
1218       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1219          menu bar.  */
1220       f->output_data.ns->dont_constrain = 0;
1221       [[view window] setFrameTopLeftPoint:
1222                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1223                                     SCREENMAXBOUND ([fscreen frame].size.height
1224                                                     - NS_TOP_POS (f)))];
1225       f->size_hint_flags &= ~(XNegative|YNegative);
1226     }
1228   UNBLOCK_INPUT;
1232 void
1233 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1234 /* --------------------------------------------------------------------------
1235      Adjust window pixel size based on given character grid size
1236      Impl is a bit more complex than other terms, need to do some
1237      internal clipping.
1238    -------------------------------------------------------------------------- */
1240   EmacsView *view = FRAME_NS_VIEW (f);
1241   EmacsToolbar *toolbar = [view toolbar];
1242   NSWindow *window = [view window];
1243   NSRect wr = [window frame];
1244   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1245   int pixelwidth, pixelheight;
1246   static int oldRows, oldCols, oldFontWidth, oldFontHeight;
1247   static int oldTB;
1248   static struct frame *oldF;
1250   NSTRACE (x_set_window_size);
1252   if (view == nil ||
1253       (f == oldF
1254        && rows == oldRows && cols == oldCols
1255        && oldFontWidth == FRAME_COLUMN_WIDTH (f)
1256        && oldFontHeight == FRAME_LINE_HEIGHT (f)
1257        && oldTB == tb))
1258     return;
1260 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1262   BLOCK_INPUT;
1264   check_frame_size (f, &rows, &cols);
1265   oldF = f;
1266   oldRows = rows;
1267   oldCols = cols;
1268   oldFontWidth = FRAME_COLUMN_WIDTH (f);
1269   oldFontHeight = FRAME_LINE_HEIGHT (f);
1270   oldTB = tb;
1272   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1273   compute_fringe_widths (f, 0);
1275   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1276   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1278   /* If we have a toolbar, take its height into account. */
1279   if (tb)
1280     /* NOTE: previously this would generate wrong result if toolbar not
1281              yet displayed and fixing toolbar_height=32 helped, but
1282              now (200903) seems no longer needed */
1283     FRAME_TOOLBAR_HEIGHT (f) =
1284       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1285         - FRAME_NS_TITLEBAR_HEIGHT (f);
1286   else
1287     FRAME_TOOLBAR_HEIGHT (f) = 0;
1289   wr.size.width = pixelwidth + f->border_width;
1290   wr.size.height = pixelheight + FRAME_NS_TITLEBAR_HEIGHT (f)
1291                   + FRAME_TOOLBAR_HEIGHT (f);
1293   /* Do not try to constrain to this screen.  We may have multiple
1294      screens, and want Emacs to span those.  Constraining to screen
1295      prevents that, and that is not nice to the user.  */
1296  if (f->output_data.ns->zooming)
1297    f->output_data.ns->zooming = 0;
1298  else
1299    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1301   [view setRows: rows andColumns: cols];
1302   [window setFrame: wr display: YES];
1304 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1306   /* This is a trick to compensate for Emacs' managing the scrollbar area
1307      as a fixed number of standard character columns.  Instead of leaving
1308      blank space for the extra, we chopped it off above.  Now for
1309      left-hand scrollbars, we shift all rendering to the left by the
1310      difference between the real width and Emacs' imagined one.  For
1311      right-hand bars, don't worry about it since the extra is never used.
1312      (Obviously doesn't work for vertically split windows tho..) */
1313   {
1314     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1315       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1316                      - NS_SCROLL_BAR_WIDTH (f), 0)
1317       : NSMakePoint (0, 0);
1318     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1319     [view setBoundsOrigin: origin];
1320   }
1322   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1323   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1324   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1325 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1327   mark_window_cursors_off (XWINDOW (f->root_window));
1328   cancel_mouse_face (f);
1330   UNBLOCK_INPUT;
1335 /* ==========================================================================
1337     Color management
1339    ========================================================================== */
1342 NSColor *
1343 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1345   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1346   if (idx < 1 || idx >= color_table->avail)
1347     return nil;
1348   return color_table->colors[idx];
1352 unsigned long
1353 ns_index_color (NSColor *color, struct frame *f)
1355   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1356   ptrdiff_t idx;
1357   ptrdiff_t i;
1359   if (!color_table->colors)
1360     {
1361       color_table->size = NS_COLOR_CAPACITY;
1362       color_table->avail = 1; /* skip idx=0 as marker */
1363       color_table->colors
1364         = (NSColor **)xmalloc (color_table->size * sizeof (NSColor *));
1365       color_table->colors[0] = nil;
1366       color_table->empty_indices = [[NSMutableSet alloc] init];
1367     }
1369   /* do we already have this color ? */
1370   for (i = 1; i < color_table->avail; i++)
1371     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1372       return i;
1374   if ([color_table->empty_indices count] > 0)
1375     {
1376       NSNumber *index = [color_table->empty_indices anyObject];
1377       [color_table->empty_indices removeObject: index];
1378       idx = [index unsignedLongValue];
1379     }
1380   else
1381     {
1382       if (color_table->avail == color_table->size)
1383         color_table->colors =
1384           xpalloc (color_table->colors, &color_table->size, 1,
1385                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1386       idx = color_table->avail++;
1387     }
1389   color_table->colors[idx] = color;
1390   [color retain];
1391 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1392   return idx;
1396 void
1397 ns_free_indexed_color (unsigned long idx, struct frame *f)
1399   struct ns_color_table *color_table;
1400   NSColor *color;
1401   NSNumber *index;
1403   if (!f)
1404     return;
1406   color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1408   if (idx <= 0 || idx >= color_table->size) {
1409     message1 ("ns_free_indexed_color: Color index out of range.\n");
1410     return;
1411   }
1413   index = [NSNumber numberWithUnsignedInt: idx];
1414   if ([color_table->empty_indices containsObject: index]) {
1415     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1416     return;
1417   }
1419   color = color_table->colors[idx];
1420   [color release];
1421   color_table->colors[idx] = nil;
1422   [color_table->empty_indices addObject: index];
1423 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1427 static int
1428 ns_get_color (const char *name, NSColor **col)
1429 /* --------------------------------------------------------------------------
1430      Parse a color name
1431    -------------------------------------------------------------------------- */
1432 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1433    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1434    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1436   NSColor *new = nil;
1437   static char hex[20];
1438   int scaling;
1439   float r = -1.0, g, b;
1440   NSString *nsname = [NSString stringWithUTF8String: name];
1442 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1443   BLOCK_INPUT;
1445   if ([nsname isEqualToString: @"ns_selection_color"])
1446     {
1447       nsname = ns_selection_color;
1448       name = [ns_selection_color UTF8String];
1449     }
1451   /* First, check for some sort of numeric specification. */
1452   hex[0] = '\0';
1454   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1455     {
1456       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1457       [scanner scanFloat: &r];
1458       [scanner scanFloat: &g];
1459       [scanner scanFloat: &b];
1460     }
1461   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1462     {
1463       strncpy (hex, name + 4, 19);
1464       hex[19] = '\0';
1465       scaling = (strlen(hex) - 2) / 3;
1466     }
1467   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1468     {
1469       int len = (strlen(name) - 1);
1470       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1471       int i;
1472       scaling = strlen(name+start) / 3;
1473       for (i=0; i<3; i++) {
1474         strncpy(hex + i * (scaling + 1), name + start + i * scaling, scaling);
1475         hex[(i+1) * (scaling + 1) - 1] = '/';
1476       }
1477       hex[3 * (scaling + 1) - 1] = '\0';
1478     }
1480   if (hex[0])
1481     {
1482       int rr, gg, bb;
1483       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1484       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1485         {
1486           r = rr / fscale;
1487           g = gg / fscale;
1488           b = bb / fscale;
1489         }
1490     }
1492   if (r >= 0.0)
1493     {
1494       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1495       UNBLOCK_INPUT;
1496       return 0;
1497     }
1499   /* Otherwise, color is expected to be from a list */
1500   {
1501     NSEnumerator *lenum, *cenum;
1502     NSString *name;
1503     NSColorList *clist;
1505 #ifdef NS_IMPL_GNUSTEP
1506     /* XXX: who is wrong, the requestor or the implementation? */
1507     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1508         == NSOrderedSame)
1509       nsname = @"highlightColor";
1510 #endif
1512     lenum = [[NSColorList availableColorLists] objectEnumerator];
1513     while ( (clist = [lenum nextObject]) && new == nil)
1514       {
1515         cenum = [[clist allKeys] objectEnumerator];
1516         while ( (name = [cenum nextObject]) && new == nil )
1517           {
1518             if ([name compare: nsname
1519                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1520               new = [clist colorWithKey: name];
1521           }
1522       }
1523   }
1525   if (new)
1526     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1527   UNBLOCK_INPUT;
1528   return new ? 0 : 1;
1532 static NSColor *
1533 ns_get_color_default (const char *name, NSColor *dflt)
1534 /* --------------------------------------------------------------------------
1535      Parse a color or use a default value
1536    -------------------------------------------------------------------------- */
1538   NSColor * col;
1540   if (ns_get_color (name, &col))
1541     return dflt;
1542   else
1543     return col;
1548 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1549 /* --------------------------------------------------------------------------
1550      Convert a Lisp string object to a NS color
1551    -------------------------------------------------------------------------- */
1553   NSTRACE (ns_lisp_to_color);
1554   if (STRINGP (color))
1555     return ns_get_color (SDATA (color), col);
1556   else if (SYMBOLP (color))
1557     return ns_get_color (SDATA (SYMBOL_NAME (color)), col);
1558   return 1;
1562 Lisp_Object
1563 ns_color_to_lisp (NSColor *col)
1564 /* --------------------------------------------------------------------------
1565      Convert a color to a lisp string with the RGB equivalent
1566    -------------------------------------------------------------------------- */
1568   CGFloat red, green, blue, alpha, gray;
1569   char buf[1024];
1570   const char *str;
1571   NSTRACE (ns_color_to_lisp);
1573   BLOCK_INPUT;
1574   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1576       if ((str =[[col colorNameComponent] UTF8String]))
1577         {
1578           UNBLOCK_INPUT;
1579           return build_string ((char *)str);
1580         }
1582     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1583         getRed: &red green: &green blue: &blue alpha: &alpha];
1584   if (red ==green && red ==blue)
1585     {
1586       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1587             getWhite: &gray alpha: &alpha];
1588       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1589                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1590       UNBLOCK_INPUT;
1591       return build_string (buf);
1592     }
1594   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1595             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1597   UNBLOCK_INPUT;
1598   return build_string (buf);
1602 void
1603 ns_query_color(void *col, XColor *color_def, int setPixel)
1604 /* --------------------------------------------------------------------------
1605          Get ARGB values out of NSColor col and put them into color_def.
1606          If setPixel, set the pixel to a concatenated version.
1607          and set color_def pixel to the resulting index.
1608    -------------------------------------------------------------------------- */
1610   CGFloat r, g, b, a;
1612   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1613   color_def->red   = r * 65535;
1614   color_def->green = g * 65535;
1615   color_def->blue  = b * 65535;
1617   if (setPixel == YES)
1618     color_def->pixel
1619       = ARGB_TO_ULONG((int)(a*255),
1620                       (int)(r*255), (int)(g*255), (int)(b*255));
1625 ns_defined_color (struct frame *f,
1626                   const char *name,
1627                   XColor *color_def,
1628                   int alloc,
1629                   char makeIndex)
1630 /* --------------------------------------------------------------------------
1631          Return 1 if named color found, and set color_def rgb accordingly.
1632          If makeIndex and alloc are nonzero put the color in the color_table,
1633          and set color_def pixel to the resulting index.
1634          If makeIndex is zero, set color_def pixel to ARGB.
1635          Return 0 if not found
1636    -------------------------------------------------------------------------- */
1638   NSColor *col;
1639   NSTRACE (ns_defined_color);
1641   BLOCK_INPUT;
1642   if (ns_get_color (name, &col) != 0) /* Color not found  */
1643     {
1644       UNBLOCK_INPUT;
1645       return 0;
1646     }
1647   if (makeIndex && alloc)
1648     color_def->pixel = ns_index_color (col, f);
1649   ns_query_color (col, color_def, !makeIndex);
1650   UNBLOCK_INPUT;
1651   return 1;
1655 unsigned long
1656 ns_get_rgb_color (struct frame *f, float r, float g, float b, float a)
1657 /* --------------------------------------------------------------------------
1658     return an autoreleased RGB color
1659    -------------------------------------------------------------------------- */
1661 /*static int c = 1; fprintf (stderr, "color request %d\n", c++); */
1662   if (r < 0.0) r = 0.0;
1663   else if (r > 1.0) r = 1.0;
1664   if (g < 0.0) g = 0.0;
1665   else if (g > 1.0) g = 1.0;
1666   if (b < 0.0) b = 0.0;
1667   else if (b > 1.0) b = 1.0;
1668   if (a < 0.0) a = 0.0;
1669   else if (a > 1.0) a = 1.0;
1670   return (unsigned long) ns_index_color(
1671     [NSColor colorWithCalibratedRed: r green: g blue: b alpha: a], f);
1675 void
1676 x_set_frame_alpha (struct frame *f)
1677 /* --------------------------------------------------------------------------
1678      change the entire-frame transparency
1679    -------------------------------------------------------------------------- */
1681   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1682   EmacsView *view = FRAME_NS_VIEW (f);
1683   double alpha = 1.0;
1684   double alpha_min = 1.0;
1686   if (dpyinfo->x_highlight_frame == f)
1687     alpha = f->alpha[0];
1688   else
1689     alpha = f->alpha[1];
1691   if (FLOATP (Vframe_alpha_lower_limit))
1692     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1693   else if (INTEGERP (Vframe_alpha_lower_limit))
1694     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1696   if (alpha < 0.0)
1697     return;
1698   else if (1.0 < alpha)
1699     alpha = 1.0;
1700   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1701     alpha = alpha_min;
1703 #ifdef NS_IMPL_COCOA
1704   [[view window] setAlphaValue: alpha];
1705 #endif
1709 /* ==========================================================================
1711     Mouse handling
1713    ========================================================================== */
1716 void
1717 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1718 /* --------------------------------------------------------------------------
1719      Programmatically reposition mouse pointer in pixel coordinates
1720    -------------------------------------------------------------------------- */
1722   NSTRACE (x_set_mouse_pixel_position);
1723   ns_raise_frame (f);
1724 #if 0
1725   /* FIXME: this does not work, and what about GNUstep? */
1726 #ifdef NS_IMPL_COCOA
1727   [FRAME_NS_VIEW (f) lockFocus];
1728   PSsetmouse ((float)pix_x, (float)pix_y);
1729   [FRAME_NS_VIEW (f) unlockFocus];
1730 #endif
1731 #endif
1735 void
1736 x_set_mouse_position (struct frame *f, int h, int v)
1737 /* --------------------------------------------------------------------------
1738      Programmatically reposition mouse pointer in character coordinates
1739    -------------------------------------------------------------------------- */
1741   int pix_x, pix_y;
1743   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1744   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1746   if (pix_x < 0) pix_x = 0;
1747   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1749   if (pix_y < 0) pix_y = 0;
1750   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1752   x_set_mouse_pixel_position (f, pix_x, pix_y);
1756 static int
1757 note_mouse_movement (struct frame *frame, float x, float y)
1758 /*   ------------------------------------------------------------------------
1759      Called by EmacsView on mouseMovement events.  Passes on
1760      to emacs mainstream code if we moved off of a rect of interest
1761      known as last_mouse_glyph.
1762      ------------------------------------------------------------------------ */
1764 //  NSTRACE (note_mouse_movement);
1766   XSETFRAME (last_mouse_motion_frame, frame);
1768   /* Note, this doesn't get called for enter/leave, since we don't have a
1769      position.  Those are taken care of in the corresponding NSView methods. */
1771   /* has movement gone beyond last rect we were tracking? */
1772   if (x < last_mouse_glyph.origin.x ||
1773       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1774       y < last_mouse_glyph.origin.y ||
1775       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1776     {
1777       ns_update_begin(frame);
1778       frame->mouse_moved = 1;
1779       note_mouse_highlight (frame, x, y);
1780       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1781       ns_update_end(frame);
1782       return 1;
1783     }
1785   return 0;
1789 static void
1790 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1791                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1792                    Time *time)
1793 /* --------------------------------------------------------------------------
1794     External (hook): inform emacs about mouse position and hit parts.
1795     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1796     x & y should be position in the scrollbar (the whole bar, not the handle)
1797     and length of scrollbar respectively
1798    -------------------------------------------------------------------------- */
1800   id view;
1801   NSPoint position;
1802   int xchar, ychar;
1803   Lisp_Object frame, tail;
1804   struct frame *f;
1805   struct ns_display_info *dpyinfo;
1807   NSTRACE (ns_mouse_position);
1809   if (*fp == NULL)
1810     {
1811       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1812       return;
1813     }
1815   dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1817   BLOCK_INPUT;
1819   if (last_mouse_scroll_bar != nil && insist == 0)
1820     {
1821       /* TODO: we do not use this path at the moment because drag events will
1822            go directly to the EmacsScroller.  Leaving code in for now. */
1823       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1824                                               x: x y: y];
1825       if (time) *time = last_mouse_movement_time;
1826       last_mouse_scroll_bar = nil;
1827     }
1828   else
1829     {
1830       /* Clear the mouse-moved flag for every frame on this display.  */
1831       FOR_EACH_FRAME (tail, frame)
1832         if (FRAME_NS_P (XFRAME (frame))
1833             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1834           XFRAME (frame)->mouse_moved = 0;
1836       last_mouse_scroll_bar = nil;
1837       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1838         f = last_mouse_frame;
1839       else
1840         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1841                                     : SELECTED_FRAME ();
1843       if (f && f->output_data.ns)  /* TODO: 2nd check no longer needed? */
1844         {
1845           view = FRAME_NS_VIEW (*fp);
1847           position = [[view window] mouseLocationOutsideOfEventStream];
1848           position = [view convertPoint: position fromView: nil];
1849           remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1850 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1852           if (bar_window) *bar_window = Qnil;
1853           if (part) *part = 0; /*scroll_bar_handle; */
1855           if (x) XSETINT (*x, lrint (position.x));
1856           if (y) XSETINT (*y, lrint (position.y));
1857           if (time) *time = last_mouse_movement_time;
1858           *fp = f;
1859         }
1860     }
1862   UNBLOCK_INPUT;
1866 static void
1867 ns_frame_up_to_date (struct frame *f)
1868 /* --------------------------------------------------------------------------
1869     External (hook): Fix up mouse highlighting right after a full update.
1870     Some highlighting was deferred if GC was happening during
1871     note_mouse_highlight (), while other highlighting was deferred for update.
1872    -------------------------------------------------------------------------- */
1874   NSTRACE (ns_frame_up_to_date);
1876   if (FRAME_NS_P (f))
1877     {
1878       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1879       if ((hlinfo->mouse_face_deferred_gc || f ==hlinfo->mouse_face_mouse_frame)
1880       /*&& hlinfo->mouse_face_mouse_frame*/)
1881         {
1882           BLOCK_INPUT;
1883           ns_update_begin(f);
1884           if (hlinfo->mouse_face_mouse_frame)
1885             note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1886                                   hlinfo->mouse_face_mouse_x,
1887                                   hlinfo->mouse_face_mouse_y);
1888           hlinfo->mouse_face_deferred_gc = 0;
1889           ns_update_end(f);
1890           UNBLOCK_INPUT;
1891         }
1892     }
1896 void
1897 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1898 /* --------------------------------------------------------------------------
1899     External (RIF): set frame mouse pointer type.
1900    -------------------------------------------------------------------------- */
1902   NSTRACE (ns_define_frame_cursor);
1903   if (FRAME_POINTER_TYPE (f) != cursor)
1904     {
1905       EmacsView *view = FRAME_NS_VIEW (f);
1906       FRAME_POINTER_TYPE (f) = cursor;
1907       [[view window] invalidateCursorRectsForView: view];
1908       /* Redisplay assumes this function also draws the changed frame
1909          cursor, but this function doesn't, so do it explicitly.  */
1910       x_update_cursor (f, 1);
1911     }
1916 /* ==========================================================================
1918     Keyboard handling
1920    ========================================================================== */
1923 static unsigned
1924 ns_convert_key (unsigned code)
1925 /* --------------------------------------------------------------------------
1926     Internal call used by NSView-keyDown.
1927    -------------------------------------------------------------------------- */
1929   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1930                                 / sizeof (convert_ns_to_X_keysym[0]));
1931   unsigned keysym;
1932   /* An array would be faster, but less easy to read. */
1933   for (keysym = 0; keysym < last_keysym; keysym += 2)
1934     if (code == convert_ns_to_X_keysym[keysym])
1935       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1936   return 0;
1937 /* if decide to use keyCode and Carbon table, use this line:
1938      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1942 char *
1943 x_get_keysym_name (int keysym)
1944 /* --------------------------------------------------------------------------
1945     Called by keyboard.c.  Not sure if the return val is important, except
1946     that it be unique.
1947    -------------------------------------------------------------------------- */
1949   static char value[16];
1950   NSTRACE (x_get_keysym_name);
1951   sprintf (value, "%d", keysym);
1952   return value;
1957 /* ==========================================================================
1959     Block drawing operations
1961    ========================================================================== */
1964 static void
1965 ns_redraw_scroll_bars (struct frame *f)
1967   int i;
1968   id view;
1969   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1970   NSTRACE (ns_judge_scroll_bars);
1971   for (i =[subviews count]-1; i >= 0; i--)
1972     {
1973       view = [subviews objectAtIndex: i];
1974       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1975       [view display];
1976     }
1980 void
1981 ns_clear_frame (struct frame *f)
1982 /* --------------------------------------------------------------------------
1983       External (hook): Erase the entire frame
1984    -------------------------------------------------------------------------- */
1986   NSView *view = FRAME_NS_VIEW (f);
1987   NSRect r;
1989   NSTRACE (ns_clear_frame);
1990   if (ns_in_resize)
1991     return;
1993  /* comes on initial frame because we have
1994     after-make-frame-functions = select-frame */
1995  if (!FRAME_DEFAULT_FACE (f))
1996    return;
1998   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2000   output_cursor.hpos = output_cursor.vpos = 0;
2001   output_cursor.x = -1;
2003   r = [view bounds];
2005   BLOCK_INPUT;
2006   ns_focus (f, &r, 1);
2007   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2008   NSRectFill (r);
2009   ns_unfocus (f);
2011 #ifdef NS_IMPL_COCOA
2012   [[view window] display];  /* redraw resize handle */
2013 #endif
2015   /* as of 2006/11 or so this is now needed */
2016   ns_redraw_scroll_bars (f);
2017   UNBLOCK_INPUT;
2021 void
2022 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2023 /* --------------------------------------------------------------------------
2024     External (RIF):  Clear section of frame
2025    -------------------------------------------------------------------------- */
2027   NSRect r = NSMakeRect (x, y, width, height);
2028   NSView *view = FRAME_NS_VIEW (f);
2029   struct face *face = FRAME_DEFAULT_FACE (f);
2031   if (!view || !face)
2032     return;
2034   NSTRACE (ns_clear_frame_area);
2036   r = NSIntersectionRect (r, [view frame]);
2037   ns_focus (f, &r, 1);
2038   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2040 #ifdef NS_IMPL_COCOA
2041   {
2042     /* clip out the resize handle */
2043     NSWindow *window = [FRAME_NS_VIEW (f) window];
2044     NSRect ir
2045       = [view convertRect: ns_resize_handle_rect (window) fromView: nil];
2047     ir = NSIntersectionRect (r, ir);
2048     if (NSIsEmptyRect (ir))
2049       {
2050 #endif
2052   NSRectFill (r);
2054 #ifdef NS_IMPL_COCOA
2055       }
2056     else
2057       {
2058         NSRect r1 = r, r2 = r; /* upper and lower non-intersecting */
2059         r1.size.height -= ir.size.height;
2060         r2.origin.y += r1.size.height;
2061         r2.size.width -= ir.size.width;
2062         r2.size.height = ir.size.height;
2063         NSRectFill (r1);
2064         NSRectFill (r2);
2065       }
2066   }
2067 #endif
2069   ns_unfocus (f);
2070   return;
2074 static void
2075 ns_scroll_run (struct window *w, struct run *run)
2076 /* --------------------------------------------------------------------------
2077     External (RIF):  Insert or delete n lines at line vpos
2078    -------------------------------------------------------------------------- */
2080   struct frame *f = XFRAME (w->frame);
2081   int x, y, width, height, from_y, to_y, bottom_y;
2083   NSTRACE (ns_scroll_run);
2085   /* begin copy from other terms */
2086   /* Get frame-relative bounding box of the text display area of W,
2087      without mode lines.  Include in this box the left and right
2088      fringe of W.  */
2089   window_box (w, -1, &x, &y, &width, &height);
2091   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2092   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2093   bottom_y = y + height;
2095   if (to_y < from_y)
2096     {
2097       /* Scrolling up.  Make sure we don't copy part of the mode
2098          line at the bottom.  */
2099       if (from_y + run->height > bottom_y)
2100         height = bottom_y - from_y;
2101       else
2102         height = run->height;
2103     }
2104   else
2105     {
2106       /* Scrolling down.  Make sure we don't copy over the mode line.
2107          at the bottom.  */
2108       if (to_y + run->height > bottom_y)
2109         height = bottom_y - to_y;
2110       else
2111         height = run->height;
2112     }
2113   /* end copy from other terms */
2115   if (height == 0)
2116       return;
2118   BLOCK_INPUT;
2120   updated_window = w;
2121   x_clear_cursor (w);
2123   {
2124     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2125     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2126     NSPoint dstOrigin = NSMakePoint (x, to_y);
2128     ns_focus (f, &dstRect, 1);
2129     NSCopyBits (0, srcRect , dstOrigin);
2130     ns_unfocus (f);
2131   }
2133   UNBLOCK_INPUT;
2137 static void
2138 ns_after_update_window_line (struct glyph_row *desired_row)
2139 /* --------------------------------------------------------------------------
2140     External (RIF): preparatory to fringe update after text was updated
2141    -------------------------------------------------------------------------- */
2143   struct window *w = updated_window;
2144   struct frame *f;
2145   int width, height;
2147   NSTRACE (ns_after_update_window_line);
2149   /* begin copy from other terms */
2150   xassert (w);
2152   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2153     desired_row->redraw_fringe_bitmaps_p = 1;
2155   /* When a window has disappeared, make sure that no rest of
2156      full-width rows stays visible in the internal border.
2157      Under NS this is drawn inside the fringes. */
2158   if (windows_or_buffers_changed
2159       && (f = XFRAME (w->frame),
2160           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2161           width != 0)
2162       && (height = desired_row->visible_height,
2163           height > 0))
2164     {
2165       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2167       /* Internal border is drawn below the tool bar.  */
2168       if (WINDOWP (f->tool_bar_window)
2169           && w == XWINDOW (f->tool_bar_window))
2170         y -= width;
2171       /* end copy from other terms */
2173       BLOCK_INPUT;
2174       if (!desired_row->full_width_p)
2175         {
2176           int x1 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2177             + WINDOW_LEFT_FRINGE_WIDTH (w);
2178           int x2 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2179             + FRAME_PIXEL_WIDTH (f) - NS_SCROLL_BAR_WIDTH (f)
2180             - WINDOW_RIGHT_FRINGE_WIDTH (w)
2181             - FRAME_INTERNAL_BORDER_WIDTH (f);
2182           ns_clear_frame_area (f, x1, y, width, height);
2183           ns_clear_frame_area (f, x2, y, width, height);
2184         }
2185       UNBLOCK_INPUT;
2186     }
2190 static void
2191 ns_shift_glyphs_for_insert (struct frame *f,
2192                            int x, int y, int width, int height,
2193                            int shift_by)
2194 /* --------------------------------------------------------------------------
2195     External (RIF): copy an area horizontally, don't worry about clearing src
2196    -------------------------------------------------------------------------- */
2198   NSRect srcRect = NSMakeRect (x, y, width, height);
2199   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2200   NSPoint dstOrigin = dstRect.origin;
2202   NSTRACE (ns_shift_glyphs_for_insert);
2204   ns_focus (f, &dstRect, 1);
2205   NSCopyBits (0, srcRect, dstOrigin);
2206   ns_unfocus (f);
2211 /* ==========================================================================
2213     Character encoding and metrics
2215    ========================================================================== */
2218 static inline void
2219 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2220 /* --------------------------------------------------------------------------
2221      External (RIF); compute left/right overhang of whole string and set in s
2222    -------------------------------------------------------------------------- */
2224   struct face *face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2225   struct font *font = s->font; /*face->font; */
2227   if (s->char2b)
2228     {
2229       struct font_metrics metrics;
2230       unsigned int codes[2];
2231       codes[0] = *(s->char2b);
2232       codes[1] = *(s->char2b + s->nchars - 1);
2234       font->driver->text_extents (font, codes, 2, &metrics);
2235       s->left_overhang = -metrics.lbearing;
2236       s->right_overhang
2237         = metrics.rbearing > metrics.width
2238         ? metrics.rbearing - metrics.width : 0;
2239     }
2240   else
2241     {
2242       s->left_overhang = 0;
2243       s->right_overhang = ((struct nsfont_info *)font)->ital ?
2244         FONT_HEIGHT (font) * 0.2 : 0;
2245     }
2250 /* ==========================================================================
2252     Fringe and cursor drawing
2254    ========================================================================== */
2257 extern int max_used_fringe_bitmap;
2258 static void
2259 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2260                       struct draw_fringe_bitmap_params *p)
2261 /* --------------------------------------------------------------------------
2262     External (RIF); fringe-related
2263    -------------------------------------------------------------------------- */
2265   struct frame *f = XFRAME (WINDOW_FRAME (w));
2266   struct face *face = p->face;
2267   int rowY;
2268   static EmacsImage **bimgs = NULL;
2269   static int nBimgs = 0;
2270   /* NS-specific: move internal border inside fringe */
2271   int x = p->bx < 0 ? p->x : p->bx;
2272   int wd = p->bx < 0 ? p->wd : p->nx;
2273   BOOL fringeOnVeryLeft
2274     = x - WINDOW_LEFT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w)
2275       - FRAME_INTERNAL_BORDER_WIDTH (f) < 10;
2276   BOOL fringeOnVeryRight
2277     = FRAME_PIXEL_WIDTH (f) - x - wd - FRAME_INTERNAL_BORDER_WIDTH (f)
2278       - WINDOW_RIGHT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w) < 10;
2279   int xAdjust = FRAME_INTERNAL_BORDER_WIDTH (f) *
2280     (fringeOnVeryLeft ? -1 : (fringeOnVeryRight ? 1 : 0));
2282   /* grow bimgs if needed */
2283   if (nBimgs < max_used_fringe_bitmap)
2284     {
2285       EmacsImage **newBimgs
2286         = xmalloc (max_used_fringe_bitmap * sizeof (EmacsImage *));
2287       memset (newBimgs, 0, max_used_fringe_bitmap * sizeof (EmacsImage *));
2289       if (nBimgs)
2290         {
2291           memcpy (newBimgs, bimgs, nBimgs * sizeof (EmacsImage *));
2292           xfree (bimgs);
2293         }
2295       bimgs = newBimgs;
2296       nBimgs = max_used_fringe_bitmap;
2297     }
2299   /* Must clip because of partially visible lines.  */
2300   rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2301   ns_clip_to_row (w, row, -1, YES);
2303   if (p->bx >= 0 && !p->overlay_p)
2304     {
2305       int yAdjust = rowY - FRAME_INTERNAL_BORDER_WIDTH (f) < 5 ?
2306         -FRAME_INTERNAL_BORDER_WIDTH (f) : 0;
2307       int yIncr = FRAME_PIXEL_HEIGHT (f) - (p->by+yAdjust + p->ny) < 5 ?
2308         FRAME_INTERNAL_BORDER_WIDTH (f) : 0
2309         + (yAdjust ? FRAME_INTERNAL_BORDER_WIDTH (f) : 0);
2310       NSRect r = NSMakeRect (p->bx+xAdjust, p->by+yAdjust, p->nx, p->ny+yIncr);
2311       NSRectClip (r);
2312       [ns_lookup_indexed_color(face->background, f) set];
2313       NSRectFill (r);
2314     }
2316   if (p->which)
2317     {
2318       NSRect r = NSMakeRect (p->x+xAdjust, p->y, p->wd, p->h);
2319       NSPoint pt = r.origin;
2320       EmacsImage *img = bimgs[p->which - 1];
2322       if (!img)
2323         {
2324           unsigned short *bits = p->bits + p->dh;
2325           int len = p->h;
2326           int i;
2327           unsigned char *cbits = xmalloc (len);
2329           for (i =0; i<len; i++)
2330             cbits[i] = ~(bits[i] & 0xff);
2331           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2332                                            flip: NO];
2333           bimgs[p->which - 1] = img;
2334           xfree (cbits);
2335         }
2337       NSRectClip (r);
2338       /* Since we composite the bitmap instead of just blitting it, we need
2339          to erase the whole background. */
2340       [ns_lookup_indexed_color(face->background, f) set];
2341       NSRectFill (r);
2342       pt.y += p->h;
2343       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2344       [img compositeToPoint: pt operation: NSCompositeSourceOver];
2345     }
2346   ns_unfocus (f);
2350 void
2351 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2352                        int x, int y, int cursor_type, int cursor_width,
2353                        int on_p, int active_p)
2354 /* --------------------------------------------------------------------------
2355      External call (RIF): draw cursor.
2356      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2357    -------------------------------------------------------------------------- */
2359   NSRect r, s;
2360   int fx, fy, h, cursor_height;
2361   struct frame *f = WINDOW_XFRAME (w);
2362   struct glyph *phys_cursor_glyph;
2363   int overspill;
2364   struct glyph *cursor_glyph;
2365   struct face *face;
2366   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2368   /* If cursor is out of bounds, don't draw garbage.  This can happen
2369      in mini-buffer windows when switching between echo area glyphs
2370      and mini-buffer.  */
2372   NSTRACE (dumpcursor);
2374   if (!on_p)
2375     return;
2377   w->phys_cursor_type = cursor_type;
2378   w->phys_cursor_on_p = on_p;
2380   if (cursor_type == NO_CURSOR)
2381     {
2382       w->phys_cursor_width = 0;
2383       return;
2384     }
2386   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2387     {
2388       if (glyph_row->exact_window_width_line_p
2389           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2390         {
2391           glyph_row->cursor_in_fringe_p = 1;
2392           draw_fringe_bitmap (w, glyph_row, 0);
2393         }
2394       return;
2395     }
2397   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2398      (other terminals do it the other way round).  We must set
2399      w->phys_cursor_width to the cursor width.  For bar cursors, that
2400      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2401   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2403   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2404      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2405   if (cursor_type == BAR_CURSOR)
2406     {
2407       if (cursor_width < 1)
2408         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2409       w->phys_cursor_width = cursor_width;
2410     }
2411   /* If we have an HBAR, "cursor_width" MAY specify height. */
2412   else if (cursor_type == HBAR_CURSOR)
2413     {
2414       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2415       fy += h - cursor_height;
2416       h = cursor_height;
2417     }
2419   r.origin.x = fx, r.origin.y = fy;
2420   r.size.height = h;
2421   r.size.width = w->phys_cursor_width;
2423   /* FIXME: if we overwrite the internal border area, it does not get erased;
2424      fix by truncating cursor, but better would be to erase properly */
2425   overspill = r.origin.x + r.size.width -
2426     WINDOW_TEXT_TO_FRAME_PIXEL_X (w, WINDOW_BOX_RIGHT_EDGE_X (w)
2427       - WINDOW_TOTAL_FRINGE_WIDTH (w) - FRAME_INTERNAL_BORDER_WIDTH (f));
2428   if (overspill > 0)
2429     r.size.width -= overspill;
2431   /* TODO: only needed in rare cases with last-resort font in HELLO..
2432      should we do this more efficiently? */
2433   ns_clip_to_row (w, glyph_row, -1, NO); /* do ns_focus(f, &r, 1); if remove */
2436   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2437   if (face && NS_FACE_BACKGROUND (face)
2438       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2439     {
2440       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2441       hollow_color = FRAME_CURSOR_COLOR (f);
2442     }
2443   else
2444     [FRAME_CURSOR_COLOR (f) set];
2446 #ifdef NS_IMPL_COCOA
2447   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2448            atomic.  Cleaner ways of doing this should be investigated.
2449            One way would be to set a global variable DRAWING_CURSOR
2450            when making the call to draw_phys..(), don't focus in that
2451            case, then move the ns_unfocus() here after that call. */
2452   NSDisableScreenUpdates ();
2453 #endif
2455   switch (cursor_type)
2456     {
2457     case NO_CURSOR:
2458       break;
2459     case FILLED_BOX_CURSOR:
2460       NSRectFill (r);
2461       break;
2462     case HOLLOW_BOX_CURSOR:
2463       NSRectFill (r);
2464       [hollow_color set];
2465       NSRectFill (NSInsetRect (r, 1, 1));
2466       [FRAME_CURSOR_COLOR (f) set];
2467       break;
2468     case HBAR_CURSOR:
2469       NSRectFill (r);
2470       break;
2471     case BAR_CURSOR:
2472       s = r;
2473       /* If the character under cursor is R2L, draw the bar cursor
2474          on the right of its glyph, rather than on the left.  */
2475       cursor_glyph = get_phys_cursor_glyph (w);
2476       if ((cursor_glyph->resolved_level & 1) != 0)
2477         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2479       NSRectFill (s);
2480       break;
2481     }
2482   ns_unfocus (f);
2484   /* draw the character under the cursor */
2485   if (cursor_type != NO_CURSOR)
2486     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2488 #ifdef NS_IMPL_COCOA
2489   NSEnableScreenUpdates ();
2490 #endif
2495 static void
2496 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2497 /* --------------------------------------------------------------------------
2498      External (RIF): Draw a vertical line.
2499    -------------------------------------------------------------------------- */
2501   struct frame *f = XFRAME (WINDOW_FRAME (w));
2502   struct face *face;
2503   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2505   NSTRACE (ns_draw_vertical_window_border);
2507   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2508   if (face)
2509       [ns_lookup_indexed_color(face->foreground, f) set];
2511   ns_focus (f, &r, 1);
2512   NSRectFill(r);
2513   ns_unfocus (f);
2517 void
2518 show_hourglass (struct atimer *timer)
2520   if (hourglass_shown_p)
2521     return;
2523   BLOCK_INPUT;
2525   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2527   hourglass_shown_p = 1;
2528   UNBLOCK_INPUT;
2532 void
2533 hide_hourglass (void)
2535   if (!hourglass_shown_p)
2536     return;
2538   BLOCK_INPUT;
2540   /* TODO: remove NSProgressIndicator from all frames */
2542   hourglass_shown_p = 0;
2543   UNBLOCK_INPUT;
2548 /* ==========================================================================
2550     Glyph drawing operations
2552    ========================================================================== */
2555 static inline NSRect
2556 ns_fix_rect_ibw (NSRect r, int fibw, int frame_pixel_width)
2557 /* --------------------------------------------------------------------------
2558     Under NS we draw internal borders inside fringes, and want full-width
2559     rendering to go all the way to edge.  This function makes that correction.
2560    -------------------------------------------------------------------------- */
2562   if (r.origin.y <= fibw+1)
2563     {
2564       r.size.height += r.origin.y;
2565       r.origin.y = 0;
2566     }
2567   if (r.origin.x <= fibw+1)
2568     {
2569       r.size.width += r.origin.x;
2570       r.origin.x = 0;
2571     }
2572   if (frame_pixel_width - (r.origin.x+r.size.width) <= fibw+1)
2573     r.size.width += fibw;
2575   return r;
2579 static int
2580 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2581 /* --------------------------------------------------------------------------
2582     Wrapper utility to account for internal border width on full-width lines,
2583     and allow top full-width rows to hit the frame top.  nr should be pointer
2584     to two successive NSRects.  Number of rects actually used is returned.
2585    -------------------------------------------------------------------------- */
2587   int n = get_glyph_string_clip_rects (s, nr, 2);
2588   if (s->row->full_width_p)
2589     {
2590       *nr = ns_fix_rect_ibw (*nr, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2591                             FRAME_PIXEL_WIDTH (s->f));
2592       if (n == 2)
2593         *nr = ns_fix_rect_ibw (*(nr+1), FRAME_INTERNAL_BORDER_WIDTH (s->f),
2594                               FRAME_PIXEL_WIDTH (s->f));
2595     }
2596   return n;
2599 void
2600 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2601                          NSColor *defaultCol, CGFloat width, CGFloat x)
2602 /* --------------------------------------------------------------------------
2603    Draw underline, overline, and strike-through on glyph string s.
2604    -------------------------------------------------------------------------- */
2606   if (s->for_overlaps)
2607     return;
2609   /* Do underline. */
2610   if (face->underline_p)
2611     {
2612       NSRect r;
2613       unsigned long thickness, position;
2615       /* If the prev was underlined, match its appearance. */
2616       if (s->prev && s->prev->face->underline_p
2617           && s->prev->underline_thickness > 0)
2618         {
2619           thickness = s->prev->underline_thickness;
2620           position = s->prev->underline_position;
2621         }
2622       else
2623         {
2624           struct font *font;
2625           unsigned long descent;
2627           font=s->font;
2628           descent = s->y + s->height - s->ybase;
2630           /* Use underline thickness of font, defaulting to 1. */
2631           thickness = (font && font->underline_thickness > 0)
2632             ? font->underline_thickness : 1;
2634           /* Determine the offset of underlining from the baseline. */
2635           if (x_underline_at_descent_line)
2636             position = descent - thickness;
2637           else if (x_use_underline_position_properties
2638                    && font && font->underline_position >= 0)
2639             position = font->underline_position;
2640           else if (font)
2641             position = lround (font->descent / 2);
2642           else
2643             position = underline_minimum_offset;
2645           position = max (position, underline_minimum_offset);
2647           /* Ensure underlining is not cropped. */
2648           if (descent <= position)
2649             {
2650               position = descent - 1;
2651               thickness = 1;
2652             }
2653           else if (descent < position + thickness)
2654             thickness = 1;
2655         }
2657       s->underline_thickness = thickness;
2658       s->underline_position = position;
2660       r = NSMakeRect (x, s->ybase + position, width, thickness);
2662       if (face->underline_defaulted_p)
2663         [defaultCol set];
2664       else
2665         [ns_lookup_indexed_color (face->underline_color, s->f) set];
2666       NSRectFill (r);
2667     }
2669   /* Do overline. We follow other terms in using a thickness of 1
2670      and ignoring overline_margin. */
2671   if (face->overline_p)
2672     {
2673       NSRect r;
2674       r = NSMakeRect (x, s->y, width, 1);
2676       if (face->overline_color_defaulted_p)
2677         [defaultCol set];
2678       else
2679         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2680       NSRectFill (r);
2681     }
2683   /* Do strike-through.  We follow other terms for thickness and
2684      vertical position.*/
2685   if (face->strike_through_p)
2686     {
2687       NSRect r;
2688       unsigned long dy;
2690       dy = lrint ((s->height - 1) / 2);
2691       r = NSMakeRect (x, s->y + dy, width, 1);
2693       if (face->strike_through_color_defaulted_p)
2694         [defaultCol set];
2695       else
2696         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2697       NSRectFill (r);
2698     }
2701 static void
2702 ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char right_p)
2703 /* --------------------------------------------------------------------------
2704     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2705     Note we can't just use an NSDrawRect command, because of the possibility
2706     of some sides not being drawn, and because the rect will be filled.
2707    -------------------------------------------------------------------------- */
2709   NSRect s = r;
2710   [col set];
2712   /* top, bottom */
2713   s.size.height = thickness;
2714   NSRectFill (s);
2715   s.origin.y += r.size.height - thickness;
2716   NSRectFill (s);
2718   s.size.height = r.size.height;
2719   s.origin.y = r.origin.y;
2721   /* left, right (optional) */
2722   s.size.width = thickness;
2723   if (left_p)
2724     NSRectFill (s);
2725   if (right_p)
2726     {
2727       s.origin.x += r.size.width - thickness;
2728       NSRectFill (s);
2729     }
2733 static void
2734 ns_draw_relief (NSRect r, int thickness, char raised_p,
2735                char top_p, char bottom_p, char left_p, char right_p,
2736                struct glyph_string *s)
2737 /* --------------------------------------------------------------------------
2738     Draw a relief rect inside r, optionally leaving some sides open.
2739     Note we can't just use an NSDrawBezel command, because of the possibility
2740     of some sides not being drawn, and because the rect will be filled.
2741    -------------------------------------------------------------------------- */
2743   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2744   NSColor *newBaseCol = nil;
2745   NSRect sr = r;
2747   NSTRACE (ns_draw_relief);
2749   /* set up colors */
2751   if (s->face->use_box_color_for_shadows_p)
2752     {
2753       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2754     }
2755 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2756            && s->img->pixmap
2757            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2758        {
2759          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2760        } */
2761   else
2762     {
2763       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2764     }
2766   if (newBaseCol == nil)
2767     newBaseCol = [NSColor grayColor];
2769   if (newBaseCol != baseCol)  /* TODO: better check */
2770     {
2771       [baseCol release];
2772       baseCol = [newBaseCol retain];
2773       [lightCol release];
2774       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2775       [darkCol release];
2776       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2777     }
2779   [(raised_p ? lightCol : darkCol) set];
2781   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2783   /* top */
2784   sr.size.height = thickness;
2785   if (top_p) NSRectFill (sr);
2787   /* left */
2788   sr.size.height = r.size.height;
2789   sr.size.width = thickness;
2790   if (left_p) NSRectFill (sr);
2792   [(raised_p ? darkCol : lightCol) set];
2794   /* bottom */
2795   sr.size.width = r.size.width;
2796   sr.size.height = thickness;
2797   sr.origin.y += r.size.height - thickness;
2798   if (bottom_p) NSRectFill (sr);
2800   /* right */
2801   sr.size.height = r.size.height;
2802   sr.origin.y = r.origin.y;
2803   sr.size.width = thickness;
2804   sr.origin.x += r.size.width - thickness;
2805   if (right_p) NSRectFill (sr);
2809 static void
2810 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2811 /* --------------------------------------------------------------------------
2812       Function modeled after x_draw_glyph_string_box ().
2813       Sets up parameters for drawing.
2814    -------------------------------------------------------------------------- */
2816   int right_x, last_x;
2817   char left_p, right_p;
2818   struct glyph *last_glyph;
2819   NSRect r;
2820   int thickness;
2821   struct face *face;
2823   if (s->hl == DRAW_MOUSE_FACE)
2824     {
2825       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2826       if (!face)
2827         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2828     }
2829   else
2830     face = s->face;
2832   thickness = face->box_line_width;
2834   NSTRACE (ns_dumpglyphs_box_or_relief);
2836   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2837             ? WINDOW_RIGHT_EDGE_X (s->w)
2838             : window_box_right (s->w, s->area));
2839   last_glyph = (s->cmp || s->img
2840                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2842   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2843               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2845   left_p = (s->first_glyph->left_box_line_p
2846             || (s->hl == DRAW_MOUSE_FACE
2847                 && (s->prev == NULL || s->prev->hl != s->hl)));
2848   right_p = (last_glyph->right_box_line_p
2849              || (s->hl == DRAW_MOUSE_FACE
2850                  && (s->next == NULL || s->next->hl != s->hl)));
2852   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2854   /* expand full-width row over internal borders */
2855   if (s->row->full_width_p)
2856     r = ns_fix_rect_ibw (r, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2857                         FRAME_PIXEL_WIDTH (s->f));
2859   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2860   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2861     {
2862       ns_draw_box (r, abs (thickness),
2863                    ns_lookup_indexed_color (face->box_color, s->f),
2864                   left_p, right_p);
2865     }
2866   else
2867     {
2868       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2869                      1, 1, left_p, right_p, s);
2870     }
2874 static void
2875 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2876 /* --------------------------------------------------------------------------
2877       Modeled after x_draw_glyph_string_background, which draws BG in
2878       certain cases.  Others are left to the text rendering routine.
2879    -------------------------------------------------------------------------- */
2881   NSTRACE (ns_maybe_dumpglyphs_background);
2883   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2884     {
2885       int box_line_width = max (s->face->box_line_width, 0);
2886       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2887           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2888         {
2889           struct face *face;
2890           if (s->hl == DRAW_MOUSE_FACE)
2891             {
2892               face = FACE_FROM_ID (s->f,
2893                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2894               if (!face)
2895                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2896             }
2897           else
2898             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2899           if (!face->stipple)
2900             [(NS_FACE_BACKGROUND (face) != 0
2901               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2902               : FRAME_BACKGROUND_COLOR (s->f)) set];
2903           else
2904             {
2905               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2906               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2907             }
2909           if (s->hl != DRAW_CURSOR)
2910             {
2911               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2912                                     s->background_width,
2913                                     s->height-2*box_line_width);
2915               /* expand full-width row over internal borders */
2916               if (s->row->full_width_p)
2917                 {
2918                   int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2919                   if (r.origin.y <= fibw+1 + box_line_width)
2920                     {
2921                       r.size.height += r.origin.y;
2922                       r.origin.y = 0;
2923                     }
2924                   if (r.origin.x <= fibw+1)
2925                     {
2926                       r.size.width += 2*r.origin.x;
2927                       r.origin.x = 0;
2928                     }
2929                   if (FRAME_PIXEL_WIDTH (s->f) - (r.origin.x + r.size.width)
2930                       <= fibw+1)
2931                     r.size.width += fibw;
2932                 }
2934               NSRectFill (r);
2935             }
2937           s->background_filled_p = 1;
2938         }
2939     }
2943 static void
2944 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2945 /* --------------------------------------------------------------------------
2946       Renders an image and associated borders.
2947    -------------------------------------------------------------------------- */
2949   EmacsImage *img = s->img->pixmap;
2950   int box_line_vwidth = max (s->face->box_line_width, 0);
2951   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2952   int bg_x, bg_y, bg_height;
2953   int th;
2954   char raised_p;
2955   NSRect br;
2956   struct face *face;
2957   NSColor *tdCol;
2959   NSTRACE (ns_dumpglyphs_image);
2961   if (s->face->box != FACE_NO_BOX
2962       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2963     x += abs (s->face->box_line_width);
2965   bg_x = x;
2966   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2967   bg_height = s->height;
2968   /* other terms have this, but was causing problems w/tabbar mode */
2969   /* - 2 * box_line_vwidth; */
2971   if (s->slice.x == 0) x += s->img->hmargin;
2972   if (s->slice.y == 0) y += s->img->vmargin;
2974   /* Draw BG: if we need larger area than image itself cleared, do that,
2975      otherwise, since we composite the image under NS (instead of mucking
2976      with its background color), we must clear just the image area. */
2977   if (s->hl == DRAW_MOUSE_FACE)
2978     {
2979       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2980       if (!face)
2981        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2982     }
2983   else
2984     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2986   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2988   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2989       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2990     {
2991       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
2992       s->background_filled_p = 1;
2993     }
2994   else
2995     {
2996       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
2997     }
2999   /* expand full-width row over internal borders */
3000   if (s->row->full_width_p)
3001     {
3002       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
3003       if (br.origin.y <= fibw+1 + box_line_vwidth)
3004         {
3005           br.size.height += br.origin.y;
3006           br.origin.y = 0;
3007         }
3008       if (br.origin.x <= fibw+1 + box_line_vwidth)
3009         {
3010           br.size.width += br.origin.x;
3011           br.origin.x = 0;
3012         }
3013       if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) <= fibw+1)
3014         br.size.width += fibw;
3015     }
3017   NSRectFill (br);
3019   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3020   if (img != nil)
3021     [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3022                 operation: NSCompositeSourceOver];
3024   if (s->hl == DRAW_CURSOR)
3025     {
3026     [FRAME_CURSOR_COLOR (s->f) set];
3027     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3028       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3029     else
3030       /* Currently on NS img->mask is always 0. Since
3031          get_window_cursor_type specifies a hollow box cursor when on
3032          a non-masked image we never reach this clause. But we put it
3033          in in anticipation of better support for image masks on
3034          NS. */
3035       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3036     }
3037   else
3038     {
3039       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3040     }
3042   /* Draw underline, overline, strike-through. */
3043   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3045   /* Draw relief, if requested */
3046   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3047     {
3048       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3049         {
3050           th = tool_bar_button_relief >= 0 ?
3051             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3052           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3053         }
3054       else
3055         {
3056           th = abs (s->img->relief);
3057           raised_p = (s->img->relief > 0);
3058         }
3060       r.origin.x = x - th;
3061       r.origin.y = y - th;
3062       r.size.width = s->slice.width + 2*th-1;
3063       r.size.height = s->slice.height + 2*th-1;
3064       ns_draw_relief (r, th, raised_p,
3065                       s->slice.y == 0,
3066                       s->slice.y + s->slice.height == s->img->height,
3067                       s->slice.x == 0,
3068                       s->slice.x + s->slice.width == s->img->width, s);
3069     }
3071   /* If there is no mask, the background won't be seen,
3072      so draw a rectangle on the image for the cursor.
3073      Do this for all images, getting transparency right is not reliable.  */
3074   if (s->hl == DRAW_CURSOR)
3075     {
3076       int thickness = abs (s->img->relief);
3077       if (thickness == 0) thickness = 1;
3078       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3079     }
3083 static void
3084 ns_dumpglyphs_stretch (struct glyph_string *s)
3086   NSRect r[2];
3087   int n, i;
3088   struct face *face;
3089   NSColor *fgCol, *bgCol;
3091   if (!s->background_filled_p)
3092     {
3093       n = ns_get_glyph_string_clip_rect (s, r);
3094       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3096       ns_focus (s->f, r, n);
3098       if (s->hl == DRAW_MOUSE_FACE)
3099        {
3100          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3101          if (!face)
3102            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3103        }
3104       else
3105        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3107       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3108       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3110       for (i=0; i<n; i++)
3111         {
3112           if (!s->row->full_width_p)
3113             {
3114               int overrun, leftoverrun;
3116               /* truncate to avoid overwriting fringe and/or scrollbar */
3117               overrun = max (0, (s->x + s->background_width)
3118                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3119                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3120               r[i].size.width -= overrun;
3122               /* truncate to avoid overwriting to left of the window box */
3123               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3124                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3126               if (leftoverrun > 0)
3127                 {
3128                   r[i].origin.x += leftoverrun;
3129                   r[i].size.width -= leftoverrun;
3130                 }
3132               /* XXX: Try to work between problem where a stretch glyph on
3133                  a partially-visible bottom row will clear part of the
3134                  modeline, and another where list-buffers headers and similar
3135                  rows erroneously have visible_height set to 0.  Not sure
3136                  where this is coming from as other terms seem not to show. */
3137               r[i].size.height = min (s->height, s->row->visible_height);
3138             }
3140           /* expand full-width rows over internal borders */
3141           else
3142             {
3143               r[i] = ns_fix_rect_ibw (r[i], FRAME_INTERNAL_BORDER_WIDTH (s->f),
3144                                       FRAME_PIXEL_WIDTH (s->f));
3145             }
3147           [bgCol set];
3149           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3150              overwriting cursor (usually when cursor on a tab) */
3151           if (s->hl == DRAW_CURSOR)
3152             {
3153               CGFloat x, width;
3155               x = r[i].origin.x;
3156               width = s->w->phys_cursor_width;
3157               r[i].size.width -= width;
3158               r[i].origin.x += width;
3160               NSRectFill (r[i]);
3162               /* Draw overlining, etc. on the cursor. */
3163               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3164                 ns_draw_text_decoration (s, face, bgCol, width, x);
3165               else
3166                 ns_draw_text_decoration (s, face, fgCol, width, x);
3167             }
3168           else
3169             {
3170               NSRectFill (r[i]);
3171             }
3173           /* Draw overlining, etc. on the stretch glyph (or the part
3174              of the stretch glyph after the cursor). */
3175           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3176                                    r[i].origin.x);
3177         }
3178       ns_unfocus (s->f);
3179       s->background_filled_p = 1;
3180     }
3184 static void
3185 ns_draw_glyph_string (struct glyph_string *s)
3186 /* --------------------------------------------------------------------------
3187       External (RIF): Main draw-text call.
3188    -------------------------------------------------------------------------- */
3190   /* TODO (optimize): focus for box and contents draw */
3191   NSRect r[2];
3192   int n;
3193   char box_drawn_p = 0;
3195   NSTRACE (ns_draw_glyph_string);
3197   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3198     {
3199       int width;
3200       struct glyph_string *next;
3202       for (width = 0, next = s->next;
3203            next && width < s->right_overhang;
3204            width += next->width, next = next->next)
3205         if (next->first_glyph->type != IMAGE_GLYPH)
3206           {
3207             if (next->first_glyph->type != STRETCH_GLYPH)
3208               {
3209                 n = ns_get_glyph_string_clip_rect (s->next, r);
3210                 ns_focus (s->f, r, n);
3211                 ns_maybe_dumpglyphs_background (s->next, 1);
3212                 ns_unfocus (s->f);
3213               }
3214             else
3215               {
3216                 ns_dumpglyphs_stretch (s->next);
3217               }
3218             next->num_clips = 0;
3219           }
3220     }
3222   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3223         && (s->first_glyph->type == CHAR_GLYPH
3224             || s->first_glyph->type == COMPOSITE_GLYPH))
3225     {
3226       n = ns_get_glyph_string_clip_rect (s, r);
3227       ns_focus (s->f, r, n);
3228       ns_maybe_dumpglyphs_background (s, 1);
3229       ns_dumpglyphs_box_or_relief (s);
3230       ns_unfocus (s->f);
3231       box_drawn_p = 1;
3232     }
3234   switch (s->first_glyph->type)
3235     {
3237     case IMAGE_GLYPH:
3238       n = ns_get_glyph_string_clip_rect (s, r);
3239       ns_focus (s->f, r, n);
3240       ns_dumpglyphs_image (s, r[0]);
3241       ns_unfocus (s->f);
3242       break;
3244     case STRETCH_GLYPH:
3245       ns_dumpglyphs_stretch (s);
3246       break;
3248     case CHAR_GLYPH:
3249     case COMPOSITE_GLYPH:
3250       n = ns_get_glyph_string_clip_rect (s, r);
3251       ns_focus (s->f, r, n);
3253       if (s->for_overlaps || (s->cmp_from > 0
3254                               && ! s->first_glyph->u.cmp.automatic))
3255         s->background_filled_p = 1;
3256       else
3257         ns_maybe_dumpglyphs_background
3258           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3260       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3261                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3262                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3263                       NS_DUMPGLYPH_NORMAL));
3264       ns_tmp_font = (struct nsfont_info *)s->face->font;
3265       if (ns_tmp_font == NULL)
3266           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
3268       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3269         {
3270           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3271           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3272           NS_FACE_FOREGROUND (s->face) = tmp;
3273         }
3275       ns_tmp_font->font.driver->draw
3276         (s, 0, s->nchars, s->x, s->y,
3277          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3278          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
3280       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3281         {
3282           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3283           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3284           NS_FACE_FOREGROUND (s->face) = tmp;
3285         }
3287       ns_unfocus (s->f);
3288       break;
3290     case GLYPHLESS_GLYPH:
3291       n = ns_get_glyph_string_clip_rect (s, r);
3292       ns_focus (s->f, r, n);
3294       if (s->for_overlaps || (s->cmp_from > 0
3295                               && ! s->first_glyph->u.cmp.automatic))
3296         s->background_filled_p = 1;
3297       else
3298         ns_maybe_dumpglyphs_background
3299           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3300       /* ... */
3301       /* Not yet implemented.  */
3302       /* ... */
3303       ns_unfocus (s->f);
3304       break;
3306     default:
3307       abort ();
3308     }
3310   /* Draw box if not done already. */
3311   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3312     {
3313       n = ns_get_glyph_string_clip_rect (s, r);
3314       ns_focus (s->f, r, n);
3315       ns_dumpglyphs_box_or_relief (s);
3316       ns_unfocus (s->f);
3317     }
3319   s->num_clips = 0;
3324 /* ==========================================================================
3326     Event loop
3328    ========================================================================== */
3331 static void
3332 ns_send_appdefined (int value)
3333 /* --------------------------------------------------------------------------
3334     Internal: post an appdefined event which EmacsApp-sendEvent will
3335               recognize and take as a command to halt the event loop.
3336    -------------------------------------------------------------------------- */
3338   /*NSTRACE (ns_send_appdefined); */
3340   /* Only post this event if we haven't already posted one.  This will end
3341        the [NXApp run] main loop after having processed all events queued at
3342        this moment.  */
3343   if (send_appdefined)
3344     {
3345       NSEvent *nxev;
3347       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3348       send_appdefined = NO;
3350       /* Don't need wakeup timer any more */
3351       if (timed_entry)
3352         {
3353           [timed_entry invalidate];
3354           [timed_entry release];
3355           timed_entry = nil;
3356         }
3358       /* Ditto for file descriptor poller */
3359       if (fd_entry)
3360         {
3361           [fd_entry invalidate];
3362           [fd_entry release];
3363           fd_entry = nil;
3364         }
3366       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3367                                 location: NSMakePoint (0, 0)
3368                            modifierFlags: 0
3369                                timestamp: 0
3370                             windowNumber: [[NSApp mainWindow] windowNumber]
3371                                  context: [NSApp context]
3372                                  subtype: 0
3373                                    data1: value
3374                                    data2: 0];
3376       /* Post an application defined event on the event queue.  When this is
3377          received the [NXApp run] will return, thus having processed all
3378          events which are currently queued.  */
3379       [NSApp postEvent: nxev atStart: NO];
3380     }
3384 static int
3385 ns_read_socket (struct terminal *terminal, int expected,
3386                 struct input_event *hold_quit)
3387 /* --------------------------------------------------------------------------
3388      External (hook): Post an event to ourself and keep reading events until
3389      we read it back again.  In effect process all events which were waiting.
3390      From 21+ we have to manage the event buffer ourselves.
3391    -------------------------------------------------------------------------- */
3393   struct input_event ev;
3394   int nevents;
3396 /* NSTRACE (ns_read_socket); */
3398   if (interrupt_input_blocked)
3399     {
3400       interrupt_input_pending = 1;
3401 #ifdef SYNC_INPUT
3402       pending_signals = 1;
3403 #endif
3404       return -1;
3405     }
3407   interrupt_input_pending = 0;
3408 #ifdef SYNC_INPUT
3409   pending_signals = pending_atimers;
3410 #endif
3412   BLOCK_INPUT;
3413   n_emacs_events_pending = 0;
3414   EVENT_INIT (ev);
3415   emacs_event = &ev;
3416   q_event_ptr = hold_quit;
3418   /* we manage autorelease pools by allocate/reallocate each time around
3419      the loop; strict nesting is occasionally violated but seems not to
3420      matter.. earlier methods using full nesting caused major memory leaks */
3421   [outerpool release];
3422   outerpool = [[NSAutoreleasePool alloc] init];
3424   /* If have pending open-file requests, attend to the next one of those. */
3425   if (ns_pending_files && [ns_pending_files count] != 0
3426       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3427     {
3428       [ns_pending_files removeObjectAtIndex: 0];
3429     }
3430   /* Deal with pending service requests. */
3431   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3432     && [(EmacsApp *)
3433          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3434                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3435     {
3436       [ns_pending_service_names removeObjectAtIndex: 0];
3437       [ns_pending_service_args removeObjectAtIndex: 0];
3438     }
3439   else
3440     {
3441       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3442          to ourself, otherwise [NXApp run] will never exit.  */
3443       send_appdefined = YES;
3445       /* If called via ns_select, this is called once with expected=1,
3446          because we expect either the timeout or file descriptor activity.
3447          In this case the first event through will either be real input or
3448          one of these.  read_avail_input() then calls once more with expected=0
3449          and in that case we need to return quickly if there is nothing.
3450          If we're being called outside of that, it's also OK to return quickly
3451          after one iteration through the event loop, since other terms do
3452          this and emacs expects it. */
3453       if (!(inNsSelect && expected))
3454         {
3455           /* Post an application defined event on the event queue.  When this is
3456              received the [NXApp run] will return, thus having processed all
3457              events which are currently queued, if any.  */
3458           ns_send_appdefined (-1);
3459         }
3461       [NSApp run];
3462     }
3464   nevents = n_emacs_events_pending;
3465   n_emacs_events_pending = 0;
3466   emacs_event = q_event_ptr = NULL;
3467   UNBLOCK_INPUT;
3469   return nevents;
3474 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3475            fd_set *exceptfds, struct timeval *timeout)
3476 /* --------------------------------------------------------------------------
3477      Replacement for select, checking for events
3478    -------------------------------------------------------------------------- */
3480   int result;
3481   double time;
3482   NSEvent *ev;
3483 /*  NSTRACE (ns_select); */
3485   if (NSApp == nil || inNsSelect == 1 /* || ([NSApp isActive] == NO &&
3486                       [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil
3487  inMode:NSDefaultRunLoopMode dequeue:NO] == nil) */)
3488     return select (nfds, readfds, writefds, exceptfds, timeout);
3490   /* Save file descriptor set, which gets overwritten in calls to select ()
3491      Note, this is called from process.c, and only readfds is ever set */
3492   if (readfds)
3493     {
3494       memcpy (&select_readfds, readfds, sizeof (fd_set));
3495       select_nfds = nfds;
3496     }
3497   else
3498     select_nfds = 0;
3500     /* Try an initial select for pending data on input files */
3501   select_timeout.tv_sec = select_timeout.tv_usec = 0;
3502   result = select (nfds, readfds, writefds, exceptfds, &select_timeout);
3503   if (result)
3504     return result;
3506   /* if (!timeout || timed_entry || fd_entry)
3507        fprintf (stderr, "assertion failed: timeout null or timed_entry/fd_entry non-null in ns_select\n"); */
3509     /* set a timeout and run the main AppKit event loop while continuing
3510        to monitor the files */
3511   time = ((double) timeout->tv_sec) + ((double) timeout->tv_usec)/1000000.0;
3512   timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3513                                            target: NSApp
3514                                          selector: @selector (timeout_handler:)
3515                                          userInfo: 0
3516                                           repeats: YES] /* for safe removal */
3517                                                          retain];
3519   /* set a periodic task to try the select () again */
3520   fd_entry = [[NSTimer scheduledTimerWithTimeInterval: 0.1
3521                                                target: NSApp
3522                                              selector: @selector (fd_handler:)
3523                                              userInfo: 0
3524                                               repeats: YES]
3525                retain];
3527   /* Let Application dispatch events until it receives an event of the type
3528      NX_APPDEFINED, which should only be sent by timeout_handler.
3529      We tell read_avail_input() that input is "expected" because we do expect
3530      either the timeout or fd handler to fire, and if they don't, the original
3531      call from process.c that got us here expects us to wait until some input
3532      comes. */
3533   inNsSelect = 1;
3534   gobble_input (1);
3535   ev = last_appdefined_event;
3536   inNsSelect = 0;
3538   if (ev)
3539     {
3540       int t;
3541       if ([ev type] != NSApplicationDefined)
3542         abort ();
3544       t = [ev data1];
3545       last_appdefined_event = 0;
3547       if (t == -2)
3548         {
3549           /* The NX_APPDEFINED event we received was a timeout. */
3550           return 0;
3551         }
3552       else if (t == -1)
3553         {
3554           /* The NX_APPDEFINED event we received was the result of
3555              at least one real input event arriving.  */
3556           errno = EINTR;
3557           return -1;
3558         }
3559       else
3560         {
3561           /* Received back from select () in fd_handler; copy the results */
3562           if (readfds)
3563             memcpy (readfds, &select_readfds, sizeof (fd_set));
3564           return t;
3565         }
3566     }
3567   /* never reached, shut compiler up */
3568   return 0;
3573 /* ==========================================================================
3575     Scrollbar handling
3577    ========================================================================== */
3580 static void
3581 ns_set_vertical_scroll_bar (struct window *window,
3582                            int portion, int whole, int position)
3583 /* --------------------------------------------------------------------------
3584       External (hook): Update or add scrollbar
3585    -------------------------------------------------------------------------- */
3587   Lisp_Object win;
3588   NSRect r, v;
3589   struct frame *f = XFRAME (WINDOW_FRAME (window));
3590   EmacsView *view = FRAME_NS_VIEW (f);
3591   int window_y, window_height;
3592   BOOL barOnVeryLeft, barOnVeryRight;
3593   int top, left, height, width, sb_width, sb_left;
3594   EmacsScroller *bar;
3595 static int count = 0;
3597   /* optimization; display engine sends WAY too many of these.. */
3598   if (!NILP (window->vertical_scroll_bar))
3599     {
3600       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3601       if ([bar checkSamePosition: position portion: portion whole: whole])
3602         {
3603           if (view->scrollbarsNeedingUpdate == 0)
3604             {
3605               if (!windows_or_buffers_changed)
3606                   return;
3607             }
3608           else
3609             view->scrollbarsNeedingUpdate--;
3610         }
3611     }
3613   NSTRACE (ns_set_vertical_scroll_bar);
3615   /* Get dimensions.  */
3616   window_box (window, -1, 0, &window_y, 0, &window_height);
3617   top = window_y;
3618   height = window_height;
3619   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3620   left = WINDOW_SCROLL_BAR_AREA_X (window);
3622   if (top < 5) /* top scrollbar adjustment */
3623     {
3624       top -= FRAME_INTERNAL_BORDER_WIDTH (f);
3625       height += FRAME_INTERNAL_BORDER_WIDTH (f);
3626     }
3628   /* allow for displaying a skinnier scrollbar than char area allotted */
3629   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3630     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3632   barOnVeryLeft = left < 5;
3633   barOnVeryRight = FRAME_PIXEL_WIDTH (f) - left - width < 5;
3634   sb_left = left + FRAME_INTERNAL_BORDER_WIDTH (f)
3635       * (barOnVeryLeft ? -1 : (barOnVeryRight ? 1 : 0));
3637   r = NSMakeRect (sb_left, top, sb_width, height);
3638   /* the parent view is flipped, so we need to flip y value */
3639   v = [view frame];
3640   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3642   XSETWINDOW (win, window);
3643   BLOCK_INPUT;
3645   /* we want at least 5 lines to display a scrollbar */
3646   if (WINDOW_TOTAL_LINES (window) < 5)
3647     {
3648       if (!NILP (window->vertical_scroll_bar))
3649         {
3650           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3651           [bar removeFromSuperview];
3652           window->vertical_scroll_bar = Qnil;
3653         }
3654       ns_clear_frame_area (f, sb_left, top, width, height);
3655       UNBLOCK_INPUT;
3656       return;
3657     }
3659   if (NILP (window->vertical_scroll_bar))
3660     {
3661       ns_clear_frame_area (f, sb_left, top, width, height);
3662       bar = [[EmacsScroller alloc] initFrame: r window: win];
3663       window->vertical_scroll_bar = make_save_value (bar, 0);
3664     }
3665   else
3666     {
3667       NSRect oldRect;
3668       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3669       oldRect = [bar frame];
3670       r.size.width = oldRect.size.width;
3671       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3672         {
3673           if (oldRect.origin.x != r.origin.x)
3674               ns_clear_frame_area (f, sb_left, top, width, height);
3675           [bar setFrame: r];
3676         }
3677     }
3679   [bar setPosition: position portion: portion whole: whole];
3680   UNBLOCK_INPUT;
3684 static void
3685 ns_condemn_scroll_bars (struct frame *f)
3686 /* --------------------------------------------------------------------------
3687      External (hook): arrange for all frame's scrollbars to be removed
3688      at next call to judge_scroll_bars, except for those redeemed.
3689    -------------------------------------------------------------------------- */
3691   int i;
3692   id view;
3693   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3695   NSTRACE (ns_condemn_scroll_bars);
3697   for (i =[subviews count]-1; i >= 0; i--)
3698     {
3699       view = [subviews objectAtIndex: i];
3700       if ([view isKindOfClass: [EmacsScroller class]])
3701         [view condemn];
3702     }
3706 static void
3707 ns_redeem_scroll_bar (struct window *window)
3708 /* --------------------------------------------------------------------------
3709      External (hook): arrange to spare this window's scrollbar
3710      at next call to judge_scroll_bars.
3711    -------------------------------------------------------------------------- */
3713   id bar;
3714   NSTRACE (ns_redeem_scroll_bar);
3715   if (!NILP (window->vertical_scroll_bar))
3716     {
3717       bar =XNS_SCROLL_BAR (window->vertical_scroll_bar);
3718       [bar reprieve];
3719     }
3723 static void
3724 ns_judge_scroll_bars (struct frame *f)
3725 /* --------------------------------------------------------------------------
3726      External (hook): destroy all scrollbars on frame that weren't
3727      redeemed after call to condemn_scroll_bars.
3728    -------------------------------------------------------------------------- */
3730   int i;
3731   id view;
3732   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3733   NSTRACE (ns_judge_scroll_bars);
3734   for (i =[subviews count]-1; i >= 0; i--)
3735     {
3736       view = [subviews objectAtIndex: i];
3737       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3738       [view judge];
3739     }
3743 void
3744 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
3746   /* XXX irrelevant under NS */
3751 /* ==========================================================================
3753     Initialization
3755    ========================================================================== */
3758 x_display_pixel_height (struct ns_display_info *dpyinfo)
3760   NSScreen *screen = [NSScreen mainScreen];
3761   return [screen frame].size.height;
3765 x_display_pixel_width (struct ns_display_info *dpyinfo)
3767   NSScreen *screen = [NSScreen mainScreen];
3768   return [screen frame].size.width;
3772 static Lisp_Object ns_string_to_lispmod (const char *s)
3773 /* --------------------------------------------------------------------------
3774      Convert modifier name to lisp symbol
3775    -------------------------------------------------------------------------- */
3777   if (!strncmp (SDATA (SYMBOL_NAME (Qmeta)), s, 10))
3778     return Qmeta;
3779   else if (!strncmp (SDATA (SYMBOL_NAME (Qsuper)), s, 10))
3780     return Qsuper;
3781   else if (!strncmp (SDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3782     return Qcontrol;
3783   else if (!strncmp (SDATA (SYMBOL_NAME (Qalt)), s, 10))
3784     return Qalt;
3785   else if (!strncmp (SDATA (SYMBOL_NAME (Qhyper)), s, 10))
3786     return Qhyper;
3787   else if (!strncmp (SDATA (SYMBOL_NAME (Qnone)), s, 10))
3788     return Qnone;
3789   else
3790     return Qnil;
3794 static Lisp_Object ns_mod_to_lisp (int m)
3795 /* --------------------------------------------------------------------------
3796      Convert modifier code (see lisp.h) to lisp symbol
3797    -------------------------------------------------------------------------- */
3799   if (m == CHAR_META)
3800     return Qmeta;
3801   else if (m == CHAR_SUPER)
3802     return Qsuper;
3803   else if (m == CHAR_CTL)
3804     return Qcontrol;
3805   else if (m == CHAR_ALT)
3806     return Qalt;
3807   else if (m == CHAR_HYPER)
3808     return Qhyper;
3809   else /* if (m == 0) */
3810     return Qnone;
3814 static void
3815 ns_default (const char *parameter, Lisp_Object *result,
3816            Lisp_Object yesval, Lisp_Object noval,
3817            BOOL is_float, BOOL is_modstring)
3818 /* --------------------------------------------------------------------------
3819       Check a parameter value in user's preferences
3820    -------------------------------------------------------------------------- */
3822   const char *value = ns_get_defaults_value (parameter);
3824   if (value)
3825     {
3826       double f;
3827       char *pos;
3828       if (strcasecmp (value, "YES") == 0)
3829         *result = yesval;
3830       else if (strcasecmp (value, "NO") == 0)
3831         *result = noval;
3832       else if (is_float && (f = strtod (value, &pos), pos != value))
3833         *result = make_float (f);
3834       else if (is_modstring && value)
3835         *result = ns_string_to_lispmod (value);
3836       else fprintf (stderr,
3837                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3838     }
3842 void
3843 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3844 /* --------------------------------------------------------------------------
3845       Initialize global info and storage for display.
3846    -------------------------------------------------------------------------- */
3848     NSScreen *screen = [NSScreen mainScreen];
3849     NSWindowDepth depth = [screen depth];
3850     Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
3852     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3853     dpyinfo->resy = 72.27;
3854     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3855                                                   NSColorSpaceFromDepth (depth)]
3856                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3857                                                  NSColorSpaceFromDepth (depth)];
3858     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3859     dpyinfo->image_cache = make_image_cache ();
3860     dpyinfo->color_table
3861       = (struct ns_color_table *)xmalloc (sizeof (struct ns_color_table));
3862     dpyinfo->color_table->colors = NULL;
3863     dpyinfo->root_window = 42; /* a placeholder.. */
3865     hlinfo->mouse_face_mouse_frame = NULL;
3866     hlinfo->mouse_face_deferred_gc = 0;
3867     hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
3868     hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
3869     hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
3870     hlinfo->mouse_face_window = hlinfo->mouse_face_overlay = Qnil;
3871     hlinfo->mouse_face_hidden = 0;
3873     hlinfo->mouse_face_mouse_x = hlinfo->mouse_face_mouse_y = 0;
3874     hlinfo->mouse_face_defer = 0;
3876     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3878     dpyinfo->n_fonts = 0;
3879     dpyinfo->smallest_font_height = 1;
3880     dpyinfo->smallest_char_width = 1;
3884 /* This and next define (many of the) public functions in this file. */
3885 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3886          with using despite presence in the "system dependent" redisplay
3887          interface.  In addition, many of the ns_ methods have code that is
3888          shared with all terms, indicating need for further refactoring. */
3889 extern frame_parm_handler ns_frame_parm_handlers[];
3890 static struct redisplay_interface ns_redisplay_interface =
3892   ns_frame_parm_handlers,
3893   x_produce_glyphs,
3894   x_write_glyphs,
3895   x_insert_glyphs,
3896   x_clear_end_of_line,
3897   ns_scroll_run,
3898   ns_after_update_window_line,
3899   ns_update_window_begin,
3900   ns_update_window_end,
3901   x_cursor_to,
3902   ns_flush,
3903   0, /* flush_display_optional */
3904   x_clear_window_mouse_face,
3905   x_get_glyph_overhangs,
3906   x_fix_overlapping_area,
3907   ns_draw_fringe_bitmap,
3908   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3909   0, /* destroy_fringe_bitmap */
3910   ns_compute_glyph_string_overhangs,
3911   ns_draw_glyph_string, /* interface to nsfont.m */
3912   ns_define_frame_cursor,
3913   ns_clear_frame_area,
3914   ns_draw_window_cursor,
3915   ns_draw_vertical_window_border,
3916   ns_shift_glyphs_for_insert
3920 static void
3921 ns_delete_display (struct ns_display_info *dpyinfo)
3923   /* TODO... */
3927 /* This function is called when the last frame on a display is deleted. */
3928 static void
3929 ns_delete_terminal (struct terminal *terminal)
3931   struct ns_display_info *dpyinfo = terminal->display_info.ns;
3932   int i;
3934   /* Protect against recursive calls.  delete_frame in
3935      delete_terminal calls us back when it deletes our last frame.  */
3936   if (!terminal->name)
3937     return;
3939   BLOCK_INPUT;
3941   x_destroy_all_bitmaps (dpyinfo);
3942   ns_delete_display (dpyinfo);
3943   UNBLOCK_INPUT;
3947 static struct terminal *
3948 ns_create_terminal (struct ns_display_info *dpyinfo)
3949 /* --------------------------------------------------------------------------
3950       Set up use of NS before we make the first connection.
3951    -------------------------------------------------------------------------- */
3953   struct terminal *terminal;
3955   NSTRACE (ns_create_terminal);
3957   terminal = create_terminal ();
3959   terminal->type = output_ns;
3960   terminal->display_info.ns = dpyinfo;
3961   dpyinfo->terminal = terminal;
3963   terminal->rif = &ns_redisplay_interface;
3965   terminal->clear_frame_hook = ns_clear_frame;
3966   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
3967   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
3968   terminal->ring_bell_hook = ns_ring_bell;
3969   terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
3970   terminal->set_terminal_modes_hook = ns_set_terminal_modes;
3971   terminal->update_begin_hook = ns_update_begin;
3972   terminal->update_end_hook = ns_update_end;
3973   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
3974   terminal->read_socket_hook = ns_read_socket;
3975   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
3976   terminal->mouse_position_hook = ns_mouse_position;
3977   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
3978   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
3980   terminal->fullscreen_hook = 0; /* see XTfullscreen_hook */
3982   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
3983   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
3984   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
3985   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
3987   terminal->delete_frame_hook = x_destroy_window;
3988   terminal->delete_terminal_hook = ns_delete_terminal;
3990   terminal->scroll_region_ok = 1;
3991   terminal->char_ins_del_ok = 1;
3992   terminal->line_ins_del_ok = 1;
3993   terminal->fast_clear_end_of_line = 1;
3994   terminal->memory_below_frame = 0;
3996   return terminal;
4000 struct ns_display_info *
4001 ns_term_init (Lisp_Object display_name)
4002 /* --------------------------------------------------------------------------
4003      Start the Application and get things rolling.
4004    -------------------------------------------------------------------------- */
4006   struct terminal *terminal;
4007   struct ns_display_info *dpyinfo;
4008   static int ns_initialized = 0;
4009   Lisp_Object tmp;
4011   NSTRACE (ns_term_init);
4013   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4014   /*GSDebugAllocationActive (YES); */
4015   BLOCK_INPUT;
4016   handling_signal = 0;
4018   if (!ns_initialized)
4019     {
4020       baud_rate = 38400;
4021       Fset_input_interrupt_mode (Qnil);
4022       ns_initialized = 1;
4023     }
4025   ns_pending_files = [[NSMutableArray alloc] init];
4026   ns_pending_service_names = [[NSMutableArray alloc] init];
4027   ns_pending_service_args = [[NSMutableArray alloc] init];
4029   /* Start app and create the main menu, window, view.
4030      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4031      The view will then ask the NSApp to stop and return to Emacs. */
4032   [EmacsApp sharedApplication];
4033   if (NSApp == nil)
4034     return NULL;
4035   [NSApp setDelegate: NSApp];
4037   /* debugging: log all notifications */
4038   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4039                                          selector: @selector (logNotification:)
4040                                              name: nil object: nil]; */
4042   dpyinfo = (struct ns_display_info *)xmalloc (sizeof (struct ns_display_info));
4043   memset (dpyinfo, 0, sizeof (struct ns_display_info));
4045   ns_initialize_display_info (dpyinfo);
4046   terminal = ns_create_terminal (dpyinfo);
4048   terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
4049   init_kboard (terminal->kboard);
4050   KVAR (terminal->kboard, Vwindow_system) = Qns;
4051   terminal->kboard->next_kboard = all_kboards;
4052   all_kboards = terminal->kboard;
4053   /* Don't let the initial kboard remain current longer than necessary.
4054      That would cause problems if a file loaded on startup tries to
4055      prompt in the mini-buffer.  */
4056   if (current_kboard == initial_kboard)
4057     current_kboard = terminal->kboard;
4058   terminal->kboard->reference_count++;
4060   dpyinfo->next = x_display_list;
4061   x_display_list = dpyinfo;
4063   /* Put it on ns_display_name_list */
4064   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
4065                                 ns_display_name_list);
4066   dpyinfo->name_list_element = XCAR (ns_display_name_list);
4068   /* Set the name of the terminal. */
4069   terminal->name = (char *) xmalloc (SBYTES (display_name) + 1);
4070   strncpy (terminal->name, SDATA (display_name), SBYTES (display_name));
4071   terminal->name[SBYTES (display_name)] = 0;
4073   UNBLOCK_INPUT;
4075   if (!inhibit_x_resources)
4076     {
4077       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4078                  Qt, Qnil, NO, NO);
4079       tmp = Qnil;
4080       /* this is a standard variable */
4081       ns_default ("AppleAntiAliasingThreshold", &tmp,
4082                  make_float (10.0), make_float (6.0), YES, NO);
4083       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4084     }
4086   ns_selection_color = [[NSUserDefaults standardUserDefaults]
4087                          stringForKey: @"AppleHighlightColor"];
4088   if (ns_selection_color == nil)
4089     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
4091   {
4092     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4094     if ( cl == nil )
4095       {
4096         Lisp_Object color_file, color_map, color;
4097         int r,g,b;
4098         unsigned long c;
4099         char *name;
4101         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4102                          Fsymbol_value (intern ("data-directory")));
4103         if (NILP (Ffile_readable_p (color_file)))
4104           fatal ("Could not find %s.\n", SDATA (color_file));
4106         color_map = Fx_load_color_file (color_file);
4107         if (NILP (color_map))
4108           fatal ("Could not read %s.\n", SDATA (color_file));
4110         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4111         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4112           {
4113             color = XCAR (color_map);
4114             name = SDATA (XCAR (color));
4115             c = XINT (XCDR (color));
4116             [cl setColor:
4117                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4118                                             green: GREEN_FROM_ULONG (c) / 255.0
4119                                              blue: BLUE_FROM_ULONG (c) / 255.0
4120                                             alpha: 1.0]
4121                   forKey: [NSString stringWithUTF8String: name]];
4122           }
4123         [cl writeToFile: nil];
4124       }
4125   }
4127   {
4128     char c[128];
4129 #ifdef NS_IMPL_GNUSTEP
4130     strncpy (c, gnustep_base_version, sizeof (c));
4131 #else
4132     /*PSnextrelease (128, c); */
4133     snprintf (c, sizeof (c), "%g", NSAppKitVersionNumber);
4134 #endif
4135     Vwindow_system_version = build_string (c);
4136   }
4138   delete_keyboard_wait_descriptor (0);
4140   ns_app_name = [[NSProcessInfo processInfo] processName];
4142 /* Set up OS X app menu */
4143 #ifdef NS_IMPL_COCOA
4144   {
4145     NSMenu *appMenu;
4146     NSMenuItem *item;
4147     /* set up the application menu */
4148     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4149     [svcsMenu setAutoenablesItems: NO];
4150     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4151     [appMenu setAutoenablesItems: NO];
4152     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4153     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4155     [appMenu insertItemWithTitle: @"About Emacs"
4156                           action: @selector (orderFrontStandardAboutPanel:)
4157                    keyEquivalent: @""
4158                          atIndex: 0];
4159     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4160     [appMenu insertItemWithTitle: @"Preferences..."
4161                           action: @selector (showPreferencesWindow:)
4162                    keyEquivalent: @","
4163                          atIndex: 2];
4164     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4165     item = [appMenu insertItemWithTitle: @"Services"
4166                                  action: @selector (menuDown:)
4167                           keyEquivalent: @""
4168                                 atIndex: 4];
4169     [appMenu setSubmenu: svcsMenu forItem: item];
4170     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4171     [appMenu insertItemWithTitle: @"Hide Emacs"
4172                           action: @selector (hide:)
4173                    keyEquivalent: @"h"
4174                          atIndex: 6];
4175     item =  [appMenu insertItemWithTitle: @"Hide Others"
4176                           action: @selector (hideOtherApplications:)
4177                    keyEquivalent: @"h"
4178                          atIndex: 7];
4179     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4180     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4181     [appMenu insertItemWithTitle: @"Quit Emacs"
4182                           action: @selector (terminate:)
4183                    keyEquivalent: @"q"
4184                          atIndex: 9];
4186     item = [mainMenu insertItemWithTitle: ns_app_name
4187                                   action: @selector (menuDown:)
4188                            keyEquivalent: @""
4189                                  atIndex: 0];
4190     [mainMenu setSubmenu: appMenu forItem: item];
4191     [dockMenu insertItemWithTitle: @"New Frame"
4192                            action: @selector (newFrame:)
4193                     keyEquivalent: @""
4194                           atIndex: 0];
4196     [NSApp setMainMenu: mainMenu];
4197     [NSApp setAppleMenu: appMenu];
4198     [NSApp setServicesMenu: svcsMenu];
4199     /* Needed at least on Cocoa, to get dock menu to show windows */
4200     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4202     [[NSNotificationCenter defaultCenter]
4203       addObserver: mainMenu
4204          selector: @selector (trackingNotification:)
4205              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4206     [[NSNotificationCenter defaultCenter]
4207       addObserver: mainMenu
4208          selector: @selector (trackingNotification:)
4209              name: NSMenuDidEndTrackingNotification object: mainMenu];
4210   }
4211 #endif /* MAC OS X menu setup */
4213   [NSApp run];
4215   return dpyinfo;
4219 void
4220 ns_term_shutdown (int sig)
4222   [[NSUserDefaults standardUserDefaults] synchronize];
4224   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4225   if (STRINGP (Vauto_save_list_file_name))
4226     unlink (SDATA (Vauto_save_list_file_name));
4228   if (sig == 0 || sig == SIGTERM)
4229     {
4230       [NSApp terminate: NSApp];
4231     }
4232   else // force a stack trace to happen
4233     {
4234       abort();
4235     }
4239 /* ==========================================================================
4241     EmacsApp implementation
4243    ========================================================================== */
4246 @implementation EmacsApp
4248 - (void)logNotification: (NSNotification *)notification
4250   const char *name = [[notification name] UTF8String];
4251   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4252       && !strstr (name, "WindowNumber"))
4253     NSLog (@"notification: '%@'", [notification name]);
4257 - (void)sendEvent: (NSEvent *)theEvent
4258 /* --------------------------------------------------------------------------
4259      Called when NSApp is running for each event received.  Used to stop
4260      the loop when we choose, since there's no way to just run one iteration.
4261    -------------------------------------------------------------------------- */
4263   int type = [theEvent type];
4264   NSWindow *window = [theEvent window];
4265 /*  NSTRACE (sendEvent); */
4266 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4268 #ifdef NS_IMPL_COCOA
4269   if (type == NSApplicationDefined
4270       && [theEvent data2] == NSAPP_DATA2_RUNASSCRIPT)
4271     {
4272       ns_run_ascript ();
4273       [self stop: self];
4274       return;
4275     }
4276 #endif
4278   if (type == NSCursorUpdate && window == nil)
4279     {
4280       fprintf (stderr, "Dropping external cursor update event.\n");
4281       return;
4282     }
4284 #ifdef NS_IMPL_COCOA
4285   /* pass mouse down in resize handle and subsequent drags directly to
4286      EmacsWindow so we can generate continuous redisplays */
4287   if (ns_in_resize)
4288     {
4289       if (type == NSLeftMouseDragged)
4290         {
4291           [window mouseDragged: theEvent];
4292           return;
4293         }
4294       else if (type == NSLeftMouseUp)
4295         {
4296           [window mouseUp: theEvent];
4297           return;
4298         }
4299     }
4300   else if (type == NSLeftMouseDown)
4301     {
4302       NSRect r = ns_resize_handle_rect (window);
4303       if (NSPointInRect ([theEvent locationInWindow], r))
4304         {
4305           ns_in_resize = YES;
4306           [window mouseDown: theEvent];
4307           return;
4308         }
4309     }
4310 #endif
4312   if (type == NSApplicationDefined)
4313     {
4314       /* Events posted by ns_send_appdefined interrupt the run loop here.
4315          But, if a modal window is up, an appdefined can still come through,
4316          (e.g., from a makeKeyWindow event) but stopping self also stops the
4317          modal loop. Just defer it until later. */
4318       if ([NSApp modalWindow] == nil)
4319         {
4320           last_appdefined_event = theEvent;
4321           [self stop: self];
4322         }
4323       else
4324         {
4325           send_appdefined = YES;
4326         }
4327     }
4329   [super sendEvent: theEvent];
4333 - (void)showPreferencesWindow: (id)sender
4335   struct frame *emacsframe = SELECTED_FRAME ();
4336   NSEvent *theEvent = [NSApp currentEvent];
4338   if (!emacs_event)
4339     return;
4340   emacs_event->kind = NS_NONKEY_EVENT;
4341   emacs_event->code = KEY_NS_SHOW_PREFS;
4342   emacs_event->modifiers = 0;
4343   EV_TRAILER (theEvent);
4347 - (void)newFrame: (id)sender
4349   struct frame *emacsframe = SELECTED_FRAME ();
4350   NSEvent *theEvent = [NSApp currentEvent];
4352   if (!emacs_event)
4353     return;
4354   emacs_event->kind = NS_NONKEY_EVENT;
4355   emacs_event->code = KEY_NS_NEW_FRAME;
4356   emacs_event->modifiers = 0;
4357   EV_TRAILER (theEvent);
4361 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4362 - (BOOL) openFile: (NSString *)fileName
4364   struct frame *emacsframe = SELECTED_FRAME ();
4365   NSEvent *theEvent = [NSApp currentEvent];
4367   if (!emacs_event)
4368     return NO;
4370   emacs_event->kind = NS_NONKEY_EVENT;
4371   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4372   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4373   ns_input_line = Qnil; /* can be start or cons start,end */
4374   emacs_event->modifiers =0;
4375   EV_TRAILER (theEvent);
4377   return YES;
4381 /* **************************************************************************
4383       EmacsApp delegate implementation
4385    ************************************************************************** */
4387 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4388 /* --------------------------------------------------------------------------
4389      When application is loaded, terminate event loop in ns_term_init
4390    -------------------------------------------------------------------------- */
4392   NSTRACE (applicationDidFinishLaunching);
4393   [NSApp setServicesProvider: NSApp];
4394   ns_send_appdefined (-2);
4398 /* Termination sequences:
4399     C-x C-c:
4400     Cmd-Q:
4401     MenuBar | File | Exit:
4402     Select Quit from App menubar:
4403         -terminate
4404         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4405         ns_term_shutdown()
4407     Select Quit from Dock menu:
4408     Logout attempt:
4409         -appShouldTerminate
4410           Cancel -> Nothing else
4411           Accept ->
4413           -terminate
4414           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4415           ns_term_shutdown()
4419 - (void) terminate: (id)sender
4421   struct frame *emacsframe = SELECTED_FRAME ();
4423   if (!emacs_event)
4424     return;
4426   emacs_event->kind = NS_NONKEY_EVENT;
4427   emacs_event->code = KEY_NS_POWER_OFF;
4428   emacs_event->arg = Qt; /* mark as non-key event */
4429   EV_TRAILER ((id)nil);
4433 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4435   int ret;
4437   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4438     return NSTerminateNow;
4440     ret = NSRunAlertPanel(ns_app_name,
4441                           [NSString stringWithUTF8String:"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?"],
4442                           @"Save Buffers and Exit", @"Cancel", nil);
4444     if (ret == NSAlertDefaultReturn)
4445         return NSTerminateNow;
4446     else if (ret == NSAlertAlternateReturn)
4447         return NSTerminateCancel;
4448     return NSTerminateNow;  /* just in case */
4452 /*   Notification from the Workspace to open a file */
4453 - (BOOL)application: sender openFile: (NSString *)file
4455   [ns_pending_files addObject: file];
4456   return YES;
4460 /*   Open a file as a temporary file */
4461 - (BOOL)application: sender openTempFile: (NSString *)file
4463   [ns_pending_files addObject: file];
4464   return YES;
4468 /*   Notification from the Workspace to open a file noninteractively (?) */
4469 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4471   [ns_pending_files addObject: file];
4472   return YES;
4476 /*   Notification from the Workspace to open multiple files */
4477 - (void)application: sender openFiles: (NSArray *)fileList
4479   NSEnumerator *files = [fileList objectEnumerator];
4480   NSString *file;
4481   while ((file = [files nextObject]) != nil)
4482     [ns_pending_files addObject: file];
4484   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4489 /* Handle dock menu requests.  */
4490 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4492   return dockMenu;
4496 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4497 - (void)applicationWillBecomeActive: (NSNotification *)notification
4499   //ns_app_active=YES;
4501 - (void)applicationDidBecomeActive: (NSNotification *)notification
4503   NSTRACE (applicationDidBecomeActive);
4505   //ns_app_active=YES;
4507   ns_update_auto_hide_menu_bar ();
4508   // No constraining takes place when the application is not active.
4509   ns_constrain_all_frames ();
4511 - (void)applicationDidResignActive: (NSNotification *)notification
4513   //ns_app_active=NO;
4514   ns_send_appdefined (-1);
4519 /* ==========================================================================
4521     EmacsApp aux handlers for managing event loop
4523    ========================================================================== */
4526 - (void)timeout_handler: (NSTimer *)timedEntry
4527 /* --------------------------------------------------------------------------
4528      The timeout specified to ns_select has passed.
4529    -------------------------------------------------------------------------- */
4531   /*NSTRACE (timeout_handler); */
4532   ns_send_appdefined (-2);
4535 - (void)fd_handler: (NSTimer *) fdEntry
4536 /* --------------------------------------------------------------------------
4537      Check data waiting on file descriptors and terminate if so
4538    -------------------------------------------------------------------------- */
4540   int result;
4541   /* NSTRACE (fd_handler); */
4543   if (select_nfds == 0)
4544     return;
4546   memcpy (&t_readfds, &select_readfds, sizeof (fd_set));
4548   select_timeout.tv_sec = select_timeout.tv_usec = 0;
4549   result = select (select_nfds, &t_readfds, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
4550                   &select_timeout);
4551   if (result)
4552     {
4553       memcpy (&select_readfds, &t_readfds, sizeof (fd_set));
4554       ns_send_appdefined (result);
4555     }
4560 /* ==========================================================================
4562     Service provision
4564    ========================================================================== */
4566 /* called from system: queue for next pass through event loop */
4567 - (void)requestService: (NSPasteboard *)pboard
4568               userData: (NSString *)userData
4569                  error: (NSString **)error
4571   [ns_pending_service_names addObject: userData];
4572   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4573       SDATA (ns_string_from_pasteboard (pboard))]];
4577 /* called from ns_read_socket to clear queue */
4578 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4580   struct frame *emacsframe = SELECTED_FRAME ();
4581   NSEvent *theEvent = [NSApp currentEvent];
4583   if (!emacs_event)
4584     return NO;
4586   emacs_event->kind = NS_NONKEY_EVENT;
4587   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4588   ns_input_spi_name = build_string ([name UTF8String]);
4589   ns_input_spi_arg = build_string ([arg UTF8String]);
4590   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4591   EV_TRAILER (theEvent);
4593   return YES;
4597 @end  /* EmacsApp */
4601 /* ==========================================================================
4603     EmacsView implementation
4605    ========================================================================== */
4608 @implementation EmacsView
4610 /* needed to inform when window closed from LISP */
4611 - (void) setWindowClosing: (BOOL)closing
4613   windowClosing = closing;
4617 - (void)dealloc
4619   NSTRACE (EmacsView_dealloc);
4620   [toolbar release];
4621   [super dealloc];
4625 /* called on font panel selection */
4626 - (void)changeFont: (id)sender
4628   NSEvent *e =[[self window] currentEvent];
4629   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4630   id newFont;
4631   float size;
4633   NSTRACE (changeFont);
4634   if (!emacs_event)
4635     return;
4637   if (newFont = [sender convertFont:
4638                            ((struct nsfont_info *)face->font)->nsfont])
4639     {
4640       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4642       emacs_event->kind = NS_NONKEY_EVENT;
4643       emacs_event->modifiers = 0;
4644       emacs_event->code = KEY_NS_CHANGE_FONT;
4646       size = [newFont pointSize];
4647       ns_input_fontsize = make_number (lrint (size));
4648       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4649       EV_TRAILER (e);
4650     }
4654 - (BOOL)acceptsFirstResponder
4656   NSTRACE (acceptsFirstResponder);
4657   return YES;
4661 - (void)resetCursorRects
4663   NSRect visible = [self visibleRect];
4664   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4665   NSTRACE (resetCursorRects);
4667   if (currentCursor == nil)
4668     currentCursor = [NSCursor arrowCursor];
4670   if (!NSIsEmptyRect (visible))
4671     [self addCursorRect: visible cursor: currentCursor];
4672   [currentCursor setOnMouseEntered: YES];
4677 /*****************************************************************************/
4678 /* Keyboard handling. */
4679 #define NS_KEYLOG 0
4681 - (void)keyDown: (NSEvent *)theEvent
4683   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4684   int code;
4685   unsigned fnKeysym = 0;
4686   int flags;
4687   static NSMutableArray *nsEvArray;
4688 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4689   static BOOL firstTime = YES;
4690 #endif
4691   int left_is_none;
4693   NSTRACE (keyDown);
4695   /* Rhapsody and OS X give up and down events for the arrow keys */
4696   if (ns_fake_keydown == YES)
4697     ns_fake_keydown = NO;
4698   else if ([theEvent type] != NSKeyDown)
4699     return;
4701   if (!emacs_event)
4702     return;
4704  if (![[self window] isKeyWindow]
4705      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4706      /* we must avoid an infinite loop here. */
4707      && (EmacsView *)[[theEvent window] delegate] != self)
4708    {
4709      /* XXX: There is an occasional condition in which, when Emacs display
4710          updates a different frame from the current one, and temporarily
4711          selects it, then processes some interrupt-driven input
4712          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4713          for some reason that window has its first responder set to the NSView
4714          most recently updated (I guess), which is not the correct one. */
4715      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4716      return;
4717    }
4719   if (nsEvArray == nil)
4720     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4722   [NSCursor setHiddenUntilMouseMoves: YES];
4724   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4725     {
4726       clear_mouse_face (hlinfo);
4727       hlinfo->mouse_face_hidden = 1;
4728     }
4730   if (!processingCompose)
4731     {
4732       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4733         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4734       /* (Carbon way: [theEvent keyCode]) */
4736       /* is it a "function key"? */
4737       fnKeysym = ns_convert_key (code);
4738       if (fnKeysym)
4739         {
4740           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4741              because Emacs treats Delete and KP-Delete same (in simple.el). */
4742           if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4743             code = 0xFF08; /* backspace */
4744           else
4745             code = fnKeysym;
4746         }
4748       /* are there modifiers? */
4749       emacs_event->modifiers = 0;
4750       flags = [theEvent modifierFlags];
4752       if (flags & NSHelpKeyMask)
4753           emacs_event->modifiers |= hyper_modifier;
4755       if (flags & NSShiftKeyMask)
4756         emacs_event->modifiers |= shift_modifier;
4758       if ((flags & NSRightCommandKeyMask) == NSRightCommandKeyMask)
4759         emacs_event->modifiers |= parse_solitary_modifier
4760           (EQ (ns_right_command_modifier, Qleft)
4761            ? ns_command_modifier
4762            : ns_right_command_modifier);
4764       if ((flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask)
4765         {
4766           emacs_event->modifiers |= parse_solitary_modifier
4767             (ns_command_modifier);
4769           /* if super (default), take input manager's word so things like
4770              dvorak / qwerty layout work */
4771           if (EQ (ns_command_modifier, Qsuper)
4772               && !fnKeysym
4773               && [[theEvent characters] length] != 0)
4774             {
4775               /* XXX: the code we get will be unshifted, so if we have
4776                  a shift modifier, must convert ourselves */
4777               if (!(flags & NSShiftKeyMask))
4778                 code = [[theEvent characters] characterAtIndex: 0];
4779 #if 0
4780               /* this is ugly and also requires linking w/Carbon framework
4781                  (for LMGetKbdType) so for now leave this rare (?) case
4782                  undealt with.. in future look into CGEvent methods */
4783               else
4784                 {
4785                   long smv = GetScriptManagerVariable (smKeyScript);
4786                   Handle uchrHandle = GetResource
4787                     ('uchr', GetScriptVariable (smv, smScriptKeys));
4788                   UInt32 dummy = 0;
4789                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
4790                                  [[theEvent characters] characterAtIndex: 0],
4791                                  kUCKeyActionDisplay,
4792                                  (flags & ~NSCommandKeyMask) >> 8,
4793                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
4794                                  &dummy, 1, &dummy, &code);
4795                   code &= 0xFF;
4796                 }
4797 #endif
4798             }
4799         }
4801       if ((flags & NSRightControlKeyMask) == NSRightControlKeyMask)
4802           emacs_event->modifiers |= parse_solitary_modifier
4803               (EQ (ns_right_control_modifier, Qleft)
4804                ? ns_control_modifier
4805                : ns_right_control_modifier);
4807       if ((flags & NSLeftControlKeyMask) == NSLeftControlKeyMask)
4808         emacs_event->modifiers |= parse_solitary_modifier
4809           (ns_control_modifier);
4811       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
4812           emacs_event->modifiers |=
4813             parse_solitary_modifier (ns_function_modifier);
4815       left_is_none = NILP (ns_alternate_modifier)
4816         || EQ (ns_alternate_modifier, Qnone);
4818       if ((flags & NSRightAlternateKeyMask) == NSRightAlternateKeyMask)
4819         {
4820           if ((NILP (ns_right_alternate_modifier)
4821                || EQ (ns_right_alternate_modifier, Qnone)
4822                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
4823               && !fnKeysym)
4824             {   /* accept pre-interp alt comb */
4825               if ([[theEvent characters] length] > 0)
4826                 code = [[theEvent characters] characterAtIndex: 0];
4827               /*HACK: clear lone shift modifier to stop next if from firing */
4828               if (emacs_event->modifiers == shift_modifier)
4829                 emacs_event->modifiers = 0;
4830             }
4831           else
4832             emacs_event->modifiers |= parse_solitary_modifier
4833               (EQ (ns_right_alternate_modifier, Qleft)
4834                ? ns_alternate_modifier
4835                : ns_right_alternate_modifier);
4836         }
4838       if ((flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask) /* default = meta */
4839         {
4840           if (left_is_none && !fnKeysym)
4841             {   /* accept pre-interp alt comb */
4842               if ([[theEvent characters] length] > 0)
4843                 code = [[theEvent characters] characterAtIndex: 0];
4844               /*HACK: clear lone shift modifier to stop next if from firing */
4845               if (emacs_event->modifiers == shift_modifier)
4846                 emacs_event->modifiers = 0;
4847             }
4848           else
4849               emacs_event->modifiers |=
4850                 parse_solitary_modifier (ns_alternate_modifier);
4851         }
4853   if (NS_KEYLOG)
4854     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
4855              code, fnKeysym, flags, emacs_event->modifiers);
4857       /* if it was a function key or had modifiers, pass it directly to emacs */
4858       if (fnKeysym || (emacs_event->modifiers
4859                        && (emacs_event->modifiers != shift_modifier)
4860                        && [[theEvent charactersIgnoringModifiers] length] > 0))
4861 /*[[theEvent characters] length] */
4862         {
4863           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4864           if (code < 0x20)
4865             code |= (1<<28)|(3<<16);
4866           else if (code == 0x7f)
4867             code |= (1<<28)|(3<<16);
4868           else if (!fnKeysym)
4869             emacs_event->kind = code > 0xFF
4870               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4872           emacs_event->code = code;
4873           EV_TRAILER (theEvent);
4874           return;
4875         }
4876     }
4879 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4880   /* if we get here we should send the key for input manager processing */
4881   if (firstTime && [[NSInputManager currentInputManager]
4882                      wantsToDelayTextChangeNotifications] == NO)
4883     fprintf (stderr,
4884           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
4885   firstTime = NO;
4886 #endif
4887   if (NS_KEYLOG && !processingCompose)
4888     fprintf (stderr, "keyDown: Begin compose sequence.\n");
4890   processingCompose = YES;
4891   [nsEvArray addObject: theEvent];
4892   [self interpretKeyEvents: nsEvArray];
4893   [nsEvArray removeObject: theEvent];
4897 #ifdef NS_IMPL_COCOA
4898 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
4899    decided not to send key-down for.
4900    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
4901    This only applies on Tiger and earlier.
4902    If it matches one of these, send it on to keyDown. */
4903 -(void)keyUp: (NSEvent *)theEvent
4905   int flags = [theEvent modifierFlags];
4906   int code = [theEvent keyCode];
4907   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
4908       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
4909     {
4910       if (NS_KEYLOG)
4911         fprintf (stderr, "keyUp: passed test");
4912       ns_fake_keydown = YES;
4913       [self keyDown: theEvent];
4914     }
4916 #endif
4919 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
4922 /* <NSTextInput>: called when done composing;
4923    NOTE: also called when we delete over working text, followed immed.
4924          by doCommandBySelector: deleteBackward: */
4925 - (void)insertText: (id)aString
4927   int code;
4928   int len = [(NSString *)aString length];
4929   int i;
4931   if (NS_KEYLOG)
4932     NSLog (@"insertText '%@'\tlen = %d", aString, len);
4933   processingCompose = NO;
4935   if (!emacs_event)
4936     return;
4938   /* first, clear any working text */
4939   if (workingText != nil)
4940     [self deleteWorkingText];
4942   /* now insert the string as keystrokes */
4943   for (i =0; i<len; i++)
4944     {
4945       code = [aString characterAtIndex: i];
4946       /* TODO: still need this? */
4947       if (code == 0x2DC)
4948         code = '~'; /* 0x7E */
4949       emacs_event->modifiers = 0;
4950       emacs_event->kind
4951         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4952       emacs_event->code = code;
4953       EV_TRAILER ((id)nil);
4954     }
4958 /* <NSTextInput>: inserts display of composing characters */
4959 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
4961   NSString *str = [aString respondsToSelector: @selector (string)] ?
4962     [aString string] : aString;
4963   if (NS_KEYLOG)
4964     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
4965            selRange.length, selRange.location);
4967   if (workingText != nil)
4968     [self deleteWorkingText];
4969   if ([str length] == 0)
4970     return;
4972   if (!emacs_event)
4973     return;
4975   processingCompose = YES;
4976   workingText = [str copy];
4977   ns_working_text = build_string ([workingText UTF8String]);
4979   emacs_event->kind = NS_TEXT_EVENT;
4980   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
4981   EV_TRAILER ((id)nil);
4985 /* delete display of composing characters [not in <NSTextInput>] */
4986 - (void)deleteWorkingText
4988   if (workingText == nil)
4989     return;
4990   if (NS_KEYLOG)
4991     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
4992   [workingText release];
4993   workingText = nil;
4994   processingCompose = NO;
4996   if (!emacs_event)
4997     return;
4999   emacs_event->kind = NS_TEXT_EVENT;
5000   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5001   EV_TRAILER ((id)nil);
5005 - (BOOL)hasMarkedText
5007   return workingText != nil;
5011 - (NSRange)markedRange
5013   NSRange rng = workingText != nil
5014     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5015   if (NS_KEYLOG)
5016     NSLog (@"markedRange request");
5017   return rng;
5021 - (void)unmarkText
5023   if (NS_KEYLOG)
5024     NSLog (@"unmark (accept) text");
5025   [self deleteWorkingText];
5026   processingCompose = NO;
5030 /* used to position char selection windows, etc. */
5031 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5033   NSRect rect;
5034   NSPoint pt;
5035   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5036   if (NS_KEYLOG)
5037     NSLog (@"firstRectForCharRange request");
5039   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5040   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5041   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5042   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5043                                        +FRAME_LINE_HEIGHT (emacsframe));
5045   pt = [self convertPoint: pt toView: nil];
5046   pt = [[self window] convertBaseToScreen: pt];
5047   rect.origin = pt;
5048   return rect;
5052 - (long)conversationIdentifier
5054   return (long)self;
5058 - (void)doCommandBySelector: (SEL)aSelector
5060   if (NS_KEYLOG)
5061     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5063   if (aSelector == @selector (deleteBackward:))
5064     {
5065       /* happens when user backspaces over an ongoing composition:
5066          throw a 'delete' into the event queue */
5067       if (!emacs_event)
5068         return;
5069       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5070       emacs_event->code = 0xFF08;
5071       EV_TRAILER ((id)nil);
5072     }
5075 - (NSArray *)validAttributesForMarkedText
5077   static NSArray *arr = nil;
5078   if (arr == nil) arr = [NSArray new];
5079  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5080   return arr;
5083 - (NSRange)selectedRange
5085   if (NS_KEYLOG)
5086     NSLog (@"selectedRange request");
5087   return NSMakeRange (NSNotFound, 0);
5090 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5092   if (NS_KEYLOG)
5093     NSLog (@"characterIndexForPoint request");
5094   return 0;
5097 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5099   static NSAttributedString *str = nil;
5100   if (str == nil) str = [NSAttributedString new];
5101   if (NS_KEYLOG)
5102     NSLog (@"attributedSubstringFromRange request");
5103   return str;
5106 /* End <NSTextInput> impl. */
5107 /*****************************************************************************/
5110 /* This is what happens when the user presses a mouse button.  */
5111 - (void)mouseDown: (NSEvent *)theEvent
5113   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5114   Lisp_Object window;
5116   NSTRACE (mouseDown);
5118   [self deleteWorkingText];
5120   if (!emacs_event)
5121     return;
5123   last_mouse_frame = emacsframe;
5124   /* appears to be needed to prevent spurious movement events generated on
5125      button clicks */
5126   last_mouse_frame->mouse_moved = 0;
5128   if ([theEvent type] == NSScrollWheel)
5129     {
5130       float delta = [theEvent deltaY];
5131       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5132       if (delta == 0)
5133         return;
5134       emacs_event->kind = WHEEL_EVENT;
5135       emacs_event->code = 0;
5136       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5137         ((delta > 0) ? up_modifier : down_modifier);
5138     }
5139   else
5140     {
5141       emacs_event->kind = MOUSE_CLICK_EVENT;
5142       emacs_event->code = EV_BUTTON (theEvent);
5143       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5144                              | EV_UDMODIFIERS (theEvent);
5145     }
5146   XSETINT (emacs_event->x, lrint (p.x));
5147   XSETINT (emacs_event->y, lrint (p.y));
5148   EV_TRAILER (theEvent);
5152 - (void)rightMouseDown: (NSEvent *)theEvent
5154   NSTRACE (rightMouseDown);
5155   [self mouseDown: theEvent];
5159 - (void)otherMouseDown: (NSEvent *)theEvent
5161   NSTRACE (otherMouseDown);
5162   [self mouseDown: theEvent];
5166 - (void)mouseUp: (NSEvent *)theEvent
5168   NSTRACE (mouseUp);
5169   [self mouseDown: theEvent];
5173 - (void)rightMouseUp: (NSEvent *)theEvent
5175   NSTRACE (rightMouseUp);
5176   [self mouseDown: theEvent];
5180 - (void)otherMouseUp: (NSEvent *)theEvent
5182   NSTRACE (otherMouseUp);
5183   [self mouseDown: theEvent];
5187 - (void) scrollWheel: (NSEvent *)theEvent
5189   NSTRACE (scrollWheel);
5190   [self mouseDown: theEvent];
5194 /* Tell emacs the mouse has moved. */
5195 - (void)mouseMoved: (NSEvent *)e
5197   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5198   Lisp_Object frame;
5200 //  NSTRACE (mouseMoved);
5202   last_mouse_movement_time = EV_TIMESTAMP (e);
5203   last_mouse_motion_position
5204     = [self convertPoint: [e locationInWindow] fromView: nil];
5206   /* update any mouse face */
5207   if (hlinfo->mouse_face_hidden)
5208     {
5209       hlinfo->mouse_face_hidden = 0;
5210       clear_mouse_face (hlinfo);
5211     }
5213   /* tooltip handling */
5214   previous_help_echo_string = help_echo_string;
5215   help_echo_string = Qnil;
5217   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
5218                             last_mouse_motion_position.y))
5219     help_echo_string = previous_help_echo_string;
5221   XSETFRAME (frame, emacsframe);
5222   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5223     {
5224       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5225          (note_mouse_highlight), which is called through the
5226          note_mouse_movement () call above */
5227       gen_help_event (help_echo_string, frame, help_echo_window,
5228                       help_echo_object, help_echo_pos);
5229     }
5230   else
5231     {
5232       help_echo_string = Qnil;
5233       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5234     }
5236   if (emacsframe->mouse_moved && send_appdefined)
5237     ns_send_appdefined (-1);
5241 - (void)mouseDragged: (NSEvent *)e
5243   NSTRACE (mouseDragged);
5244   [self mouseMoved: e];
5248 - (void)rightMouseDragged: (NSEvent *)e
5250   NSTRACE (rightMouseDragged);
5251   [self mouseMoved: e];
5255 - (void)otherMouseDragged: (NSEvent *)e
5257   NSTRACE (otherMouseDragged);
5258   [self mouseMoved: e];
5262 - (BOOL)windowShouldClose: (id)sender
5264   NSEvent *e =[[self window] currentEvent];
5266   NSTRACE (windowShouldClose);
5267   windowClosing = YES;
5268   if (!emacs_event)
5269     return NO;
5270   emacs_event->kind = DELETE_WINDOW_EVENT;
5271   emacs_event->modifiers = 0;
5272   emacs_event->code = 0;
5273   EV_TRAILER (e);
5274   /* Don't close this window, let this be done from lisp code.  */
5275   return NO;
5279 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5280 /* normalize frame to gridded text size */
5282   NSTRACE (windowWillResize);
5283 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5285   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5286 #ifdef NS_IMPL_GNUSTEP
5287                                         frameSize.width + 3);
5288 #else
5289                                         frameSize.width);
5290 #endif
5291   if (cols < MINWIDTH)
5292     cols = MINWIDTH;
5294   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, frameSize.height
5295 #ifdef NS_IMPL_GNUSTEP
5296       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + 3
5297         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5298 #else
5299       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5300         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5301 #endif
5302   if (rows < MINHEIGHT)
5303     rows = MINHEIGHT;
5304 #ifdef NS_IMPL_COCOA
5305   {
5306     /* this sets window title to have size in it; the wm does this under GS */
5307     NSRect r = [[self window] frame];
5308     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5309       {
5310         if (old_title != 0)
5311           {
5312             xfree (old_title);
5313             old_title = 0;
5314           }
5315       }
5316     else
5317       {
5318         char *size_title;
5319         NSWindow *window = [self window];
5320         if (old_title == 0)
5321           {
5322             const char *t = [[[self window] title] UTF8String];
5323             char *pos = strstr (t, "  â€”  ");
5324             if (pos)
5325               *pos = '\0';
5326             old_title = (char *) xmalloc (strlen (t) + 1);
5327             strcpy (old_title, t);
5328           }
5329         size_title = xmalloc (strlen (old_title) + 40);
5330         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5331         [window setTitle: [NSString stringWithUTF8String: size_title]];
5332         [window display];
5333         xfree (size_title);
5334       }
5335   }
5336 #endif /* NS_IMPL_COCOA */
5337 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5339   return frameSize;
5343 - (void)windowDidResize: (NSNotification *)notification
5345   NSWindow *theWindow = [notification object];
5347 #ifdef NS_IMPL_GNUSTEP
5348    /* in GNUstep, at least currently, it's possible to get a didResize
5349       without getting a willResize.. therefore we need to act as if we got
5350       the willResize now */
5351   NSSize sz = [theWindow frame].size;
5352   sz = [self windowWillResize: theWindow toSize: sz];
5353 #endif /* NS_IMPL_GNUSTEP */
5355   NSTRACE (windowDidResize);
5356 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5358 #ifdef NS_IMPL_COCOA
5359   if (old_title != 0)
5360     {
5361       xfree (old_title);
5362       old_title = 0;
5363     }
5364 #endif /* NS_IMPL_COCOA */
5366   /* Avoid loop under GNUstep due to call at beginning of this function.
5367      (x_set_window_size causes a resize which causes
5368      a "windowDidResize" which calls x_set_window_size).  */
5369 #ifndef NS_IMPL_GNUSTEP
5370   if (cols > 0 && rows > 0)
5371     {
5372       if (ns_in_resize)
5373         x_set_window_size (emacsframe, 0, cols, rows);
5374       else
5375         {
5376           NSWindow *window = [self window];
5377           NSRect wr = [window frame];
5378           FRAME_PIXEL_WIDTH (emacsframe) = (int)wr.size.width
5379             - emacsframe->border_width;
5380           FRAME_PIXEL_HEIGHT (emacsframe) = (int)wr.size.height
5381             - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5382             - FRAME_TOOLBAR_HEIGHT (emacsframe);
5383           change_frame_size (emacsframe, rows, cols, 0, 0, 1);
5384           SET_FRAME_GARBAGED (emacsframe);
5385           cancel_mouse_face (emacsframe);
5386         }
5387     }
5388 #endif
5390   ns_send_appdefined (-1);
5394 - (void)windowDidBecomeKey: (NSNotification *)notification
5395 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5397   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5398   struct frame *old_focus = dpyinfo->x_focus_frame;
5400   NSTRACE (windowDidBecomeKey);
5402   if (emacsframe != old_focus)
5403     dpyinfo->x_focus_frame = emacsframe;
5405   ns_frame_rehighlight (emacsframe);
5407   if (emacs_event)
5408     {
5409       emacs_event->kind = FOCUS_IN_EVENT;
5410       EV_TRAILER ((id)nil);
5411     }
5415 - (void)windowDidResignKey: (NSNotification *)notification
5416 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5418   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5419   NSTRACE (windowDidResignKey);
5421   if (dpyinfo->x_focus_frame == emacsframe)
5422     dpyinfo->x_focus_frame = 0;
5424   ns_frame_rehighlight (emacsframe);
5426   /* FIXME: for some reason needed on second and subsequent clicks away
5427             from sole-frame Emacs to get hollow box to show */
5428   if (!windowClosing && [[self window] isVisible] == YES)
5429     {
5430       x_update_cursor (emacsframe, 1);
5431       x_set_frame_alpha (emacsframe);
5432     }
5434   if (emacs_event)
5435     {
5436       [self deleteWorkingText];
5437       emacs_event->kind = FOCUS_IN_EVENT;
5438       EV_TRAILER ((id)nil);
5439     }
5443 - (void)windowWillMiniaturize: sender
5445   NSTRACE (windowWillMiniaturize);
5449 - (BOOL)isFlipped
5451   return YES;
5455 - (BOOL)isOpaque
5457   return NO;
5461 - initFrameFromEmacs: (struct frame *)f
5463   NSRect r, wr;
5464   Lisp_Object tem;
5465   NSWindow *win;
5466   NSButton *toggleButton;
5467   int vbextra = NS_SCROLL_BAR_WIDTH (f);
5468   NSSize sz;
5469   NSColor *col;
5470   NSString *name;
5472   NSTRACE (initFrameFromEmacs);
5474   windowClosing = NO;
5475   processingCompose = NO;
5476   scrollbarsNeedingUpdate = 0;
5478 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5480   ns_userRect = NSMakeRect (0, 0, 0, 0);
5481   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5482                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5483   [self initWithFrame: r];
5484   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5486   FRAME_NS_VIEW (f) = self;
5487   emacsframe = f;
5488   old_title = 0;
5490   win = [[EmacsWindow alloc]
5491             initWithContentRect: r
5492                       styleMask: (NSResizableWindowMask |
5493 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5494                                   NSTitledWindowMask |
5495 #endif
5496                                   NSMiniaturizableWindowMask |
5497                                   NSClosableWindowMask)
5498                         backing: NSBackingStoreBuffered
5499                           defer: YES];
5501   wr = [win frame];
5502   f->border_width = wr.size.width - r.size.width;
5503   FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5505   [win setAcceptsMouseMovedEvents: YES];
5506   [win setDelegate: self];
5507   [win useOptimizedDrawing: YES];
5509   sz.width = FRAME_COLUMN_WIDTH (f);
5510   sz.height = FRAME_LINE_HEIGHT (f);
5511   [win setResizeIncrements: sz];
5513   [[win contentView] addSubview: self];
5515   if (ns_drag_types)
5516     [self registerForDraggedTypes: ns_drag_types];
5518   tem = f->name;
5519   name = [NSString stringWithUTF8String:
5520                    NILP (tem) ? (unsigned char *)"Emacs" : SDATA (tem)];
5521   [win setTitle: name];
5523   /* toolbar support */
5524   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5525                          [NSString stringWithFormat: @"Emacs Frame %d",
5526                                    ns_window_num]];
5527   [win setToolbar: toolbar];
5528   [toolbar setVisible: NO];
5529 #ifdef NS_IMPL_COCOA
5530   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5531   [toggleButton setTarget: self];
5532   [toggleButton setAction: @selector (toggleToolbar: )];
5533 #endif
5534   FRAME_TOOLBAR_HEIGHT (f) = 0;
5536   tem = f->icon_name;
5537   if (!NILP (tem))
5538     [win setMiniwindowTitle:
5539            [NSString stringWithUTF8String: SDATA (tem)]];
5541   {
5542     NSScreen *screen = [win screen];
5544     if (screen != 0)
5545       [win setFrameTopLeftPoint: NSMakePoint
5546            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5547             IN_BOUND (-SCREENMAX,
5548                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5549   }
5551   [win makeFirstResponder: self];
5553   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5554                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5555   [win setBackgroundColor: col];
5556   if ([col alphaComponent] != 1.0)
5557     [win setOpaque: NO];
5559   [self allocateGState];
5561   [NSApp registerServicesMenuSendTypes: ns_send_types
5562                            returnTypes: nil];
5564   ns_window_num++;
5565   return self;
5569 - (void)windowDidMove: sender
5571   NSWindow *win = [self window];
5572   NSRect r = [win frame];
5573   NSArray *screens = [NSScreen screens];
5574   NSScreen *screen = [screens objectAtIndex: 0];
5576   NSTRACE (windowDidMove);
5578   if (!emacsframe->output_data.ns)
5579     return;
5580   if (screen != nil)
5581     {
5582       emacsframe->left_pos = r.origin.x;
5583       emacsframe->top_pos =
5584         [screen frame].size.height - (r.origin.y + r.size.height);
5585     }
5589 /* Called AFTER method below, but before our windowWillResize call there leads
5590    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5591    location so set_window_size moves the frame. */
5592 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5594   emacsframe->output_data.ns->zooming = 1;
5595   return YES;
5599 /* Override to do something slightly nonstandard, but nice.  First click on
5600    zoom button will zoom vertically.  Second will zoom completely.  Third
5601    returns to original. */
5602 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5603                         defaultFrame:(NSRect)defaultFrame
5605   NSRect result = [sender frame];
5607   NSTRACE (windowWillUseStandardFrame);
5609   if (abs (defaultFrame.size.height - result.size.height)
5610       > FRAME_LINE_HEIGHT (emacsframe))
5611     {
5612       /* first click */
5613       ns_userRect = result;
5614       result.size.height = defaultFrame.size.height;
5615       result.origin.y = defaultFrame.origin.y;
5616     }
5617   else
5618     {
5619       if (abs (defaultFrame.size.width - result.size.width)
5620           > FRAME_COLUMN_WIDTH (emacsframe))
5621         result = defaultFrame;  /* second click */
5622       else
5623         {
5624           /* restore */
5625           result = ns_userRect.size.height ? ns_userRect : result;
5626           ns_userRect = NSMakeRect (0, 0, 0, 0);
5627         }
5628     }
5630   [self windowWillResize: sender toSize: result.size];
5631   return result;
5635 - (void)windowDidDeminiaturize: sender
5637   NSTRACE (windowDidDeminiaturize);
5638   if (!emacsframe->output_data.ns)
5639     return;
5640   emacsframe->async_iconified = 0;
5641   emacsframe->async_visible   = 1;
5642   windows_or_buffers_changed++;
5644   if (emacs_event)
5645     {
5646       emacs_event->kind = ICONIFY_EVENT;
5647       EV_TRAILER ((id)nil);
5648     }
5652 - (void)windowDidExpose: sender
5654   NSTRACE (windowDidExpose);
5655   if (!emacsframe->output_data.ns)
5656     return;
5657   emacsframe->async_visible = 1;
5658   SET_FRAME_GARBAGED (emacsframe);
5660   if (send_appdefined)
5661     ns_send_appdefined (-1);
5665 - (void)windowDidMiniaturize: sender
5667   NSTRACE (windowDidMiniaturize);
5668   if (!emacsframe->output_data.ns)
5669     return;
5671   emacsframe->async_iconified = 1;
5672   emacsframe->async_visible = 0;
5674   if (emacs_event)
5675     {
5676       emacs_event->kind = ICONIFY_EVENT;
5677       EV_TRAILER ((id)nil);
5678     }
5682 - (void)mouseEntered: (NSEvent *)theEvent
5684   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5685   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5686   NSTRACE (mouseEntered);
5688   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5692 - (void)mouseExited: (NSEvent *)theEvent
5694   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5695   NSRect r;
5696   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
5698   NSTRACE (mouseExited);
5700   if (!hlinfo)
5701     return;
5703   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5705   if (emacsframe == hlinfo->mouse_face_mouse_frame)
5706     {
5707       clear_mouse_face (hlinfo);
5708       hlinfo->mouse_face_mouse_frame = 0;
5709     }
5713 - menuDown: sender
5715   NSTRACE (menuDown);
5716   if (context_menu_value == -1)
5717     context_menu_value = [sender tag];
5718   else
5719     find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
5720                                   emacsframe->menu_bar_vector,
5721                                   (void *)[sender tag]);
5722   ns_send_appdefined (-1);
5723   return self;
5727 - (EmacsToolbar *)toolbar
5729   return toolbar;
5733 /* this gets called on toolbar button click */
5734 - toolbarClicked: (id)item
5736   NSEvent *theEvent;
5737   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
5739   NSTRACE (toolbarClicked);
5741   if (!emacs_event)
5742     return self;
5744   /* send first event (for some reason two needed) */
5745   theEvent = [[self window] currentEvent];
5746   emacs_event->kind = TOOL_BAR_EVENT;
5747   XSETFRAME (emacs_event->arg, emacsframe);
5748   EV_TRAILER (theEvent);
5750   emacs_event->kind = TOOL_BAR_EVENT;
5751 /*   XSETINT (emacs_event->code, 0); */
5752   emacs_event->arg = AREF (emacsframe->tool_bar_items,
5753                           idx + TOOL_BAR_ITEM_KEY);
5754   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5755   EV_TRAILER (theEvent);
5756   return self;
5760 - toggleToolbar: (id)sender
5762   if (!emacs_event)
5763     return self;
5765   emacs_event->kind = NS_NONKEY_EVENT;
5766   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
5767   EV_TRAILER ((id)nil);
5768   return self;
5772 - (void)drawRect: (NSRect)rect
5774   int x = NSMinX (rect), y = NSMinY (rect);
5775   int width = NSWidth (rect), height = NSHeight (rect);
5777   NSTRACE (drawRect);
5779   if (!emacsframe || !emacsframe->output_data.ns || ns_in_resize)
5780     return;
5782   ns_clear_frame_area (emacsframe, x, y, width, height);
5783   expose_frame (emacsframe, x, y, width, height);
5785   /*
5786     drawRect: may be called (at least in OS X 10.5) for invisible
5787     views as well for some reason.  Thus, do not infer visibility
5788     here.
5790     emacsframe->async_visible = 1;
5791     emacsframe->async_iconified = 0;
5792   */
5796 /* NSDraggingDestination protocol methods.  Actually this is not really a
5797    protocol, but a category of Object.  O well...  */
5799 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
5801   NSTRACE (draggingEntered);
5802   return NSDragOperationGeneric;
5806 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
5808   return YES;
5812 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
5814   id pb;
5815   int x, y;
5816   NSString *type;
5817   NSEvent *theEvent = [[self window] currentEvent];
5818   NSPoint position;
5820   NSTRACE (performDragOperation);
5822   if (!emacs_event)
5823     return NO;
5825   position = [self convertPoint: [sender draggingLocation] fromView: nil];
5826   x = lrint (position.x);  y = lrint (position.y);
5828   pb = [sender draggingPasteboard];
5829   type = [pb availableTypeFromArray: ns_drag_types];
5830   if (type == 0)
5831     {
5832       return NO;
5833     }
5834   else if ([type isEqualToString: NSFilenamesPboardType])
5835     {
5836       NSArray *files;
5837       NSEnumerator *fenum;
5838       NSString *file;
5840       if (!(files = [pb propertyListForType: type]))
5841         return NO;
5843       fenum = [files objectEnumerator];
5844       while ( (file = [fenum nextObject]) )
5845         {
5846           emacs_event->kind = NS_NONKEY_EVENT;
5847           emacs_event->code = KEY_NS_DRAG_FILE;
5848           XSETINT (emacs_event->x, x);
5849           XSETINT (emacs_event->y, y);
5850           ns_input_file = append2 (ns_input_file,
5851                                    build_string ([file UTF8String]));
5852           emacs_event->modifiers = EV_MODIFIERS (theEvent);
5853           EV_TRAILER (theEvent);
5854         }
5855       return YES;
5856     }
5857   else if ([type isEqualToString: NSURLPboardType])
5858     {
5859       NSString *file;
5860       NSURL *fileURL;
5862       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
5863           [fileURL isFileURL] == NO)
5864         return NO;
5866       file = [fileURL path];
5867       emacs_event->kind = NS_NONKEY_EVENT;
5868       emacs_event->code = KEY_NS_DRAG_FILE;
5869       XSETINT (emacs_event->x, x);
5870       XSETINT (emacs_event->y, y);
5871       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
5872       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5873       EV_TRAILER (theEvent);
5874       return YES;
5875     }
5876   else if ([type isEqualToString: NSStringPboardType]
5877            || [type isEqualToString: NSTabularTextPboardType])
5878     {
5879       NSString *data;
5881       if (! (data = [pb stringForType: type]))
5882         return NO;
5884       emacs_event->kind = NS_NONKEY_EVENT;
5885       emacs_event->code = KEY_NS_DRAG_TEXT;
5886       XSETINT (emacs_event->x, x);
5887       XSETINT (emacs_event->y, y);
5888       ns_input_text = build_string ([data UTF8String]);
5889       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5890       EV_TRAILER (theEvent);
5891       return YES;
5892     }
5893   else if ([type isEqualToString: NSColorPboardType])
5894     {
5895       NSColor *c = [NSColor colorFromPasteboard: pb];
5896       emacs_event->kind = NS_NONKEY_EVENT;
5897       emacs_event->code = KEY_NS_DRAG_COLOR;
5898       XSETINT (emacs_event->x, x);
5899       XSETINT (emacs_event->y, y);
5900       ns_input_color = ns_color_to_lisp (c);
5901       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5902       EV_TRAILER (theEvent);
5903       return YES;
5904     }
5905   else if ([type isEqualToString: NSFontPboardType])
5906     {
5907       /* impl based on GNUstep NSTextView.m */
5908       NSData *data = [pb dataForType: NSFontPboardType];
5909       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
5910       NSFont *font = [dict objectForKey: NSFontAttributeName];
5911       char fontSize[10];
5913       if (font == nil)
5914         return NO;
5916       emacs_event->kind = NS_NONKEY_EVENT;
5917       emacs_event->code = KEY_NS_CHANGE_FONT;
5918       XSETINT (emacs_event->x, x);
5919       XSETINT (emacs_event->y, y);
5920       ns_input_font = build_string ([[font fontName] UTF8String]);
5921       snprintf (fontSize, 10, "%f", [font pointSize]);
5922       ns_input_fontsize = build_string (fontSize);
5923       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5924       EV_TRAILER (theEvent);
5925       return YES;
5926     }
5927   else
5928     {
5929       error ("Invalid data type in dragging pasteboard.");
5930       return NO;
5931     }
5935 - (id) validRequestorForSendType: (NSString *)typeSent
5936                       returnType: (NSString *)typeReturned
5938   NSTRACE (validRequestorForSendType);
5939   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
5940       && typeReturned == nil)
5941     {
5942       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
5943         return self;
5944     }
5946   return [super validRequestorForSendType: typeSent
5947                                returnType: typeReturned];
5951 /* The next two methods are part of NSServicesRequests informal protocol,
5952    supposedly called when a services menu item is chosen from this app.
5953    But this should not happen because we override the services menu with our
5954    own entries which call ns-perform-service.
5955    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
5956    So let's at least stub them out until further investigation can be done. */
5958 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
5960   /* we could call ns_string_from_pasteboard(pboard) here but then it should
5961      be written into the buffer in place of the existing selection..
5962      ordinary service calls go through functions defined in ns-win.el */
5963   return NO;
5966 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
5968   NSArray *typesDeclared;
5969   Lisp_Object val;
5971   /* We only support NSStringPboardType */
5972   if ([types containsObject:NSStringPboardType] == NO) {
5973     return NO;
5974   }
5976   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
5977   if (CONSP (val) && SYMBOLP (XCAR (val)))
5978     {
5979       val = XCDR (val);
5980       if (CONSP (val) && NILP (XCDR (val)))
5981         val = XCAR (val);
5982     }
5983   if (! STRINGP (val))
5984     return NO;
5986   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
5987   [pb declareTypes:typesDeclared owner:nil];
5988   ns_string_to_pasteboard (pb, val);
5989   return YES;
5993 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
5994    (gives a miniaturized version of the window); currently we use the latter for
5995    frames whose active buffer doesn't correspond to any file
5996    (e.g., '*scratch*') */
5997 - setMiniwindowImage: (BOOL) setMini
5999   id image = [[self window] miniwindowImage];
6000   NSTRACE (setMiniwindowImage);
6002   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6003      about "AppleDockIconEnabled" notwithstanding, however the set message
6004      below has its effect nonetheless. */
6005   if (image != emacsframe->output_data.ns->miniimage)
6006     {
6007       if (image && [image isKindOfClass: [EmacsImage class]])
6008         [image release];
6009       [[self window] setMiniwindowImage:
6010                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6011     }
6013   return self;
6017 - (void) setRows: (int) r andColumns: (int) c
6019   rows = r;
6020   cols = c;
6023 @end  /* EmacsView */
6027 /* ==========================================================================
6029     EmacsWindow implementation
6031    ========================================================================== */
6033 @implementation EmacsWindow
6035 /* If we have multiple monitors, one above the other, we don't want to
6036    restrict the height to just one monitor.  So we override this.  */
6037 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6039   /* When making the frame visible for the first time, we want to
6040      constrain.  Other times not.  */
6041   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6042   NSTRACE (constrainFrameRect);
6044   if (f->output_data.ns->dont_constrain
6045       || ns_menu_bar_should_be_hidden ())
6046     return frameRect;
6048   f->output_data.ns->dont_constrain = 1;
6049   return [super constrainFrameRect:frameRect toScreen:screen];
6053 /* called only on resize clicks by special case in EmacsApp-sendEvent */
6054 - (void)mouseDown: (NSEvent *)theEvent
6056   if (ns_in_resize)
6057     {
6058       NSSize size = [[theEvent window] frame].size;
6059       grabOffset = [theEvent locationInWindow];
6060       grabOffset.x = size.width - grabOffset.x;
6061     }
6062   else
6063     [super mouseDown: theEvent];
6067 /* stop resizing */
6068 - (void)mouseUp: (NSEvent *)theEvent
6070   if (ns_in_resize)
6071     {
6072       struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6073       ns_in_resize = NO;
6074       ns_set_name_as_filename (f);
6075       [self display];
6076       ns_send_appdefined (-1);
6077     }
6078   else
6079     [super mouseUp: theEvent];
6083 /* send resize events */
6084 - (void)mouseDragged: (NSEvent *)theEvent
6086   if (ns_in_resize)
6087     {
6088       NSPoint p = [theEvent locationInWindow];
6089       NSSize size, vettedSize, origSize = [self frame].size;
6091       size.width = p.x + grabOffset.x;
6092       size.height = origSize.height - p.y + grabOffset.y;
6094       if (size.width == origSize.width && size.height == origSize.height)
6095         return;
6097       vettedSize = [[self delegate] windowWillResize: self toSize: size];
6098       [[NSNotificationCenter defaultCenter]
6099             postNotificationName: NSWindowDidResizeNotification
6100                           object: self];
6101     }
6102   else
6103     [super mouseDragged: theEvent];
6106 @end /* EmacsWindow */
6109 /* ==========================================================================
6111     EmacsScroller implementation
6113    ========================================================================== */
6116 @implementation EmacsScroller
6118 /* for repeat button push */
6119 #define SCROLL_BAR_FIRST_DELAY 0.5
6120 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6122 + (CGFloat) scrollerWidth
6124   /* TODO: if we want to allow variable widths, this is the place to do it,
6125            however neither GNUstep nor Cocoa support it very well */
6126   return [NSScroller scrollerWidth];
6130 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6132   NSTRACE (EmacsScroller_initFrame);
6134   r.size.width = [EmacsScroller scrollerWidth];
6135   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6136   [self setContinuous: YES];
6137   [self setEnabled: YES];
6139   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6140      locked against the top and bottom edges, and right edge on OS X, where
6141      scrollers are on right. */
6142 #ifdef NS_IMPL_GNUSTEP
6143   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6144 #else
6145   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6146 #endif
6148   win = nwin;
6149   condemned = NO;
6150   pixel_height = NSHeight (r);
6151   if (pixel_height == 0) pixel_height = 1;
6152   min_portion = 20 / pixel_height;
6154   frame = XFRAME (XWINDOW (win)->frame);
6155   if (FRAME_LIVE_P (frame))
6156     {
6157       int i;
6158       EmacsView *view = FRAME_NS_VIEW (frame);
6159       NSView *sview = [[view window] contentView];
6160       NSArray *subs = [sview subviews];
6162       /* disable optimization stopping redraw of other scrollbars */
6163       view->scrollbarsNeedingUpdate = 0;
6164       for (i =[subs count]-1; i >= 0; i--)
6165         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6166           view->scrollbarsNeedingUpdate++;
6167       [sview addSubview: self];
6168     }
6170 /*  [self setFrame: r]; */
6172   return self;
6176 - (void)setFrame: (NSRect)newRect
6178   NSTRACE (EmacsScroller_setFrame);
6179 /*  BLOCK_INPUT; */
6180   pixel_height = NSHeight (newRect);
6181   if (pixel_height == 0) pixel_height = 1;
6182   min_portion = 20 / pixel_height;
6183   [super setFrame: newRect];
6184   [self display];
6185 /*  UNBLOCK_INPUT; */
6189 - (void)dealloc
6191   NSTRACE (EmacsScroller_dealloc);
6192   if (!NILP (win))
6193     XWINDOW (win)->vertical_scroll_bar = Qnil;
6194   [super dealloc];
6198 - condemn
6200   NSTRACE (condemn);
6201   condemned =YES;
6202   return self;
6206 - reprieve
6208   NSTRACE (reprieve);
6209   condemned =NO;
6210   return self;
6214 - judge
6216   NSTRACE (judge);
6217   if (condemned)
6218     {
6219       EmacsView *view;
6220       BLOCK_INPUT;
6221       /* ensure other scrollbar updates after deletion */
6222       view = (EmacsView *)FRAME_NS_VIEW (frame);
6223       if (view != nil)
6224         view->scrollbarsNeedingUpdate++;
6225       [self removeFromSuperview];
6226       [self release];
6227       UNBLOCK_INPUT;
6228     }
6229   return self;
6233 - (void)resetCursorRects
6235   NSRect visible = [self visibleRect];
6236   NSTRACE (resetCursorRects);
6238   if (!NSIsEmptyRect (visible))
6239     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6240   [[NSCursor arrowCursor] setOnMouseEntered: YES];
6244 - (int) checkSamePosition: (int) position portion: (int) portion
6245                     whole: (int) whole
6247   return em_position ==position && em_portion ==portion && em_whole ==whole
6248     && portion != whole; /* needed for resize empty buf */
6252 - setPosition: (int)position portion: (int)portion whole: (int)whole
6254   NSTRACE (setPosition);
6256   em_position = position;
6257   em_portion = portion;
6258   em_whole = whole;
6260   if (portion >= whole)
6261     {
6262 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6263       [self setKnobProportion: 1.0];
6264       [self setDoubleValue: 1.0];
6265 #else
6266       [self setFloatValue: 0.0 knobProportion: 1.0];
6267 #endif
6268     }
6269   else
6270     {
6271       float pos, por;
6272       portion = max ((float)whole*min_portion/pixel_height, portion);
6273       pos = (float)position / (whole - portion);
6274       por = (float)portion/whole;
6275 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6276       [self setKnobProportion: por];
6277       [self setDoubleValue: pos];
6278 #else
6279       [self setFloatValue: pos knobProportion: por];
6280 #endif
6281     }
6282   return self;
6285 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6286      drag events will go directly to the EmacsScroller.  Leaving in for now. */
6287 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6288                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
6290   *part = last_hit_part;
6291   *window = win;
6292   XSETINT (*y, pixel_height);
6293   if ([self floatValue] > 0.999)
6294     XSETINT (*x, pixel_height);
6295   else
6296     XSETINT (*x, pixel_height * [self floatValue]);
6300 /* set up emacs_event */
6301 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6303   if (!emacs_event)
6304     return;
6306   emacs_event->part = last_hit_part;
6307   emacs_event->code = 0;
6308   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
6309   emacs_event->frame_or_window = win;
6310   emacs_event->timestamp = EV_TIMESTAMP (e);
6311   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
6312   emacs_event->arg = Qnil;
6313   XSETINT (emacs_event->x, loc * pixel_height);
6314   XSETINT (emacs_event->y, pixel_height-20);
6316   n_emacs_events_pending++;
6317   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
6318   EVENT_INIT (*emacs_event);
6319   ns_send_appdefined (-1);
6323 /* called manually thru timer to implement repeated button action w/hold-down */
6324 - repeatScroll: (NSTimer *)scrollEntry
6326   NSEvent *e = [[self window] currentEvent];
6327   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
6328   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
6330   /* clear timer if need be */
6331   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
6332     {
6333         [scroll_repeat_entry invalidate];
6334         [scroll_repeat_entry release];
6335         scroll_repeat_entry = nil;
6337         if (inKnob)
6338           return self;
6340         scroll_repeat_entry
6341           = [[NSTimer scheduledTimerWithTimeInterval:
6342                         SCROLL_BAR_CONTINUOUS_DELAY
6343                                             target: self
6344                                           selector: @selector (repeatScroll:)
6345                                           userInfo: 0
6346                                            repeats: YES]
6347               retain];
6348     }
6350   [self sendScrollEventAtLoc: 0 fromEvent: e];
6351   return self;
6355 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
6356    mouseDragged events without going into a modal loop. */
6357 - (void)mouseDown: (NSEvent *)e
6359   NSRect sr, kr;
6360   /* hitPart is only updated AFTER event is passed on */
6361   NSScrollerPart part = [self testPart: [e locationInWindow]];
6362   double inc = 0.0, loc, kloc, pos;
6363   int edge = 0;
6365   NSTRACE (EmacsScroller_mouseDown);
6367   switch (part)
6368     {
6369     case NSScrollerDecrementPage:
6370         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
6371     case NSScrollerIncrementPage:
6372         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
6373     case NSScrollerDecrementLine:
6374       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
6375     case NSScrollerIncrementLine:
6376       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
6377     case NSScrollerKnob:
6378       last_hit_part = scroll_bar_handle; break;
6379     case NSScrollerKnobSlot:  /* GNUstep-only */
6380       last_hit_part = scroll_bar_move_ratio; break;
6381     default:  /* NSScrollerNoPart? */
6382       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
6383                (long) part);
6384       return;
6385     }
6387   if (inc != 0.0)
6388     {
6389       pos = 0;      /* ignored */
6391       /* set a timer to repeat, as we can't let superclass do this modally */
6392       scroll_repeat_entry
6393         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
6394                                             target: self
6395                                           selector: @selector (repeatScroll:)
6396                                           userInfo: 0
6397                                            repeats: YES]
6398             retain];
6399     }
6400   else
6401     {
6402       /* handle, or on GNUstep possibly slot */
6403       NSEvent *fake_event;
6405       /* compute float loc in slot and mouse offset on knob */
6406       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6407                       toView: nil];
6408       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6409       if (loc <= 0.0)
6410         {
6411           loc = 0.0;
6412           edge = -1;
6413         }
6414       else if (loc >= NSHeight (sr))
6415         {
6416           loc = NSHeight (sr);
6417           edge = 1;
6418         }
6420       if (edge)
6421         kloc = 0.5 * edge;
6422       else
6423         {
6424           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
6425                           toView: nil];
6426           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
6427         }
6428       last_mouse_offset = kloc;
6430       /* if knob, tell emacs a location offset by knob pos
6431          (to indicate top of handle) */
6432       if (part == NSScrollerKnob)
6433           pos = (loc - last_mouse_offset) / NSHeight (sr);
6434       else
6435         /* else this is a slot click on GNUstep: go straight there */
6436         pos = loc / NSHeight (sr);
6438       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
6439       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
6440                                       location: [e locationInWindow]
6441                                  modifierFlags: [e modifierFlags]
6442                                      timestamp: [e timestamp]
6443                                   windowNumber: [e windowNumber]
6444                                        context: [e context]
6445                                    eventNumber: [e eventNumber]
6446                                     clickCount: [e clickCount]
6447                                       pressure: [e pressure]];
6448       [super mouseUp: fake_event];
6449     }
6451   if (part != NSScrollerKnob)
6452     [self sendScrollEventAtLoc: pos fromEvent: e];
6456 /* Called as we manually track scroller drags, rather than superclass. */
6457 - (void)mouseDragged: (NSEvent *)e
6459     NSRect sr;
6460     double loc, pos;
6461     int edge = 0;
6463     NSTRACE (EmacsScroller_mouseDragged);
6465       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6466                       toView: nil];
6467       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6469       if (loc <= 0.0)
6470         {
6471           loc = 0.0;
6472           edge = -1;
6473         }
6474       else if (loc >= NSHeight (sr) + last_mouse_offset)
6475         {
6476           loc = NSHeight (sr) + last_mouse_offset;
6477           edge = 1;
6478         }
6480       pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
6481       [self sendScrollEventAtLoc: pos fromEvent: e];
6485 - (void)mouseUp: (NSEvent *)e
6487   if (scroll_repeat_entry)
6488     {
6489       [scroll_repeat_entry invalidate];
6490       [scroll_repeat_entry release];
6491       scroll_repeat_entry = nil;
6492     }
6493   last_hit_part = 0;
6497 /* treat scrollwheel events in the bar as though they were in the main window */
6498 - (void) scrollWheel: (NSEvent *)theEvent
6500   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
6501   [view mouseDown: theEvent];
6504 @end  /* EmacsScroller */
6509 /* ==========================================================================
6511    Font-related functions; these used to be in nsfaces.m
6513    ========================================================================== */
6516 Lisp_Object
6517 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
6519   struct font *font = XFONT_OBJECT (font_object);
6521   if (fontset < 0)
6522     fontset = fontset_from_font (font_object);
6523   FRAME_FONTSET (f) = fontset;
6525   if (FRAME_FONT (f) == font)
6526     /* This font is already set in frame F.  There's nothing more to
6527        do.  */
6528     return font_object;
6530   FRAME_FONT (f) = font;
6532   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
6533   FRAME_COLUMN_WIDTH (f) = font->average_width;
6534   FRAME_SPACE_WIDTH (f) = font->space_width;
6535   FRAME_LINE_HEIGHT (f) = font->height;
6537   compute_fringe_widths (f, 1);
6539   /* Compute the scroll bar width in character columns.  */
6540   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6541     {
6542       int wid = FRAME_COLUMN_WIDTH (f);
6543       FRAME_CONFIG_SCROLL_BAR_COLS (f)
6544         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
6545     }
6546   else
6547     {
6548       int wid = FRAME_COLUMN_WIDTH (f);
6549       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6550     }
6552   /* Now make the frame display the given font.  */
6553   if (FRAME_NS_WINDOW (f) != 0)
6554         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6556   return font_object;
6560 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
6561 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
6562          in 1.43. */
6564 const char *
6565 ns_xlfd_to_fontname (const char *xlfd)
6566 /* --------------------------------------------------------------------------
6567     Convert an X font name (XLFD) to an NS font name.
6568     Only family is used.
6569     The string returned is temporarily allocated.
6570    -------------------------------------------------------------------------- */
6572   char *name = xmalloc (180);
6573   int i, len;
6574   const char *ret;
6576   if (!strncmp (xlfd, "--", 2))
6577     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
6578   else
6579     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
6581   /* stopgap for malformed XLFD input */
6582   if (strlen (name) == 0)
6583     strcpy (name, "Monaco");
6585   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
6586      also uppercase after '-' or ' ' */
6587   name[0] = toupper (name[0]);
6588   for (len =strlen (name), i =0; i<len; i++)
6589     {
6590       if (name[i] == '$')
6591         {
6592           name[i] = '-';
6593           if (i+1<len)
6594             name[i+1] = toupper (name[i+1]);
6595         }
6596       else if (name[i] == '_')
6597         {
6598           name[i] = ' ';
6599           if (i+1<len)
6600             name[i+1] = toupper (name[i+1]);
6601         }
6602     }
6603 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
6604   ret = [[NSString stringWithUTF8String: name] UTF8String];
6605   xfree (name);
6606   return ret;
6610 void
6611 syms_of_nsterm (void)
6613   NSTRACE (syms_of_nsterm);
6615   ns_antialias_threshold = 10.0;
6617   /* from 23+ we need to tell emacs what modifiers there are.. */
6618   DEFSYM (Qmodifier_value, "modifier-value");
6619   DEFSYM (Qalt, "alt");
6620   DEFSYM (Qhyper, "hyper");
6621   DEFSYM (Qmeta, "meta");
6622   DEFSYM (Qsuper, "super");
6623   DEFSYM (Qcontrol, "control");
6624   DEFSYM (Qnone, "none");
6625   DEFSYM (QUTF8_STRING, "UTF8_STRING");
6627   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
6628   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
6629   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
6630   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
6631   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
6633   DEFVAR_LISP ("ns-input-file", ns_input_file,
6634               "The file specified in the last NS event.");
6635   ns_input_file =Qnil;
6637   DEFVAR_LISP ("ns-input-text", ns_input_text,
6638               "The data received in the last NS text drag event.");
6639   ns_input_text =Qnil;
6641   DEFVAR_LISP ("ns-working-text", ns_working_text,
6642               "String for visualizing working composition sequence.");
6643   ns_working_text =Qnil;
6645   DEFVAR_LISP ("ns-input-font", ns_input_font,
6646               "The font specified in the last NS event.");
6647   ns_input_font =Qnil;
6649   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
6650               "The fontsize specified in the last NS event.");
6651   ns_input_fontsize =Qnil;
6653   DEFVAR_LISP ("ns-input-line", ns_input_line,
6654                "The line specified in the last NS event.");
6655   ns_input_line =Qnil;
6657   DEFVAR_LISP ("ns-input-color", ns_input_color,
6658                "The color specified in the last NS event.");
6659   ns_input_color =Qnil;
6661   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
6662                "The service name specified in the last NS event.");
6663   ns_input_spi_name =Qnil;
6665   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
6666                "The service argument specified in the last NS event.");
6667   ns_input_spi_arg =Qnil;
6669   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
6670                "This variable describes the behavior of the alternate or option key.\n\
6671 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6672 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6673 at all, allowing it to be used at a lower level for accented character entry.");
6674   ns_alternate_modifier = Qmeta;
6676   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
6677                "This variable describes the behavior of the right alternate or option key.\n\
6678 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6679 Set to left means be the same key as `ns-alternate-modifier'.\n\
6680 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6681 at all, allowing it to be used at a lower level for accented character entry.");
6682   ns_right_alternate_modifier = Qleft;
6684   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
6685                "This variable describes the behavior of the command key.\n\
6686 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6687   ns_command_modifier = Qsuper;
6689   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
6690                "This variable describes the behavior of the right command key.\n\
6691 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6692 Set to left means be the same key as `ns-command-modifier'.\n\
6693 Set to none means that the command / option key is not interpreted by Emacs\n\
6694 at all, allowing it to be used at a lower level for accented character entry.");
6695   ns_right_command_modifier = Qleft;
6697   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
6698                "This variable describes the behavior of the control key.\n\
6699 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6700   ns_control_modifier = Qcontrol;
6702   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
6703                "This variable describes the behavior of the right control key.\n\
6704 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6705 Set to left means be the same key as `ns-control-modifier'.\n\
6706 Set to none means that the control / option key is not interpreted by Emacs\n\
6707 at all, allowing it to be used at a lower level for accented character entry.");
6708   ns_right_control_modifier = Qleft;
6710   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
6711                "This variable describes the behavior of the function key (on laptops).\n\
6712 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6713 Set to none means that the function key is not interpreted by Emacs at all,\n\
6714 allowing it to be used at a lower level for accented character entry.");
6715   ns_function_modifier = Qnone;
6717   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
6718                "Non-nil (the default) means to render text antialiased. Only has an effect on OS X Panther and above.");
6719   ns_antialias_text = Qt;
6721   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
6722                "Whether to confirm application quit using dialog.");
6723   ns_confirm_quit = Qnil;
6725   staticpro (&ns_display_name_list);
6726   ns_display_name_list = Qnil;
6728   staticpro (&last_mouse_motion_frame);
6729   last_mouse_motion_frame = Qnil;
6731   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
6732                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
6733 Only works on OSX 10.6 or later.  */);
6734   ns_auto_hide_menu_bar = Qnil;
6736   /* TODO: move to common code */
6737   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
6738                doc: /* If not nil, Emacs uses toolkit scroll bars.  */);
6739 #ifdef USE_TOOLKIT_SCROLL_BARS
6740   Vx_toolkit_scroll_bars = Qt;
6741 #else
6742   Vx_toolkit_scroll_bars = Qnil;
6743 #endif
6745   DEFVAR_BOOL ("x-use-underline-position-properties",
6746                x_use_underline_position_properties,
6747      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
6748 A value of nil means ignore them.  If you encounter fonts with bogus
6749 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
6750 to 4.1, set this to nil. */);
6751   x_use_underline_position_properties = 0;
6753   DEFVAR_BOOL ("x-underline-at-descent-line",
6754                x_underline_at_descent_line,
6755      doc: /* Non-nil means to draw the underline at the same place as the descent line.
6756 A value of nil means to draw the underline according to the value of the
6757 variable `x-use-underline-position-properties', which is usually at the
6758 baseline level.  The default value is nil.  */);
6759   x_underline_at_descent_line = 0;
6761   /* Tell emacs about this window system. */
6762   Fprovide (intern ("ns"), Qnil);