* process.h (PSET): Remove.
[emacs.git] / src / nsterm.m
blob3ab9358467aa88479268e166aefdd56f541c091d
1 /* NeXT/Open/GNUstep / MacOSX communication module.
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2012
4   Free Software Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
22 Originally by Carl Edman
23 Updated by Christian Limpach (chris@nice.ch)
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25 MacOSX/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
26 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
29 /* This should be the first include, as it may set up #defines affecting
30    interpretation of even the system includes. */
31 #include <config.h>
33 #include <math.h>
34 #include <sys/types.h>
35 #include <time.h>
36 #include <signal.h>
37 #include <unistd.h>
38 #include <setjmp.h>
40 #include <c-ctype.h>
41 #include <c-strcase.h>
42 #include <ftoastr.h>
44 #ifdef HAVE_FCNTL_H
45 #include <fcntl.h>
46 #endif
48 #include "lisp.h"
49 #include "blockinput.h"
50 #include "sysselect.h"
51 #include "nsterm.h"
52 #include "systime.h"
53 #include "character.h"
54 #include "fontset.h"
55 #include "composite.h"
56 #include "ccl.h"
58 #include "termhooks.h"
59 #include "termopts.h"
60 #include "termchar.h"
62 #include "window.h"
63 #include "keyboard.h"
64 #include "buffer.h"
65 #include "font.h"
67 /* call tracing */
68 #if 0
69 int term_trace_num = 0;
70 #define NSTRACE(x)        fprintf (stderr, "%s:%d: [%d] " #x "\n",         \
71                                 __FILE__, __LINE__, ++term_trace_num)
72 #else
73 #define NSTRACE(x)
74 #endif
76 extern NSString *NSMenuDidBeginTrackingNotification;
78 /* ==========================================================================
80     Local declarations
82    ========================================================================== */
84 /* Convert a symbol indexed with an NSxxx value to a value as defined
85    in keyboard.c (lispy_function_key). I hope this is a correct way
86    of doing things... */
87 static unsigned convert_ns_to_X_keysym[] =
89   NSHomeFunctionKey,            0x50,
90   NSLeftArrowFunctionKey,       0x51,
91   NSUpArrowFunctionKey,         0x52,
92   NSRightArrowFunctionKey,      0x53,
93   NSDownArrowFunctionKey,       0x54,
94   NSPageUpFunctionKey,          0x55,
95   NSPageDownFunctionKey,        0x56,
96   NSEndFunctionKey,             0x57,
97   NSBeginFunctionKey,           0x58,
98   NSSelectFunctionKey,          0x60,
99   NSPrintFunctionKey,           0x61,
100   NSExecuteFunctionKey,         0x62,
101   NSInsertFunctionKey,          0x63,
102   NSUndoFunctionKey,            0x65,
103   NSRedoFunctionKey,            0x66,
104   NSMenuFunctionKey,            0x67,
105   NSFindFunctionKey,            0x68,
106   NSHelpFunctionKey,            0x6A,
107   NSBreakFunctionKey,           0x6B,
109   NSF1FunctionKey,              0xBE,
110   NSF2FunctionKey,              0xBF,
111   NSF3FunctionKey,              0xC0,
112   NSF4FunctionKey,              0xC1,
113   NSF5FunctionKey,              0xC2,
114   NSF6FunctionKey,              0xC3,
115   NSF7FunctionKey,              0xC4,
116   NSF8FunctionKey,              0xC5,
117   NSF9FunctionKey,              0xC6,
118   NSF10FunctionKey,             0xC7,
119   NSF11FunctionKey,             0xC8,
120   NSF12FunctionKey,             0xC9,
121   NSF13FunctionKey,             0xCA,
122   NSF14FunctionKey,             0xCB,
123   NSF15FunctionKey,             0xCC,
124   NSF16FunctionKey,             0xCD,
125   NSF17FunctionKey,             0xCE,
126   NSF18FunctionKey,             0xCF,
127   NSF19FunctionKey,             0xD0,
128   NSF20FunctionKey,             0xD1,
129   NSF21FunctionKey,             0xD2,
130   NSF22FunctionKey,             0xD3,
131   NSF23FunctionKey,             0xD4,
132   NSF24FunctionKey,             0xD5,
134   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
135   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
136   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
138   NSTabCharacter,               0x09,
139   0x19,                         0x09,  /* left tab->regular since pass shift */
140   NSCarriageReturnCharacter,    0x0D,
141   NSNewlineCharacter,           0x0D,
142   NSEnterCharacter,             0x8D,
144   0x1B,                         0x1B   /* escape */
147 static Lisp_Object Qmodifier_value;
148 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper;
149 extern Lisp_Object Qcursor_color, Qcursor_type, Qns, Qleft;
151 static Lisp_Object QUTF8_STRING;
153 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
154    the maximum font size to NOT antialias.  On GNUstep there is currently
155    no way to control this behavior. */
156 float ns_antialias_threshold;
158 /* Used to pick up AppleHighlightColor on OS X */
159 NSString *ns_selection_color;
161 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
162 NSString *ns_app_name = @"Emacs";  /* default changed later */
164 /* Display variables */
165 struct ns_display_info *x_display_list; /* Chain of existing displays */
166 Lisp_Object ns_display_name_list;
167 long context_menu_value = 0;
169 /* display update */
170 NSPoint last_mouse_motion_position;
171 static NSRect last_mouse_glyph;
172 static Time last_mouse_movement_time = 0;
173 static Lisp_Object last_mouse_motion_frame;
174 static EmacsScroller *last_mouse_scroll_bar = nil;
175 static struct frame *ns_updating_frame;
176 static NSView *focus_view = NULL;
177 static int ns_window_num = 0;
178 #ifdef NS_IMPL_GNUSTEP
179 static NSRect uRect;
180 #endif
181 static BOOL gsaved = NO;
182 BOOL ns_in_resize = NO;
183 static BOOL ns_fake_keydown = NO;
184 int ns_tmp_flags; /* FIXME */
185 struct nsfont_info *ns_tmp_font; /* FIXME */
186 static BOOL ns_menu_bar_is_hidden = NO;
187 /*static int debug_lock = 0; */
189 /* event loop */
190 static BOOL send_appdefined = YES;
191 static NSEvent *last_appdefined_event = 0;
192 static NSTimer *timed_entry = 0;
193 static NSTimer *scroll_repeat_entry = nil;
194 static fd_set select_readfds, select_writefds;
195 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
196 static int select_nfds = 0, select_valid = 0;
197 static EMACS_TIME select_timeout = { 0, 0 };
198 static int selfds[2] = { -1, -1 };
199 static pthread_mutex_t select_mutex;
200 static int apploopnr = 0;
201 static NSAutoreleasePool *outerpool;
202 static struct input_event *emacs_event = NULL;
203 static struct input_event *q_event_ptr = NULL;
204 static int n_emacs_events_pending = 0;
205 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
206   *ns_pending_service_args;
207 static BOOL ns_do_open_file = NO;
209 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
210 #define NS_FUNCTION_KEY_MASK 0x800000
211 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
212 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
213 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
214 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
215 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
216 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
217 #define EV_MODIFIERS(e)                               \
218     ((([e modifierFlags] & NSHelpKeyMask) ?           \
219            hyper_modifier : 0)                        \
220      | (!EQ (ns_right_alternate_modifier, Qleft) && \
221         (([e modifierFlags] & NSRightAlternateKeyMask) \
222          == NSRightAlternateKeyMask) ? \
223            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
224      | (([e modifierFlags] & NSAlternateKeyMask) ?                 \
225            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
226      | (([e modifierFlags] & NSShiftKeyMask) ?     \
227            shift_modifier : 0)                        \
228      | (!EQ (ns_right_control_modifier, Qleft) && \
229         (([e modifierFlags] & NSRightControlKeyMask) \
230          == NSRightControlKeyMask) ? \
231            parse_solitary_modifier (ns_right_control_modifier) : 0) \
232      | (([e modifierFlags] & NSControlKeyMask) ?      \
233            parse_solitary_modifier (ns_control_modifier) : 0)     \
234      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
235            parse_solitary_modifier (ns_function_modifier) : 0)    \
236      | (!EQ (ns_right_command_modifier, Qleft) && \
237         (([e modifierFlags] & NSRightCommandKeyMask) \
238          == NSRightCommandKeyMask) ? \
239            parse_solitary_modifier (ns_right_command_modifier) : 0) \
240      | (([e modifierFlags] & NSCommandKeyMask) ?      \
241            parse_solitary_modifier (ns_command_modifier):0))
243 #define EV_UDMODIFIERS(e)                                      \
244     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
245      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
246      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
247      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
248      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
249      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
250      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
251      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
252      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
254 #define EV_BUTTON(e)                                                         \
255     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
256       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
257      [e buttonNumber] - 1)
259 /* Convert the time field to a timestamp in milliseconds. */
260 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
262 /* This is a piece of code which is common to all the event handling
263    methods.  Maybe it should even be a function.  */
264 #define EV_TRAILER(e)                                                   \
265     {                                                                   \
266       XSETFRAME (emacs_event->frame_or_window, emacsframe);             \
267       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
268       if (q_event_ptr)                                                  \
269         {                                                               \
270           n_emacs_events_pending++;                                     \
271           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
272         }                                                               \
273       else                                                              \
274         kbd_buffer_store_event (emacs_event);                           \
275       EVENT_INIT (*emacs_event);                                        \
276       ns_send_appdefined (-1);                                          \
277     }
279 void x_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
281 /* TODO: get rid of need for these forward declarations */
282 static void ns_condemn_scroll_bars (struct frame *f);
283 static void ns_judge_scroll_bars (struct frame *f);
284 void x_set_frame_alpha (struct frame *f);
287 /* ==========================================================================
289     Utilities
291    ========================================================================== */
294 static Lisp_Object
295 append2 (Lisp_Object list, Lisp_Object item)
296 /* --------------------------------------------------------------------------
297    Utility to append to a list
298    -------------------------------------------------------------------------- */
300   Lisp_Object array[2];
301   array[0] = list;
302   array[1] = Fcons (item, Qnil);
303   return Fnconc (2, &array[0]);
307 const char *
308 ns_etc_directory (void)
309 /* If running as a self-contained app bundle, return as a string the
310    filename of the etc directory, if present; else nil.  */
312   NSBundle *bundle = [NSBundle mainBundle];
313   NSString *resourceDir = [bundle resourcePath];
314   NSString *resourcePath;
315   NSFileManager *fileManager = [NSFileManager defaultManager];
316   BOOL isDir;
318   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
319   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
320     {
321       if (isDir) return [resourcePath UTF8String];
322     }
323   return NULL;
327 const char *
328 ns_exec_path (void)
329 /* If running as a self-contained app bundle, return as a path string
330    the filenames of the libexec and bin directories, ie libexec:bin.
331    Otherwise, return nil.
332    Normally, Emacs does not add its own bin/ directory to the PATH.
333    However, a self-contained NS build has a different layout, with
334    bin/ and libexec/ subdirectories in the directory that contains
335    Emacs.app itself.
336    We put libexec first, because init_callproc_1 uses the first
337    element to initialize exec-directory.  An alternative would be
338    for init_callproc to check for invocation-directory/libexec.
341   NSBundle *bundle = [NSBundle mainBundle];
342   NSString *resourceDir = [bundle resourcePath];
343   NSString *binDir = [bundle bundlePath];
344   NSString *resourcePath, *resourcePaths;
345   NSRange range;
346   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
347   NSFileManager *fileManager = [NSFileManager defaultManager];
348   NSArray *paths;
349   NSEnumerator *pathEnum;
350   BOOL isDir;
352   range = [resourceDir rangeOfString: @"Contents"];
353   if (range.location != NSNotFound)
354     {
355       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
356 #ifdef NS_IMPL_COCOA
357       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
358 #endif
359     }
361   paths = [binDir stringsByAppendingPaths:
362                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
363   pathEnum = [paths objectEnumerator];
364   resourcePaths = @"";
366   while ((resourcePath = [pathEnum nextObject]))
367     {
368       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
369         if (isDir)
370           {
371             if ([resourcePaths length] > 0)
372               resourcePaths
373                 = [resourcePaths stringByAppendingString: pathSeparator];
374             resourcePaths
375               = [resourcePaths stringByAppendingString: resourcePath];
376           }
377     }
378   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
380   return NULL;
384 const char *
385 ns_load_path (void)
386 /* If running as a self-contained app bundle, return as a path string
387    the filenames of the site-lisp, lisp and leim directories.
388    Ie, site-lisp:lisp:leim.  Otherwise, return nil.  */
390   NSBundle *bundle = [NSBundle mainBundle];
391   NSString *resourceDir = [bundle resourcePath];
392   NSString *resourcePath, *resourcePaths;
393   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
394   NSFileManager *fileManager = [NSFileManager defaultManager];
395   BOOL isDir;
396   NSArray *paths = [resourceDir stringsByAppendingPaths:
397                               [NSArray arrayWithObjects:
398                                          @"site-lisp", @"lisp", @"leim", nil]];
399   NSEnumerator *pathEnum = [paths objectEnumerator];
400   resourcePaths = @"";
402   /* Hack to skip site-lisp.  */
403   if (no_site_lisp) resourcePath = [pathEnum nextObject];
405   while ((resourcePath = [pathEnum nextObject]))
406     {
407       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
408         if (isDir)
409           {
410             if ([resourcePaths length] > 0)
411               resourcePaths
412                 = [resourcePaths stringByAppendingString: pathSeparator];
413             resourcePaths
414               = [resourcePaths stringByAppendingString: resourcePath];
415           }
416     }
417   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
419   return NULL;
422 static void
423 ns_timeout (int usecs)
424 /* --------------------------------------------------------------------------
425      Blocking timer utility used by ns_ring_bell
426    -------------------------------------------------------------------------- */
428   EMACS_TIME wakeup = add_emacs_time (current_emacs_time (),
429                                       make_emacs_time (0, usecs * 1000));
431   /* Keep waiting until past the time wakeup.  */
432   while (1)
433     {
434       EMACS_TIME timeout, now = current_emacs_time ();
435       if (EMACS_TIME_LE (wakeup, now))
436         break;
437       timeout = sub_emacs_time (wakeup, now);
439       /* Try to wait that long--but we might wake up sooner.  */
440       pselect (0, NULL, NULL, NULL, &timeout, NULL);
441     }
445 void
446 ns_release_object (void *obj)
447 /* --------------------------------------------------------------------------
448     Release an object (callable from C)
449    -------------------------------------------------------------------------- */
451     [(id)obj release];
455 void
456 ns_retain_object (void *obj)
457 /* --------------------------------------------------------------------------
458     Retain an object (callable from C)
459    -------------------------------------------------------------------------- */
461     [(id)obj retain];
465 void *
466 ns_alloc_autorelease_pool (void)
467 /* --------------------------------------------------------------------------
468      Allocate a pool for temporary objects (callable from C)
469    -------------------------------------------------------------------------- */
471   return [[NSAutoreleasePool alloc] init];
475 void
476 ns_release_autorelease_pool (void *pool)
477 /* --------------------------------------------------------------------------
478      Free a pool and temporary objects it refers to (callable from C)
479    -------------------------------------------------------------------------- */
481   ns_release_object (pool);
486 /* ==========================================================================
488     Focus (clipping) and screen update
490    ========================================================================== */
492 static NSRect
493 ns_resize_handle_rect (NSWindow *window)
495   NSRect r = [window frame];
496   r.origin.x = r.size.width - RESIZE_HANDLE_SIZE;
497   r.origin.y = 0;
498   r.size.width = r.size.height = RESIZE_HANDLE_SIZE;
499   return r;
504 // Window constraining
505 // -------------------
507 // To ensure that the windows are not placed under the menu bar, they
508 // are typically moved by the call-back constrainFrameRect. However,
509 // by overriding it, it's possible to inhibit this, leaving the window
510 // in it's original position.
512 // It's possible to hide the menu bar. However, technically, it's only
513 // possible to hide it when the application is active. To ensure that
514 // this work properly, the menu bar and window constraining are
515 // deferred until the application becomes active.
517 // Even though it's not possible to manually move a window above the
518 // top of the screen, it is allowed if it's done programmatically,
519 // when the menu is hidden. This allows the editable area to cover the
520 // full screen height.
522 // Test cases
523 // ----------
525 // Use the following extra files:
527 //    init.el:
528 //       ;; Hide menu and place frame slightly above the top of the screen.
529 //       (setq ns-auto-hide-menu-bar t)
530 //       (set-frame-position (selected-frame) 0 -20)
532 // Test 1:
534 //    emacs -Q -l init.el
536 //    Result: No menu bar, and the title bar should be above the screen.
538 // Test 2:
540 //    emacs -Q
542 //    Result: Menu bar visible, frame placed immediately below the menu.
545 static void
546 ns_constrain_all_frames (void)
548   Lisp_Object tail, frame;
550   FOR_EACH_FRAME (tail, frame)
551     {
552       struct frame *f = XFRAME (frame);
553       if (FRAME_NS_P (f))
554         {
555           NSView *view = FRAME_NS_VIEW (f);
556           /* This no-op will trigger the default window placing
557            * constraint system. */
558           f->output_data.ns->dont_constrain = 0;
559           [[view window] setFrameOrigin:[[view window] frame].origin];
560         }
561     }
565 /* True, if the menu bar should be hidden.  */
567 static BOOL
568 ns_menu_bar_should_be_hidden (void)
570   return !NILP (ns_auto_hide_menu_bar)
571     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
575 /* Show or hide the menu bar, based on user setting.  */
577 static void
578 ns_update_auto_hide_menu_bar (void)
580 #ifndef MAC_OS_X_VERSION_10_6
581 #define MAC_OS_X_VERSION_10_6 1060
582 #endif
583 #ifdef NS_IMPL_COCOA
584 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
585   BLOCK_INPUT;
587   NSTRACE (ns_update_auto_hide_menu_bar);
589   if (NSApp != nil
590       && [NSApp isActive]
591       && [NSApp respondsToSelector:@selector(setPresentationOptions:)])
592     {
593       // Note, "setPresentationOptions" triggers an error unless the
594       // application is active.
595       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
597       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
598         {
599           NSApplicationPresentationOptions options
600             = NSApplicationPresentationAutoHideDock;
602           if (menu_bar_should_be_hidden)
603             options |= NSApplicationPresentationAutoHideMenuBar;
605           [NSApp setPresentationOptions: options];
607           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
609           if (!ns_menu_bar_is_hidden)
610             {
611               ns_constrain_all_frames ();
612             }
613         }
614     }
616   UNBLOCK_INPUT;
617 #endif
618 #endif
622 static void
623 ns_update_begin (struct frame *f)
624 /* --------------------------------------------------------------------------
625    Prepare for a grouped sequence of drawing calls
626    external (RIF) call; whole frame, called before update_window_begin
627    -------------------------------------------------------------------------- */
629   NSView *view = FRAME_NS_VIEW (f);
630   NSTRACE (ns_update_begin);
632   ns_update_auto_hide_menu_bar ();
634   ns_updating_frame = f;
635   [view lockFocus];
637 #ifdef NS_IMPL_GNUSTEP
638   uRect = NSMakeRect (0, 0, 0, 0);
639 #endif
643 static void
644 ns_update_window_begin (struct window *w)
645 /* --------------------------------------------------------------------------
646    Prepare for a grouped sequence of drawing calls
647    external (RIF) call; for one window, called after update_begin
648    -------------------------------------------------------------------------- */
650   struct frame *f = XFRAME (WINDOW_FRAME (w));
651  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
652   NSTRACE (ns_update_window_begin);
654   updated_window = w;
655   set_output_cursor (&w->cursor);
657   BLOCK_INPUT;
659   if (f == hlinfo->mouse_face_mouse_frame)
660     {
661       /* Don't do highlighting for mouse motion during the update.  */
662       hlinfo->mouse_face_defer = 1;
664         /* If the frame needs to be redrawn,
665            simply forget about any prior mouse highlighting.  */
666       if (FRAME_GARBAGED_P (f))
667         hlinfo->mouse_face_window = Qnil;
669       /* (further code for mouse faces ifdef'd out in other terms elided) */
670     }
672   UNBLOCK_INPUT;
676 static void
677 ns_update_window_end (struct window *w, int cursor_on_p,
678                       int mouse_face_overwritten_p)
679 /* --------------------------------------------------------------------------
680    Finished a grouped sequence of drawing calls
681    external (RIF) call; for one window called before update_end
682    -------------------------------------------------------------------------- */
684   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
686   /* note: this fn is nearly identical in all terms */
687   if (!w->pseudo_window_p)
688     {
689       BLOCK_INPUT;
691       if (cursor_on_p)
692         display_and_set_cursor (w, 1,
693                                 output_cursor.hpos, output_cursor.vpos,
694                                 output_cursor.x, output_cursor.y);
696       if (draw_window_fringes (w, 1))
697         x_draw_vertical_border (w);
699       UNBLOCK_INPUT;
700     }
702   /* If a row with mouse-face was overwritten, arrange for
703      frame_up_to_date to redisplay the mouse highlight.  */
704   if (mouse_face_overwritten_p)
705     {
706       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
707       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
708       hlinfo->mouse_face_window = Qnil;
709     }
711   updated_window = NULL;
712   NSTRACE (update_window_end);
716 static void
717 ns_update_end (struct frame *f)
718 /* --------------------------------------------------------------------------
719    Finished a grouped sequence of drawing calls
720    external (RIF) call; for whole frame, called after update_window_end
721    -------------------------------------------------------------------------- */
723   NSView *view = FRAME_NS_VIEW (f);
725 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
726     MOUSE_HL_INFO (f)->mouse_face_defer = 0;
728   BLOCK_INPUT;
730 #ifdef NS_IMPL_GNUSTEP
731   /* trigger flush only in the rectangle we tracked as being drawn */
732   [view unlockFocusNeedsFlush: NO];
733 /*fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", uRect.origin.x, uRect.origin.y, uRect.size.width, uRect.size.height); */
734   [view lockFocusInRect: uRect];
735 #endif
737   [view unlockFocus];
738   [[view window] flushWindow];
740   UNBLOCK_INPUT;
741   ns_updating_frame = NULL;
742   NSTRACE (ns_update_end);
746 static void
747 ns_flush (struct frame *f)
748 /* --------------------------------------------------------------------------
749    external (RIF) call
750    NS impl is no-op since currently we flush in ns_update_end and elsewhere
751    -------------------------------------------------------------------------- */
753     NSTRACE (ns_flush);
757 static void
758 ns_focus (struct frame *f, NSRect *r, int n)
759 /* --------------------------------------------------------------------------
760    Internal: Focus on given frame.  During small local updates this is used to
761      draw, however during large updates, ns_update_begin and ns_update_end are
762      called to wrap the whole thing, in which case these calls are stubbed out.
763      Except, on GNUstep, we accumulate the rectangle being drawn into, because
764      the back end won't do this automatically, and will just end up flushing
765      the entire window.
766    -------------------------------------------------------------------------- */
768 //  NSTRACE (ns_focus);
769 #ifdef NS_IMPL_GNUSTEP
770   NSRect u;
771     if (n == 2)
772       u = NSUnionRect (r[0], r[1]);
773     else if (r)
774       u = *r;
775 #endif
776 /* static int c =0;
777    fprintf (stderr, "focus: %d", c++);
778    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
779    fprintf (stderr, "\n"); */
781   if (f != ns_updating_frame)
782     {
783       NSView *view = FRAME_NS_VIEW (f);
784       if (view != focus_view)
785         {
786           if (focus_view != NULL)
787             {
788               [focus_view unlockFocus];
789               [[focus_view window] flushWindow];
790 /*debug_lock--; */
791             }
793           if (view)
794 #ifdef NS_IMPL_GNUSTEP
795             r ? [view lockFocusInRect: u] : [view lockFocus];
796 #else
797             [view lockFocus];
798 #endif
799           focus_view = view;
800 /*if (view) debug_lock++; */
801         }
802 #ifdef NS_IMPL_GNUSTEP
803       else
804         {
805           /* more than one rect being drawn into */
806           if (view && r)
807             {
808               [view unlockFocus]; /* add prev rect to redraw list */
809               [view lockFocusInRect: u]; /* focus for draw in new rect */
810             }
811         }
812 #endif
813     }
814 #ifdef NS_IMPL_GNUSTEP
815   else
816     {
817       /* in batch mode, but in GNUstep must still track rectangles explicitly */
818       uRect = (r ? NSUnionRect (uRect, u) : [FRAME_NS_VIEW (f) visibleRect]);
819     }
820 #endif
822   /* clipping */
823   if (r)
824     {
825       [[NSGraphicsContext currentContext] saveGraphicsState];
826       if (n == 2)
827         NSRectClipList (r, 2);
828       else
829         NSRectClip (*r);
830       gsaved = YES;
831     }
835 static void
836 ns_unfocus (struct frame *f)
837 /* --------------------------------------------------------------------------
838      Internal: Remove focus on given frame
839    -------------------------------------------------------------------------- */
841 //  NSTRACE (ns_unfocus);
843   if (gsaved)
844     {
845       [[NSGraphicsContext currentContext] restoreGraphicsState];
846       gsaved = NO;
847     }
849   if (f != ns_updating_frame)
850     {
851       if (focus_view != NULL)
852         {
853           [focus_view unlockFocus];
854           [[focus_view window] flushWindow];
855           focus_view = NULL;
856 /*debug_lock--; */
857         }
858     }
862 static void
863 ns_clip_to_row (struct window *w, struct glyph_row *row, int area, BOOL gc)
864 /* --------------------------------------------------------------------------
865      Internal (but parallels other terms): Focus drawing on given row
866    -------------------------------------------------------------------------- */
868   struct frame *f = XFRAME (WINDOW_FRAME (w));
869   NSRect clip_rect;
870   int window_x, window_y, window_width;
872   window_box (w, area, &window_x, &window_y, &window_width, 0);
874   clip_rect.origin.x = window_x - FRAME_INTERNAL_BORDER_WIDTH (f);
875   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
876   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
877   clip_rect.size.width = window_width + 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
878   clip_rect.size.height = row->visible_height;
880   /* allow a full-height row at the top when requested
881      (used to draw fringe all the way through internal border area) */
882   if (gc && clip_rect.origin.y < 5)
883     {
884       clip_rect.origin.y -= FRAME_INTERNAL_BORDER_WIDTH (f);
885       clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
886     }
888   /* likewise at bottom */
889   if (gc &&
890       FRAME_PIXEL_HEIGHT (f) - (clip_rect.origin.y + clip_rect.size.height) < 5)
891     clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
893   ns_focus (f, &clip_rect, 1);
897 static void
898 ns_ring_bell (struct frame *f)
899 /* --------------------------------------------------------------------------
900      "Beep" routine
901    -------------------------------------------------------------------------- */
903   NSTRACE (ns_ring_bell);
904   if (visible_bell)
905     {
906       NSAutoreleasePool *pool;
907       struct frame *frame = SELECTED_FRAME ();
908       NSView *view;
910       BLOCK_INPUT;
911       pool = [[NSAutoreleasePool alloc] init];
913       view = FRAME_NS_VIEW (frame);
914       if (view != nil)
915         {
916           NSRect r, surr;
917           NSPoint dim = NSMakePoint (128, 128);
919           r = [view bounds];
920           r.origin.x += (r.size.width - dim.x) / 2;
921           r.origin.y += (r.size.height - dim.y) / 2;
922           r.size.width = dim.x;
923           r.size.height = dim.y;
924           surr = NSInsetRect (r, -2, -2);
925           ns_focus (frame, &surr, 1);
926           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
927           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
928                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
929           NSRectFill (r);
930           [[view window] flushWindow];
931           ns_timeout (150000);
932           [[view window] restoreCachedImage];
933           [[view window] flushWindow];
934           ns_unfocus (frame);
935         }
936       [pool release];
937       UNBLOCK_INPUT;
938     }
939   else
940     {
941       NSBeep ();
942     }
946 static void
947 ns_reset_terminal_modes (struct terminal *terminal)
948 /*  Externally called as hook */
950   NSTRACE (ns_reset_terminal_modes);
954 static void
955 ns_set_terminal_modes (struct terminal *terminal)
956 /*  Externally called as hook */
958   NSTRACE (ns_set_terminal_modes);
963 /* ==========================================================================
965     Frame / window manager related functions
967    ========================================================================== */
970 static void
971 ns_raise_frame (struct frame *f)
972 /* --------------------------------------------------------------------------
973      Bring window to foreground and make it active
974    -------------------------------------------------------------------------- */
976   NSView *view = FRAME_NS_VIEW (f);
977   check_ns ();
978   BLOCK_INPUT;
979   FRAME_SAMPLE_VISIBILITY (f);
980   if (FRAME_VISIBLE_P (f))
981     {
982       [[view window] makeKeyAndOrderFront: NSApp];
983     }
984   UNBLOCK_INPUT;
988 static void
989 ns_lower_frame (struct frame *f)
990 /* --------------------------------------------------------------------------
991      Send window to back
992    -------------------------------------------------------------------------- */
994   NSView *view = FRAME_NS_VIEW (f);
995   check_ns ();
996   BLOCK_INPUT;
997   [[view window] orderBack: NSApp];
998   UNBLOCK_INPUT;
1002 static void
1003 ns_frame_raise_lower (struct frame *f, int raise)
1004 /* --------------------------------------------------------------------------
1005      External (hook)
1006    -------------------------------------------------------------------------- */
1008   NSTRACE (ns_frame_raise_lower);
1010   if (raise)
1011     ns_raise_frame (f);
1012   else
1013     ns_lower_frame (f);
1017 static void
1018 ns_frame_rehighlight (struct frame *frame)
1019 /* --------------------------------------------------------------------------
1020      External (hook): called on things like window switching within frame
1021    -------------------------------------------------------------------------- */
1023   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
1024   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1026   NSTRACE (ns_frame_rehighlight);
1027   if (dpyinfo->x_focus_frame)
1028     {
1029       dpyinfo->x_highlight_frame
1030         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1031            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1032            : dpyinfo->x_focus_frame);
1033       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1034         {
1035           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1036           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1037         }
1038     }
1039   else
1040       dpyinfo->x_highlight_frame = 0;
1042   if (dpyinfo->x_highlight_frame &&
1043          dpyinfo->x_highlight_frame != old_highlight)
1044     {
1045       if (old_highlight)
1046         {
1047           x_update_cursor (old_highlight, 1);
1048           x_set_frame_alpha (old_highlight);
1049         }
1050       if (dpyinfo->x_highlight_frame)
1051         {
1052           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1053           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1054         }
1055     }
1059 void
1060 x_make_frame_visible (struct frame *f)
1061 /* --------------------------------------------------------------------------
1062      External: Show the window (X11 semantics)
1063    -------------------------------------------------------------------------- */
1065   NSTRACE (x_make_frame_visible);
1066   /* XXX: at some points in past this was not needed, as the only place that
1067      called this (frame.c:Fraise_frame ()) also called raise_lower;
1068      if this ends up the case again, comment this out again. */
1069   if (!FRAME_VISIBLE_P (f))
1070     {
1071       f->async_visible = 1;
1072       ns_raise_frame (f);
1073     }
1077 void
1078 x_make_frame_invisible (struct frame *f)
1079 /* --------------------------------------------------------------------------
1080      External: Hide the window (X11 semantics)
1081    -------------------------------------------------------------------------- */
1083   NSView * view = FRAME_NS_VIEW (f);
1084   NSTRACE (x_make_frame_invisible);
1085   check_ns ();
1086   [[view window] orderOut: NSApp];
1087   f->async_visible = 0;
1088   f->async_iconified = 0;
1092 void
1093 x_iconify_frame (struct frame *f)
1094 /* --------------------------------------------------------------------------
1095      External: Iconify window
1096    -------------------------------------------------------------------------- */
1098   NSView * view = FRAME_NS_VIEW (f);
1099   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1100   NSTRACE (x_iconify_frame);
1101   check_ns ();
1103   if (dpyinfo->x_highlight_frame == f)
1104     dpyinfo->x_highlight_frame = 0;
1106   if ([[view window] windowNumber] <= 0)
1107     {
1108       /* the window is still deferred.  Make it very small, bring it
1109          on screen and order it out. */
1110       NSRect s = { { 100, 100}, {0, 0} };
1111       NSRect t;
1112       t = [[view window] frame];
1113       [[view window] setFrame: s display: NO];
1114       [[view window] orderBack: NSApp];
1115       [[view window] orderOut: NSApp];
1116       [[view window] setFrame: t display: NO];
1117     }
1118   [[view window] miniaturize: NSApp];
1121 /* Free X resources of frame F.  */
1123 void
1124 x_free_frame_resources (struct frame *f)
1126   NSView *view = FRAME_NS_VIEW (f);
1127   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1128   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1129   NSTRACE (x_free_frame_resources);
1130   check_ns ();
1132   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1134   BLOCK_INPUT;
1136   free_frame_menubar (f);
1138   if (FRAME_FACE_CACHE (f))
1139     free_frame_faces (f);
1141   if (f == dpyinfo->x_focus_frame)
1142     dpyinfo->x_focus_frame = 0;
1143   if (f == dpyinfo->x_highlight_frame)
1144     dpyinfo->x_highlight_frame = 0;
1145   if (f == hlinfo->mouse_face_mouse_frame)
1146     {
1147       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
1148       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
1149       hlinfo->mouse_face_window = Qnil;
1150       hlinfo->mouse_face_deferred_gc = 0;
1151       hlinfo->mouse_face_mouse_frame = 0;
1152     }
1154   if (f->output_data.ns->miniimage != nil)
1155     [f->output_data.ns->miniimage release];
1157   [[view window] close];
1158   [view release];
1160   xfree (f->output_data.ns);
1162   UNBLOCK_INPUT;
1165 void
1166 x_destroy_window (struct frame *f)
1167 /* --------------------------------------------------------------------------
1168      External: Delete the window
1169    -------------------------------------------------------------------------- */
1171   NSTRACE (x_destroy_window);
1172   check_ns ();
1173   x_free_frame_resources (f);
1174   ns_window_num--;
1178 void
1179 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1180 /* --------------------------------------------------------------------------
1181      External: Position the window
1182    -------------------------------------------------------------------------- */
1184   NSView *view = FRAME_NS_VIEW (f);
1185   NSArray *screens = [NSScreen screens];
1186   NSScreen *fscreen = [screens objectAtIndex: 0];
1187   NSScreen *screen = [[view window] screen];
1189   NSTRACE (x_set_offset);
1191   BLOCK_INPUT;
1193   f->left_pos = xoff;
1194   f->top_pos = yoff;
1196   if (view != nil && screen && fscreen)
1197     {
1198       f->left_pos = f->size_hint_flags & XNegative
1199         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1200         : f->left_pos;
1201       /* We use visibleFrame here to take menu bar into account.
1202          Ideally we should also adjust left/top with visibleFrame.origin.  */
1204       f->top_pos = f->size_hint_flags & YNegative
1205         ? ([screen visibleFrame].size.height + f->top_pos
1206            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1207            - FRAME_TOOLBAR_HEIGHT (f))
1208         : f->top_pos;
1209 #ifdef NS_IMPL_GNUSTEP
1210       if (f->left_pos < 100)
1211         f->left_pos = 100;  /* don't overlap menu */
1212 #endif
1213       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1214          menu bar.  */
1215       f->output_data.ns->dont_constrain = 0;
1216       [[view window] setFrameTopLeftPoint:
1217                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1218                                     SCREENMAXBOUND ([fscreen frame].size.height
1219                                                     - NS_TOP_POS (f)))];
1220       f->size_hint_flags &= ~(XNegative|YNegative);
1221     }
1223   UNBLOCK_INPUT;
1227 void
1228 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1229 /* --------------------------------------------------------------------------
1230      Adjust window pixel size based on given character grid size
1231      Impl is a bit more complex than other terms, need to do some
1232      internal clipping.
1233    -------------------------------------------------------------------------- */
1235   EmacsView *view = FRAME_NS_VIEW (f);
1236   NSWindow *window = [view window];
1237   NSRect wr = [window frame];
1238   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1239   int pixelwidth, pixelheight;
1240   static int oldRows, oldCols, oldFontWidth, oldFontHeight;
1241   static int oldTB;
1242   static struct frame *oldF;
1244   NSTRACE (x_set_window_size);
1246   if (view == nil ||
1247       (f == oldF
1248        && rows == oldRows && cols == oldCols
1249        && oldFontWidth == FRAME_COLUMN_WIDTH (f)
1250        && oldFontHeight == FRAME_LINE_HEIGHT (f)
1251        && oldTB == tb))
1252     return;
1254 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1256   BLOCK_INPUT;
1258   check_frame_size (f, &rows, &cols);
1259   oldF = f;
1260   oldRows = rows;
1261   oldCols = cols;
1262   oldFontWidth = FRAME_COLUMN_WIDTH (f);
1263   oldFontHeight = FRAME_LINE_HEIGHT (f);
1264   oldTB = tb;
1266   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1267   compute_fringe_widths (f, 0);
1269   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1270   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1272   /* If we have a toolbar, take its height into account. */
1273   if (tb)
1274     /* NOTE: previously this would generate wrong result if toolbar not
1275              yet displayed and fixing toolbar_height=32 helped, but
1276              now (200903) seems no longer needed */
1277     FRAME_TOOLBAR_HEIGHT (f) =
1278       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1279         - FRAME_NS_TITLEBAR_HEIGHT (f);
1280   else
1281     FRAME_TOOLBAR_HEIGHT (f) = 0;
1283   wr.size.width = pixelwidth + f->border_width;
1284   wr.size.height = pixelheight + FRAME_NS_TITLEBAR_HEIGHT (f)
1285                   + FRAME_TOOLBAR_HEIGHT (f);
1287   /* Do not try to constrain to this screen.  We may have multiple
1288      screens, and want Emacs to span those.  Constraining to screen
1289      prevents that, and that is not nice to the user.  */
1290  if (f->output_data.ns->zooming)
1291    f->output_data.ns->zooming = 0;
1292  else
1293    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1295   [view setRows: rows andColumns: cols];
1296   [window setFrame: wr display: YES];
1298 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1300   /* This is a trick to compensate for Emacs' managing the scrollbar area
1301      as a fixed number of standard character columns.  Instead of leaving
1302      blank space for the extra, we chopped it off above.  Now for
1303      left-hand scrollbars, we shift all rendering to the left by the
1304      difference between the real width and Emacs' imagined one.  For
1305      right-hand bars, don't worry about it since the extra is never used.
1306      (Obviously doesn't work for vertically split windows tho..) */
1307   {
1308     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1309       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1310                      - NS_SCROLL_BAR_WIDTH (f), 0)
1311       : NSMakePoint (0, 0);
1312     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1313     [view setBoundsOrigin: origin];
1314   }
1316   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1317   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1318   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1319 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1321   mark_window_cursors_off (XWINDOW (f->root_window));
1322   cancel_mouse_face (f);
1324   UNBLOCK_INPUT;
1329 /* ==========================================================================
1331     Color management
1333    ========================================================================== */
1336 NSColor *
1337 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1339   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1340   if (idx < 1 || idx >= color_table->avail)
1341     return nil;
1342   return color_table->colors[idx];
1346 unsigned long
1347 ns_index_color (NSColor *color, struct frame *f)
1349   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1350   ptrdiff_t idx;
1351   ptrdiff_t i;
1353   if (!color_table->colors)
1354     {
1355       color_table->size = NS_COLOR_CAPACITY;
1356       color_table->avail = 1; /* skip idx=0 as marker */
1357       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1358       color_table->colors[0] = nil;
1359       color_table->empty_indices = [[NSMutableSet alloc] init];
1360     }
1362   /* do we already have this color ? */
1363   for (i = 1; i < color_table->avail; i++)
1364     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1365       return i;
1367   if ([color_table->empty_indices count] > 0)
1368     {
1369       NSNumber *index = [color_table->empty_indices anyObject];
1370       [color_table->empty_indices removeObject: index];
1371       idx = [index unsignedLongValue];
1372     }
1373   else
1374     {
1375       if (color_table->avail == color_table->size)
1376         color_table->colors =
1377           xpalloc (color_table->colors, &color_table->size, 1,
1378                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1379       idx = color_table->avail++;
1380     }
1382   color_table->colors[idx] = color;
1383   [color retain];
1384 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1385   return idx;
1389 void
1390 ns_free_indexed_color (unsigned long idx, struct frame *f)
1392   struct ns_color_table *color_table;
1393   NSColor *color;
1394   NSNumber *index;
1396   if (!f)
1397     return;
1399   color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1401   if (idx <= 0 || idx >= color_table->size) {
1402     message1 ("ns_free_indexed_color: Color index out of range.\n");
1403     return;
1404   }
1406   index = [NSNumber numberWithUnsignedInt: idx];
1407   if ([color_table->empty_indices containsObject: index]) {
1408     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1409     return;
1410   }
1412   color = color_table->colors[idx];
1413   [color release];
1414   color_table->colors[idx] = nil;
1415   [color_table->empty_indices addObject: index];
1416 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1420 static int
1421 ns_get_color (const char *name, NSColor **col)
1422 /* --------------------------------------------------------------------------
1423      Parse a color name
1424    -------------------------------------------------------------------------- */
1425 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1426    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1427    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1429   NSColor *new = nil;
1430   static char hex[20];
1431   int scaling;
1432   float r = -1.0, g, b;
1433   NSString *nsname = [NSString stringWithUTF8String: name];
1435 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1436   BLOCK_INPUT;
1438   if ([nsname isEqualToString: @"ns_selection_color"])
1439     {
1440       nsname = ns_selection_color;
1441       name = [ns_selection_color UTF8String];
1442     }
1444   /* First, check for some sort of numeric specification. */
1445   hex[0] = '\0';
1447   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1448     {
1449       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1450       [scanner scanFloat: &r];
1451       [scanner scanFloat: &g];
1452       [scanner scanFloat: &b];
1453     }
1454   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1455     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1456   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1457     {
1458       int len = (strlen(name) - 1);
1459       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1460       int i;
1461       scaling = strlen(name+start) / 3;
1462       for (i = 0; i < 3; i++)
1463         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1464                  name + start + i * scaling);
1465       hex[3 * (scaling + 1) - 1] = '\0';
1466     }
1468   if (hex[0])
1469     {
1470       int rr, gg, bb;
1471       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1472       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1473         {
1474           r = rr / fscale;
1475           g = gg / fscale;
1476           b = bb / fscale;
1477         }
1478     }
1480   if (r >= 0.0)
1481     {
1482       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1483       UNBLOCK_INPUT;
1484       return 0;
1485     }
1487   /* Otherwise, color is expected to be from a list */
1488   {
1489     NSEnumerator *lenum, *cenum;
1490     NSString *name;
1491     NSColorList *clist;
1493 #ifdef NS_IMPL_GNUSTEP
1494     /* XXX: who is wrong, the requestor or the implementation? */
1495     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1496         == NSOrderedSame)
1497       nsname = @"highlightColor";
1498 #endif
1500     lenum = [[NSColorList availableColorLists] objectEnumerator];
1501     while ( (clist = [lenum nextObject]) && new == nil)
1502       {
1503         cenum = [[clist allKeys] objectEnumerator];
1504         while ( (name = [cenum nextObject]) && new == nil )
1505           {
1506             if ([name compare: nsname
1507                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1508               new = [clist colorWithKey: name];
1509           }
1510       }
1511   }
1513   if (new)
1514     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1515   UNBLOCK_INPUT;
1516   return new ? 0 : 1;
1521 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1522 /* --------------------------------------------------------------------------
1523      Convert a Lisp string object to a NS color
1524    -------------------------------------------------------------------------- */
1526   NSTRACE (ns_lisp_to_color);
1527   if (STRINGP (color))
1528     return ns_get_color (SSDATA (color), col);
1529   else if (SYMBOLP (color))
1530     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1531   return 1;
1535 Lisp_Object
1536 ns_color_to_lisp (NSColor *col)
1537 /* --------------------------------------------------------------------------
1538      Convert a color to a lisp string with the RGB equivalent
1539    -------------------------------------------------------------------------- */
1541   CGFloat red, green, blue, alpha, gray;
1542   char buf[1024];
1543   const char *str;
1544   NSTRACE (ns_color_to_lisp);
1546   BLOCK_INPUT;
1547   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1549       if ((str =[[col colorNameComponent] UTF8String]))
1550         {
1551           UNBLOCK_INPUT;
1552           return build_string ((char *)str);
1553         }
1555     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1556         getRed: &red green: &green blue: &blue alpha: &alpha];
1557   if (red ==green && red ==blue)
1558     {
1559       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1560             getWhite: &gray alpha: &alpha];
1561       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1562                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1563       UNBLOCK_INPUT;
1564       return build_string (buf);
1565     }
1567   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1568             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1570   UNBLOCK_INPUT;
1571   return build_string (buf);
1575 void
1576 ns_query_color(void *col, XColor *color_def, int setPixel)
1577 /* --------------------------------------------------------------------------
1578          Get ARGB values out of NSColor col and put them into color_def.
1579          If setPixel, set the pixel to a concatenated version.
1580          and set color_def pixel to the resulting index.
1581    -------------------------------------------------------------------------- */
1583   CGFloat r, g, b, a;
1585   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1586   color_def->red   = r * 65535;
1587   color_def->green = g * 65535;
1588   color_def->blue  = b * 65535;
1590   if (setPixel == YES)
1591     color_def->pixel
1592       = ARGB_TO_ULONG((int)(a*255),
1593                       (int)(r*255), (int)(g*255), (int)(b*255));
1598 ns_defined_color (struct frame *f,
1599                   const char *name,
1600                   XColor *color_def,
1601                   int alloc,
1602                   char makeIndex)
1603 /* --------------------------------------------------------------------------
1604          Return 1 if named color found, and set color_def rgb accordingly.
1605          If makeIndex and alloc are nonzero put the color in the color_table,
1606          and set color_def pixel to the resulting index.
1607          If makeIndex is zero, set color_def pixel to ARGB.
1608          Return 0 if not found
1609    -------------------------------------------------------------------------- */
1611   NSColor *col;
1612   NSTRACE (ns_defined_color);
1614   BLOCK_INPUT;
1615   if (ns_get_color (name, &col) != 0) /* Color not found  */
1616     {
1617       UNBLOCK_INPUT;
1618       return 0;
1619     }
1620   if (makeIndex && alloc)
1621     color_def->pixel = ns_index_color (col, f);
1622   ns_query_color (col, color_def, !makeIndex);
1623   UNBLOCK_INPUT;
1624   return 1;
1628 unsigned long
1629 ns_get_rgb_color (struct frame *f, float r, float g, float b, float a)
1630 /* --------------------------------------------------------------------------
1631     return an autoreleased RGB color
1632    -------------------------------------------------------------------------- */
1634 /*static int c = 1; fprintf (stderr, "color request %d\n", c++); */
1635   if (r < 0.0) r = 0.0;
1636   else if (r > 1.0) r = 1.0;
1637   if (g < 0.0) g = 0.0;
1638   else if (g > 1.0) g = 1.0;
1639   if (b < 0.0) b = 0.0;
1640   else if (b > 1.0) b = 1.0;
1641   if (a < 0.0) a = 0.0;
1642   else if (a > 1.0) a = 1.0;
1643   return (unsigned long) ns_index_color(
1644     [NSColor colorWithCalibratedRed: r green: g blue: b alpha: a], f);
1648 void
1649 x_set_frame_alpha (struct frame *f)
1650 /* --------------------------------------------------------------------------
1651      change the entire-frame transparency
1652    -------------------------------------------------------------------------- */
1654   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1655   EmacsView *view = FRAME_NS_VIEW (f);
1656   double alpha = 1.0;
1657   double alpha_min = 1.0;
1659   if (dpyinfo->x_highlight_frame == f)
1660     alpha = f->alpha[0];
1661   else
1662     alpha = f->alpha[1];
1664   if (FLOATP (Vframe_alpha_lower_limit))
1665     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1666   else if (INTEGERP (Vframe_alpha_lower_limit))
1667     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1669   if (alpha < 0.0)
1670     return;
1671   else if (1.0 < alpha)
1672     alpha = 1.0;
1673   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1674     alpha = alpha_min;
1676 #ifdef NS_IMPL_COCOA
1677   [[view window] setAlphaValue: alpha];
1678 #endif
1682 /* ==========================================================================
1684     Mouse handling
1686    ========================================================================== */
1689 void
1690 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1691 /* --------------------------------------------------------------------------
1692      Programmatically reposition mouse pointer in pixel coordinates
1693    -------------------------------------------------------------------------- */
1695   NSTRACE (x_set_mouse_pixel_position);
1696   ns_raise_frame (f);
1697 #if 0
1698   /* FIXME: this does not work, and what about GNUstep? */
1699 #ifdef NS_IMPL_COCOA
1700   [FRAME_NS_VIEW (f) lockFocus];
1701   PSsetmouse ((float)pix_x, (float)pix_y);
1702   [FRAME_NS_VIEW (f) unlockFocus];
1703 #endif
1704 #endif
1708 void
1709 x_set_mouse_position (struct frame *f, int h, int v)
1710 /* --------------------------------------------------------------------------
1711      Programmatically reposition mouse pointer in character coordinates
1712    -------------------------------------------------------------------------- */
1714   int pix_x, pix_y;
1716   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1717   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1719   if (pix_x < 0) pix_x = 0;
1720   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1722   if (pix_y < 0) pix_y = 0;
1723   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1725   x_set_mouse_pixel_position (f, pix_x, pix_y);
1729 static int
1730 note_mouse_movement (struct frame *frame, float x, float y)
1731 /*   ------------------------------------------------------------------------
1732      Called by EmacsView on mouseMovement events.  Passes on
1733      to emacs mainstream code if we moved off of a rect of interest
1734      known as last_mouse_glyph.
1735      ------------------------------------------------------------------------ */
1737 //  NSTRACE (note_mouse_movement);
1739   XSETFRAME (last_mouse_motion_frame, frame);
1741   /* Note, this doesn't get called for enter/leave, since we don't have a
1742      position.  Those are taken care of in the corresponding NSView methods. */
1744   /* has movement gone beyond last rect we were tracking? */
1745   if (x < last_mouse_glyph.origin.x ||
1746       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1747       y < last_mouse_glyph.origin.y ||
1748       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1749     {
1750       ns_update_begin(frame);
1751       frame->mouse_moved = 1;
1752       note_mouse_highlight (frame, x, y);
1753       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1754       ns_update_end(frame);
1755       return 1;
1756     }
1758   return 0;
1762 static void
1763 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1764                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1765                    Time *time)
1766 /* --------------------------------------------------------------------------
1767     External (hook): inform emacs about mouse position and hit parts.
1768     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1769     x & y should be position in the scrollbar (the whole bar, not the handle)
1770     and length of scrollbar respectively
1771    -------------------------------------------------------------------------- */
1773   id view;
1774   NSPoint position;
1775   Lisp_Object frame, tail;
1776   struct frame *f;
1777   struct ns_display_info *dpyinfo;
1779   NSTRACE (ns_mouse_position);
1781   if (*fp == NULL)
1782     {
1783       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1784       return;
1785     }
1787   dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1789   BLOCK_INPUT;
1791   if (last_mouse_scroll_bar != nil && insist == 0)
1792     {
1793       /* TODO: we do not use this path at the moment because drag events will
1794            go directly to the EmacsScroller.  Leaving code in for now. */
1795       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1796                                               x: x y: y];
1797       if (time) *time = last_mouse_movement_time;
1798       last_mouse_scroll_bar = nil;
1799     }
1800   else
1801     {
1802       /* Clear the mouse-moved flag for every frame on this display.  */
1803       FOR_EACH_FRAME (tail, frame)
1804         if (FRAME_NS_P (XFRAME (frame))
1805             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1806           XFRAME (frame)->mouse_moved = 0;
1808       last_mouse_scroll_bar = nil;
1809       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1810         f = last_mouse_frame;
1811       else
1812         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1813                                     : SELECTED_FRAME ();
1815       if (f && f->output_data.ns)  /* TODO: 2nd check no longer needed? */
1816         {
1817           view = FRAME_NS_VIEW (*fp);
1819           position = [[view window] mouseLocationOutsideOfEventStream];
1820           position = [view convertPoint: position fromView: nil];
1821           remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1822 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1824           if (bar_window) *bar_window = Qnil;
1825           if (part) *part = 0; /*scroll_bar_handle; */
1827           if (x) XSETINT (*x, lrint (position.x));
1828           if (y) XSETINT (*y, lrint (position.y));
1829           if (time) *time = last_mouse_movement_time;
1830           *fp = f;
1831         }
1832     }
1834   UNBLOCK_INPUT;
1838 static void
1839 ns_frame_up_to_date (struct frame *f)
1840 /* --------------------------------------------------------------------------
1841     External (hook): Fix up mouse highlighting right after a full update.
1842     Some highlighting was deferred if GC was happening during
1843     note_mouse_highlight (), while other highlighting was deferred for update.
1844    -------------------------------------------------------------------------- */
1846   NSTRACE (ns_frame_up_to_date);
1848   if (FRAME_NS_P (f))
1849     {
1850       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1851       if ((hlinfo->mouse_face_deferred_gc || f ==hlinfo->mouse_face_mouse_frame)
1852       /*&& hlinfo->mouse_face_mouse_frame*/)
1853         {
1854           BLOCK_INPUT;
1855           ns_update_begin(f);
1856           if (hlinfo->mouse_face_mouse_frame)
1857             note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1858                                   hlinfo->mouse_face_mouse_x,
1859                                   hlinfo->mouse_face_mouse_y);
1860           hlinfo->mouse_face_deferred_gc = 0;
1861           ns_update_end(f);
1862           UNBLOCK_INPUT;
1863         }
1864     }
1868 static void
1869 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1870 /* --------------------------------------------------------------------------
1871     External (RIF): set frame mouse pointer type.
1872    -------------------------------------------------------------------------- */
1874   NSTRACE (ns_define_frame_cursor);
1875   if (FRAME_POINTER_TYPE (f) != cursor)
1876     {
1877       EmacsView *view = FRAME_NS_VIEW (f);
1878       FRAME_POINTER_TYPE (f) = cursor;
1879       [[view window] invalidateCursorRectsForView: view];
1880       /* Redisplay assumes this function also draws the changed frame
1881          cursor, but this function doesn't, so do it explicitly.  */
1882       x_update_cursor (f, 1);
1883     }
1888 /* ==========================================================================
1890     Keyboard handling
1892    ========================================================================== */
1895 static unsigned
1896 ns_convert_key (unsigned code)
1897 /* --------------------------------------------------------------------------
1898     Internal call used by NSView-keyDown.
1899    -------------------------------------------------------------------------- */
1901   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1902                                 / sizeof (convert_ns_to_X_keysym[0]));
1903   unsigned keysym;
1904   /* An array would be faster, but less easy to read. */
1905   for (keysym = 0; keysym < last_keysym; keysym += 2)
1906     if (code == convert_ns_to_X_keysym[keysym])
1907       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1908   return 0;
1909 /* if decide to use keyCode and Carbon table, use this line:
1910      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1914 char *
1915 x_get_keysym_name (int keysym)
1916 /* --------------------------------------------------------------------------
1917     Called by keyboard.c.  Not sure if the return val is important, except
1918     that it be unique.
1919    -------------------------------------------------------------------------- */
1921   static char value[16];
1922   NSTRACE (x_get_keysym_name);
1923   sprintf (value, "%d", keysym);
1924   return value;
1929 /* ==========================================================================
1931     Block drawing operations
1933    ========================================================================== */
1936 static void
1937 ns_redraw_scroll_bars (struct frame *f)
1939   int i;
1940   id view;
1941   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1942   NSTRACE (ns_judge_scroll_bars);
1943   for (i =[subviews count]-1; i >= 0; i--)
1944     {
1945       view = [subviews objectAtIndex: i];
1946       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1947       [view display];
1948     }
1952 void
1953 ns_clear_frame (struct frame *f)
1954 /* --------------------------------------------------------------------------
1955       External (hook): Erase the entire frame
1956    -------------------------------------------------------------------------- */
1958   NSView *view = FRAME_NS_VIEW (f);
1959   NSRect r;
1961   NSTRACE (ns_clear_frame);
1962   if (ns_in_resize)
1963     return;
1965  /* comes on initial frame because we have
1966     after-make-frame-functions = select-frame */
1967  if (!FRAME_DEFAULT_FACE (f))
1968    return;
1970   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
1972   output_cursor.hpos = output_cursor.vpos = 0;
1973   output_cursor.x = -1;
1975   r = [view bounds];
1977   BLOCK_INPUT;
1978   ns_focus (f, &r, 1);
1979   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
1980   NSRectFill (r);
1981   ns_unfocus (f);
1983 #ifdef NS_IMPL_COCOA
1984   [[view window] display];  /* redraw resize handle */
1985 #endif
1987   /* as of 2006/11 or so this is now needed */
1988   ns_redraw_scroll_bars (f);
1989   UNBLOCK_INPUT;
1993 static void
1994 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
1995 /* --------------------------------------------------------------------------
1996     External (RIF):  Clear section of frame
1997    -------------------------------------------------------------------------- */
1999   NSRect r = NSMakeRect (x, y, width, height);
2000   NSView *view = FRAME_NS_VIEW (f);
2001   struct face *face = FRAME_DEFAULT_FACE (f);
2003   if (!view || !face)
2004     return;
2006   NSTRACE (ns_clear_frame_area);
2008   r = NSIntersectionRect (r, [view frame]);
2009   ns_focus (f, &r, 1);
2010   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2012 #ifdef NS_IMPL_COCOA
2013   {
2014     /* clip out the resize handle */
2015     NSWindow *window = [FRAME_NS_VIEW (f) window];
2016     NSRect ir
2017       = [view convertRect: ns_resize_handle_rect (window) fromView: nil];
2019     ir = NSIntersectionRect (r, ir);
2020     if (NSIsEmptyRect (ir))
2021       {
2022 #endif
2024   NSRectFill (r);
2026 #ifdef NS_IMPL_COCOA
2027       }
2028     else
2029       {
2030         NSRect r1 = r, r2 = r; /* upper and lower non-intersecting */
2031         r1.size.height -= ir.size.height;
2032         r2.origin.y += r1.size.height;
2033         r2.size.width -= ir.size.width;
2034         r2.size.height = ir.size.height;
2035         NSRectFill (r1);
2036         NSRectFill (r2);
2037       }
2038   }
2039 #endif
2041   ns_unfocus (f);
2042   return;
2046 static void
2047 ns_scroll_run (struct window *w, struct run *run)
2048 /* --------------------------------------------------------------------------
2049     External (RIF):  Insert or delete n lines at line vpos
2050    -------------------------------------------------------------------------- */
2052   struct frame *f = XFRAME (w->frame);
2053   int x, y, width, height, from_y, to_y, bottom_y;
2055   NSTRACE (ns_scroll_run);
2057   /* begin copy from other terms */
2058   /* Get frame-relative bounding box of the text display area of W,
2059      without mode lines.  Include in this box the left and right
2060      fringe of W.  */
2061   window_box (w, -1, &x, &y, &width, &height);
2063   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2064   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2065   bottom_y = y + height;
2067   if (to_y < from_y)
2068     {
2069       /* Scrolling up.  Make sure we don't copy part of the mode
2070          line at the bottom.  */
2071       if (from_y + run->height > bottom_y)
2072         height = bottom_y - from_y;
2073       else
2074         height = run->height;
2075     }
2076   else
2077     {
2078       /* Scrolling down.  Make sure we don't copy over the mode line.
2079          at the bottom.  */
2080       if (to_y + run->height > bottom_y)
2081         height = bottom_y - to_y;
2082       else
2083         height = run->height;
2084     }
2085   /* end copy from other terms */
2087   if (height == 0)
2088       return;
2090   BLOCK_INPUT;
2092   updated_window = w;
2093   x_clear_cursor (w);
2095   {
2096     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2097     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2098     NSPoint dstOrigin = NSMakePoint (x, to_y);
2100     ns_focus (f, &dstRect, 1);
2101     NSCopyBits (0, srcRect , dstOrigin);
2102     ns_unfocus (f);
2103   }
2105   UNBLOCK_INPUT;
2109 static void
2110 ns_after_update_window_line (struct glyph_row *desired_row)
2111 /* --------------------------------------------------------------------------
2112     External (RIF): preparatory to fringe update after text was updated
2113    -------------------------------------------------------------------------- */
2115   struct window *w = updated_window;
2116   struct frame *f;
2117   int width, height;
2119   NSTRACE (ns_after_update_window_line);
2121   /* begin copy from other terms */
2122   eassert (w);
2124   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2125     desired_row->redraw_fringe_bitmaps_p = 1;
2127   /* When a window has disappeared, make sure that no rest of
2128      full-width rows stays visible in the internal border.
2129      Under NS this is drawn inside the fringes. */
2130   if (windows_or_buffers_changed
2131       && (f = XFRAME (w->frame),
2132           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2133           width != 0)
2134       && (height = desired_row->visible_height,
2135           height > 0))
2136     {
2137       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2139       /* Internal border is drawn below the tool bar.  */
2140       if (WINDOWP (f->tool_bar_window)
2141           && w == XWINDOW (f->tool_bar_window))
2142         y -= width;
2143       /* end copy from other terms */
2145       BLOCK_INPUT;
2146       if (!desired_row->full_width_p)
2147         {
2148           int x1 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2149             + WINDOW_LEFT_FRINGE_WIDTH (w);
2150           int x2 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2151             + FRAME_PIXEL_WIDTH (f) - NS_SCROLL_BAR_WIDTH (f)
2152             - WINDOW_RIGHT_FRINGE_WIDTH (w)
2153             - FRAME_INTERNAL_BORDER_WIDTH (f);
2154           ns_clear_frame_area (f, x1, y, width, height);
2155           ns_clear_frame_area (f, x2, y, width, height);
2156         }
2157       UNBLOCK_INPUT;
2158     }
2162 static void
2163 ns_shift_glyphs_for_insert (struct frame *f,
2164                            int x, int y, int width, int height,
2165                            int shift_by)
2166 /* --------------------------------------------------------------------------
2167     External (RIF): copy an area horizontally, don't worry about clearing src
2168    -------------------------------------------------------------------------- */
2170   NSRect srcRect = NSMakeRect (x, y, width, height);
2171   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2172   NSPoint dstOrigin = dstRect.origin;
2174   NSTRACE (ns_shift_glyphs_for_insert);
2176   ns_focus (f, &dstRect, 1);
2177   NSCopyBits (0, srcRect, dstOrigin);
2178   ns_unfocus (f);
2183 /* ==========================================================================
2185     Character encoding and metrics
2187    ========================================================================== */
2190 static inline void
2191 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2192 /* --------------------------------------------------------------------------
2193      External (RIF); compute left/right overhang of whole string and set in s
2194    -------------------------------------------------------------------------- */
2196   struct font *font = s->font;
2198   if (s->char2b)
2199     {
2200       struct font_metrics metrics;
2201       unsigned int codes[2];
2202       codes[0] = *(s->char2b);
2203       codes[1] = *(s->char2b + s->nchars - 1);
2205       font->driver->text_extents (font, codes, 2, &metrics);
2206       s->left_overhang = -metrics.lbearing;
2207       s->right_overhang
2208         = metrics.rbearing > metrics.width
2209         ? metrics.rbearing - metrics.width : 0;
2210     }
2211   else
2212     {
2213       s->left_overhang = 0;
2214       s->right_overhang = ((struct nsfont_info *)font)->ital ?
2215         FONT_HEIGHT (font) * 0.2 : 0;
2216     }
2221 /* ==========================================================================
2223     Fringe and cursor drawing
2225    ========================================================================== */
2228 extern int max_used_fringe_bitmap;
2229 static void
2230 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2231                       struct draw_fringe_bitmap_params *p)
2232 /* --------------------------------------------------------------------------
2233     External (RIF); fringe-related
2234    -------------------------------------------------------------------------- */
2236   struct frame *f = XFRAME (WINDOW_FRAME (w));
2237   struct face *face = p->face;
2238   int rowY;
2239   static EmacsImage **bimgs = NULL;
2240   static int nBimgs = 0;
2241   /* NS-specific: move internal border inside fringe */
2242   int x = p->bx < 0 ? p->x : p->bx;
2243   int wd = p->bx < 0 ? p->wd : p->nx;
2244   BOOL fringeOnVeryLeft
2245     = x - WINDOW_LEFT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w)
2246       - FRAME_INTERNAL_BORDER_WIDTH (f) < 10;
2247   BOOL fringeOnVeryRight
2248     = FRAME_PIXEL_WIDTH (f) - x - wd - FRAME_INTERNAL_BORDER_WIDTH (f)
2249       - WINDOW_RIGHT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w) < 10;
2250   int xAdjust = FRAME_INTERNAL_BORDER_WIDTH (f) *
2251     (fringeOnVeryLeft ? -1 : (fringeOnVeryRight ? 1 : 0));
2253   /* grow bimgs if needed */
2254   if (nBimgs < max_used_fringe_bitmap)
2255     {
2256       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2257       memset (bimgs + nBimgs, 0,
2258               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2259       nBimgs = max_used_fringe_bitmap;
2260     }
2262   /* Must clip because of partially visible lines.  */
2263   rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2264   ns_clip_to_row (w, row, -1, YES);
2266   if (p->bx >= 0 && !p->overlay_p)
2267     {
2268       int yAdjust = rowY - FRAME_INTERNAL_BORDER_WIDTH (f) < 5 ?
2269         -FRAME_INTERNAL_BORDER_WIDTH (f) : 0;
2270       int yIncr = FRAME_PIXEL_HEIGHT (f) - (p->by+yAdjust + p->ny) < 5 ?
2271         FRAME_INTERNAL_BORDER_WIDTH (f) : 0
2272         + (yAdjust ? FRAME_INTERNAL_BORDER_WIDTH (f) : 0);
2273       NSRect r = NSMakeRect (p->bx+xAdjust, p->by+yAdjust, p->nx, p->ny+yIncr);
2274       NSRectClip (r);
2275       [ns_lookup_indexed_color(face->background, f) set];
2276       NSRectFill (r);
2277     }
2279   if (p->which)
2280     {
2281       NSRect r = NSMakeRect (p->x+xAdjust, p->y, p->wd, p->h);
2282       EmacsImage *img = bimgs[p->which - 1];
2284       if (!img)
2285         {
2286           unsigned short *bits = p->bits + p->dh;
2287           int len = p->h;
2288           int i;
2289           unsigned char *cbits = xmalloc (len);
2291           for (i =0; i<len; i++)
2292             cbits[i] = ~(bits[i] & 0xff);
2293           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2294                                            flip: NO];
2295           bimgs[p->which - 1] = img;
2296           xfree (cbits);
2297         }
2299       NSRectClip (r);
2300       /* Since we composite the bitmap instead of just blitting it, we need
2301          to erase the whole background. */
2302       [ns_lookup_indexed_color(face->background, f) set];
2303       NSRectFill (r);
2304       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2305       [img drawInRect: r
2306               fromRect: NSZeroRect
2307              operation: NSCompositeSourceOver
2308               fraction: 1.0
2309            respectFlipped: YES
2310                 hints: nil];
2311     }
2312   ns_unfocus (f);
2316 static void
2317 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2318                        int x, int y, int cursor_type, int cursor_width,
2319                        int on_p, int active_p)
2320 /* --------------------------------------------------------------------------
2321      External call (RIF): draw cursor.
2322      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2323    -------------------------------------------------------------------------- */
2325   NSRect r, s;
2326   int fx, fy, h, cursor_height;
2327   struct frame *f = WINDOW_XFRAME (w);
2328   struct glyph *phys_cursor_glyph;
2329   int overspill;
2330   struct glyph *cursor_glyph;
2331   struct face *face;
2332   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2334   /* If cursor is out of bounds, don't draw garbage.  This can happen
2335      in mini-buffer windows when switching between echo area glyphs
2336      and mini-buffer.  */
2338   NSTRACE (dumpcursor);
2340   if (!on_p)
2341     return;
2343   w->phys_cursor_type = cursor_type;
2344   w->phys_cursor_on_p = on_p;
2346   if (cursor_type == NO_CURSOR)
2347     {
2348       w->phys_cursor_width = 0;
2349       return;
2350     }
2352   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2353     {
2354       if (glyph_row->exact_window_width_line_p
2355           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2356         {
2357           glyph_row->cursor_in_fringe_p = 1;
2358           draw_fringe_bitmap (w, glyph_row, 0);
2359         }
2360       return;
2361     }
2363   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2364      (other terminals do it the other way round).  We must set
2365      w->phys_cursor_width to the cursor width.  For bar cursors, that
2366      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2367   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2369   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2370      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2371   if (cursor_type == BAR_CURSOR)
2372     {
2373       if (cursor_width < 1)
2374         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2375       w->phys_cursor_width = cursor_width;
2376     }
2377   /* If we have an HBAR, "cursor_width" MAY specify height. */
2378   else if (cursor_type == HBAR_CURSOR)
2379     {
2380       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2381       fy += h - cursor_height;
2382       h = cursor_height;
2383     }
2385   r.origin.x = fx, r.origin.y = fy;
2386   r.size.height = h;
2387   r.size.width = w->phys_cursor_width;
2389   /* FIXME: if we overwrite the internal border area, it does not get erased;
2390      fix by truncating cursor, but better would be to erase properly */
2391   overspill = r.origin.x + r.size.width -
2392     WINDOW_TEXT_TO_FRAME_PIXEL_X (w, WINDOW_BOX_RIGHT_EDGE_X (w)
2393       - WINDOW_TOTAL_FRINGE_WIDTH (w) - FRAME_INTERNAL_BORDER_WIDTH (f));
2394   if (overspill > 0)
2395     r.size.width -= overspill;
2397   /* TODO: only needed in rare cases with last-resort font in HELLO..
2398      should we do this more efficiently? */
2399   ns_clip_to_row (w, glyph_row, -1, NO); /* do ns_focus(f, &r, 1); if remove */
2402   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2403   if (face && NS_FACE_BACKGROUND (face)
2404       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2405     {
2406       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2407       hollow_color = FRAME_CURSOR_COLOR (f);
2408     }
2409   else
2410     [FRAME_CURSOR_COLOR (f) set];
2412 #ifdef NS_IMPL_COCOA
2413   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2414            atomic.  Cleaner ways of doing this should be investigated.
2415            One way would be to set a global variable DRAWING_CURSOR
2416            when making the call to draw_phys..(), don't focus in that
2417            case, then move the ns_unfocus() here after that call. */
2418   NSDisableScreenUpdates ();
2419 #endif
2421   switch (cursor_type)
2422     {
2423     case NO_CURSOR:
2424       break;
2425     case FILLED_BOX_CURSOR:
2426       NSRectFill (r);
2427       break;
2428     case HOLLOW_BOX_CURSOR:
2429       NSRectFill (r);
2430       [hollow_color set];
2431       NSRectFill (NSInsetRect (r, 1, 1));
2432       [FRAME_CURSOR_COLOR (f) set];
2433       break;
2434     case HBAR_CURSOR:
2435       NSRectFill (r);
2436       break;
2437     case BAR_CURSOR:
2438       s = r;
2439       /* If the character under cursor is R2L, draw the bar cursor
2440          on the right of its glyph, rather than on the left.  */
2441       cursor_glyph = get_phys_cursor_glyph (w);
2442       if ((cursor_glyph->resolved_level & 1) != 0)
2443         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2445       NSRectFill (s);
2446       break;
2447     }
2448   ns_unfocus (f);
2450   /* draw the character under the cursor */
2451   if (cursor_type != NO_CURSOR)
2452     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2454 #ifdef NS_IMPL_COCOA
2455   NSEnableScreenUpdates ();
2456 #endif
2461 static void
2462 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2463 /* --------------------------------------------------------------------------
2464      External (RIF): Draw a vertical line.
2465    -------------------------------------------------------------------------- */
2467   struct frame *f = XFRAME (WINDOW_FRAME (w));
2468   struct face *face;
2469   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2471   NSTRACE (ns_draw_vertical_window_border);
2473   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2474   if (face)
2475       [ns_lookup_indexed_color(face->foreground, f) set];
2477   ns_focus (f, &r, 1);
2478   NSRectFill(r);
2479   ns_unfocus (f);
2483 void
2484 show_hourglass (struct atimer *timer)
2486   if (hourglass_shown_p)
2487     return;
2489   BLOCK_INPUT;
2491   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2493   hourglass_shown_p = 1;
2494   UNBLOCK_INPUT;
2498 void
2499 hide_hourglass (void)
2501   if (!hourglass_shown_p)
2502     return;
2504   BLOCK_INPUT;
2506   /* TODO: remove NSProgressIndicator from all frames */
2508   hourglass_shown_p = 0;
2509   UNBLOCK_INPUT;
2514 /* ==========================================================================
2516     Glyph drawing operations
2518    ========================================================================== */
2521 static inline NSRect
2522 ns_fix_rect_ibw (NSRect r, int fibw, int frame_pixel_width)
2523 /* --------------------------------------------------------------------------
2524     Under NS we draw internal borders inside fringes, and want full-width
2525     rendering to go all the way to edge.  This function makes that correction.
2526    -------------------------------------------------------------------------- */
2528   if (r.origin.y <= fibw+1)
2529     {
2530       r.size.height += r.origin.y;
2531       r.origin.y = 0;
2532     }
2533   if (r.origin.x <= fibw+1)
2534     {
2535       r.size.width += r.origin.x;
2536       r.origin.x = 0;
2537     }
2538   if (frame_pixel_width - (r.origin.x+r.size.width) <= fibw+1)
2539     r.size.width += fibw;
2541   return r;
2545 static int
2546 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2547 /* --------------------------------------------------------------------------
2548     Wrapper utility to account for internal border width on full-width lines,
2549     and allow top full-width rows to hit the frame top.  nr should be pointer
2550     to two successive NSRects.  Number of rects actually used is returned.
2551    -------------------------------------------------------------------------- */
2553   int n = get_glyph_string_clip_rects (s, nr, 2);
2554   if (s->row->full_width_p)
2555     {
2556       *nr = ns_fix_rect_ibw (*nr, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2557                             FRAME_PIXEL_WIDTH (s->f));
2558       if (n == 2)
2559         *nr = ns_fix_rect_ibw (*(nr+1), FRAME_INTERNAL_BORDER_WIDTH (s->f),
2560                               FRAME_PIXEL_WIDTH (s->f));
2561     }
2562   return n;
2565 /* --------------------------------------------------------------------
2566    Draw a wavy line under glyph string s. The wave fills wave_height
2567    pixels from y.
2569                     x          wave_length = 3
2570                                  --
2571                 y    *   *   *   *   *
2572                      |* * * * * * * * *
2573     wave_height = 3  | *   *   *   *
2574   --------------------------------------------------------------------- */
2576 static void
2577 ns_draw_underwave (struct glyph_string *s, CGFloat width, CGFloat x)
2579   int wave_height = 3, wave_length = 3;
2580   int y, dx, dy, odd, xmax;
2581   NSPoint a, b;
2582   NSRect waveClip;
2584   dx = wave_length;
2585   dy = wave_height - 1;
2586   y =  s->ybase + 1;
2587   xmax = x + width;
2589   /* Find and set clipping rectangle */
2590   waveClip = NSMakeRect (x, y, width, wave_height);
2591   [[NSGraphicsContext currentContext] saveGraphicsState];
2592   NSRectClip (waveClip);
2594   /* Draw the waves */
2595   a.x = x - ((int)(x) % dx);
2596   b.x = a.x + dx;
2597   odd = (int)(a.x/dx) % 2;
2598   a.y = b.y = y;
2600   if (odd)
2601     a.y += dy;
2602   else
2603     b.y += dy;
2605   while (a.x <= xmax)
2606     {
2607       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2608       a.x = b.x, a.y = b.y;
2609       b.x += dx, b.y = y + odd*dy;
2610       odd = !odd;
2611     }
2613   /* Restore previous clipping rectangle(s) */
2614   [[NSGraphicsContext currentContext] restoreGraphicsState];
2619 void
2620 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2621                          NSColor *defaultCol, CGFloat width, CGFloat x)
2622 /* --------------------------------------------------------------------------
2623    Draw underline, overline, and strike-through on glyph string s.
2624    -------------------------------------------------------------------------- */
2626   if (s->for_overlaps)
2627     return;
2629   /* Do underline. */
2630   if (face->underline_p)
2631     {
2632       if (s->face->underline_type == FACE_UNDER_WAVE)
2633         {
2634           if (face->underline_defaulted_p)
2635             [defaultCol set];
2636           else
2637             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2639           ns_draw_underwave (s, width, x);
2640         }
2641       else if (s->face->underline_type == FACE_UNDER_LINE)
2642         {
2644           NSRect r;
2645           unsigned long thickness, position;
2647           /* If the prev was underlined, match its appearance. */
2648           if (s->prev && s->prev->face->underline_p
2649               && s->prev->underline_thickness > 0)
2650             {
2651               thickness = s->prev->underline_thickness;
2652               position = s->prev->underline_position;
2653             }
2654           else
2655             {
2656               struct font *font;
2657               unsigned long descent;
2659               font=s->font;
2660               descent = s->y + s->height - s->ybase;
2662               /* Use underline thickness of font, defaulting to 1. */
2663               thickness = (font && font->underline_thickness > 0)
2664                 ? font->underline_thickness : 1;
2666               /* Determine the offset of underlining from the baseline. */
2667               if (x_underline_at_descent_line)
2668                 position = descent - thickness;
2669               else if (x_use_underline_position_properties
2670                        && font && font->underline_position >= 0)
2671                 position = font->underline_position;
2672               else if (font)
2673                 position = lround (font->descent / 2);
2674               else
2675                 position = underline_minimum_offset;
2677               position = max (position, underline_minimum_offset);
2679               /* Ensure underlining is not cropped. */
2680               if (descent <= position)
2681                 {
2682                   position = descent - 1;
2683                   thickness = 1;
2684                 }
2685               else if (descent < position + thickness)
2686                 thickness = 1;
2687             }
2689           s->underline_thickness = thickness;
2690           s->underline_position = position;
2692           r = NSMakeRect (x, s->ybase + position, width, thickness);
2694           if (face->underline_defaulted_p)
2695             [defaultCol set];
2696           else
2697             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2698           NSRectFill (r);
2699         }
2700     }
2701   /* Do overline. We follow other terms in using a thickness of 1
2702      and ignoring overline_margin. */
2703   if (face->overline_p)
2704     {
2705       NSRect r;
2706       r = NSMakeRect (x, s->y, width, 1);
2708       if (face->overline_color_defaulted_p)
2709         [defaultCol set];
2710       else
2711         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2712       NSRectFill (r);
2713     }
2715   /* Do strike-through.  We follow other terms for thickness and
2716      vertical position.*/
2717   if (face->strike_through_p)
2718     {
2719       NSRect r;
2720       unsigned long dy;
2722       dy = lrint ((s->height - 1) / 2);
2723       r = NSMakeRect (x, s->y + dy, width, 1);
2725       if (face->strike_through_color_defaulted_p)
2726         [defaultCol set];
2727       else
2728         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2729       NSRectFill (r);
2730     }
2733 static void
2734 ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char right_p)
2735 /* --------------------------------------------------------------------------
2736     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2737     Note we can't just use an NSDrawRect command, because of the possibility
2738     of some sides not being drawn, and because the rect will be filled.
2739    -------------------------------------------------------------------------- */
2741   NSRect s = r;
2742   [col set];
2744   /* top, bottom */
2745   s.size.height = thickness;
2746   NSRectFill (s);
2747   s.origin.y += r.size.height - thickness;
2748   NSRectFill (s);
2750   s.size.height = r.size.height;
2751   s.origin.y = r.origin.y;
2753   /* left, right (optional) */
2754   s.size.width = thickness;
2755   if (left_p)
2756     NSRectFill (s);
2757   if (right_p)
2758     {
2759       s.origin.x += r.size.width - thickness;
2760       NSRectFill (s);
2761     }
2765 static void
2766 ns_draw_relief (NSRect r, int thickness, char raised_p,
2767                char top_p, char bottom_p, char left_p, char right_p,
2768                struct glyph_string *s)
2769 /* --------------------------------------------------------------------------
2770     Draw a relief rect inside r, optionally leaving some sides open.
2771     Note we can't just use an NSDrawBezel command, because of the possibility
2772     of some sides not being drawn, and because the rect will be filled.
2773    -------------------------------------------------------------------------- */
2775   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2776   NSColor *newBaseCol = nil;
2777   NSRect sr = r;
2779   NSTRACE (ns_draw_relief);
2781   /* set up colors */
2783   if (s->face->use_box_color_for_shadows_p)
2784     {
2785       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2786     }
2787 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2788            && s->img->pixmap
2789            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2790        {
2791          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2792        } */
2793   else
2794     {
2795       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2796     }
2798   if (newBaseCol == nil)
2799     newBaseCol = [NSColor grayColor];
2801   if (newBaseCol != baseCol)  /* TODO: better check */
2802     {
2803       [baseCol release];
2804       baseCol = [newBaseCol retain];
2805       [lightCol release];
2806       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2807       [darkCol release];
2808       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2809     }
2811   [(raised_p ? lightCol : darkCol) set];
2813   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2815   /* top */
2816   sr.size.height = thickness;
2817   if (top_p) NSRectFill (sr);
2819   /* left */
2820   sr.size.height = r.size.height;
2821   sr.size.width = thickness;
2822   if (left_p) NSRectFill (sr);
2824   [(raised_p ? darkCol : lightCol) set];
2826   /* bottom */
2827   sr.size.width = r.size.width;
2828   sr.size.height = thickness;
2829   sr.origin.y += r.size.height - thickness;
2830   if (bottom_p) NSRectFill (sr);
2832   /* right */
2833   sr.size.height = r.size.height;
2834   sr.origin.y = r.origin.y;
2835   sr.size.width = thickness;
2836   sr.origin.x += r.size.width - thickness;
2837   if (right_p) NSRectFill (sr);
2841 static void
2842 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2843 /* --------------------------------------------------------------------------
2844       Function modeled after x_draw_glyph_string_box ().
2845       Sets up parameters for drawing.
2846    -------------------------------------------------------------------------- */
2848   int right_x, last_x;
2849   char left_p, right_p;
2850   struct glyph *last_glyph;
2851   NSRect r;
2852   int thickness;
2853   struct face *face;
2855   if (s->hl == DRAW_MOUSE_FACE)
2856     {
2857       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2858       if (!face)
2859         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2860     }
2861   else
2862     face = s->face;
2864   thickness = face->box_line_width;
2866   NSTRACE (ns_dumpglyphs_box_or_relief);
2868   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2869             ? WINDOW_RIGHT_EDGE_X (s->w)
2870             : window_box_right (s->w, s->area));
2871   last_glyph = (s->cmp || s->img
2872                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2874   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2875               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2877   left_p = (s->first_glyph->left_box_line_p
2878             || (s->hl == DRAW_MOUSE_FACE
2879                 && (s->prev == NULL || s->prev->hl != s->hl)));
2880   right_p = (last_glyph->right_box_line_p
2881              || (s->hl == DRAW_MOUSE_FACE
2882                  && (s->next == NULL || s->next->hl != s->hl)));
2884   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2886   /* expand full-width row over internal borders */
2887   if (s->row->full_width_p)
2888     r = ns_fix_rect_ibw (r, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2889                         FRAME_PIXEL_WIDTH (s->f));
2891   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2892   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2893     {
2894       ns_draw_box (r, abs (thickness),
2895                    ns_lookup_indexed_color (face->box_color, s->f),
2896                   left_p, right_p);
2897     }
2898   else
2899     {
2900       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2901                      1, 1, left_p, right_p, s);
2902     }
2906 static void
2907 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2908 /* --------------------------------------------------------------------------
2909       Modeled after x_draw_glyph_string_background, which draws BG in
2910       certain cases.  Others are left to the text rendering routine.
2911    -------------------------------------------------------------------------- */
2913   NSTRACE (ns_maybe_dumpglyphs_background);
2915   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2916     {
2917       int box_line_width = max (s->face->box_line_width, 0);
2918       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2919           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2920         {
2921           struct face *face;
2922           if (s->hl == DRAW_MOUSE_FACE)
2923             {
2924               face = FACE_FROM_ID (s->f,
2925                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2926               if (!face)
2927                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2928             }
2929           else
2930             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2931           if (!face->stipple)
2932             [(NS_FACE_BACKGROUND (face) != 0
2933               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2934               : FRAME_BACKGROUND_COLOR (s->f)) set];
2935           else
2936             {
2937               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2938               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2939             }
2941           if (s->hl != DRAW_CURSOR)
2942             {
2943               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2944                                     s->background_width,
2945                                     s->height-2*box_line_width);
2947               /* expand full-width row over internal borders */
2948               if (s->row->full_width_p)
2949                 {
2950                   int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2951                   if (r.origin.y <= fibw+1 + box_line_width)
2952                     {
2953                       r.size.height += r.origin.y;
2954                       r.origin.y = 0;
2955                     }
2956                   if (r.origin.x <= fibw+1)
2957                     {
2958                       r.size.width += 2*r.origin.x;
2959                       r.origin.x = 0;
2960                     }
2961                   if (FRAME_PIXEL_WIDTH (s->f) - (r.origin.x + r.size.width)
2962                       <= fibw+1)
2963                     r.size.width += fibw;
2964                 }
2966               NSRectFill (r);
2967             }
2969           s->background_filled_p = 1;
2970         }
2971     }
2975 static void
2976 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2977 /* --------------------------------------------------------------------------
2978       Renders an image and associated borders.
2979    -------------------------------------------------------------------------- */
2981   EmacsImage *img = s->img->pixmap;
2982   int box_line_vwidth = max (s->face->box_line_width, 0);
2983   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2984   int bg_x, bg_y, bg_height;
2985   int th;
2986   char raised_p;
2987   NSRect br;
2988   struct face *face;
2989   NSColor *tdCol;
2991   NSTRACE (ns_dumpglyphs_image);
2993   if (s->face->box != FACE_NO_BOX
2994       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2995     x += abs (s->face->box_line_width);
2997   bg_x = x;
2998   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2999   bg_height = s->height;
3000   /* other terms have this, but was causing problems w/tabbar mode */
3001   /* - 2 * box_line_vwidth; */
3003   if (s->slice.x == 0) x += s->img->hmargin;
3004   if (s->slice.y == 0) y += s->img->vmargin;
3006   /* Draw BG: if we need larger area than image itself cleared, do that,
3007      otherwise, since we composite the image under NS (instead of mucking
3008      with its background color), we must clear just the image area. */
3009   if (s->hl == DRAW_MOUSE_FACE)
3010     {
3011       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3012       if (!face)
3013        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3014     }
3015   else
3016     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3018   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3020   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3021       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3022     {
3023       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3024       s->background_filled_p = 1;
3025     }
3026   else
3027     {
3028       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3029     }
3031   /* expand full-width row over internal borders */
3032   if (s->row->full_width_p)
3033     {
3034       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
3035       if (br.origin.y <= fibw+1 + box_line_vwidth)
3036         {
3037           br.size.height += br.origin.y;
3038           br.origin.y = 0;
3039         }
3040       if (br.origin.x <= fibw+1 + box_line_vwidth)
3041         {
3042           br.size.width += br.origin.x;
3043           br.origin.x = 0;
3044         }
3045       if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) <= fibw+1)
3046         br.size.width += fibw;
3047     }
3049   NSRectFill (br);
3051   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3052   if (img != nil)
3053       [img drawInRect: br
3054               fromRect: NSZeroRect
3055              operation: NSCompositeSourceOver
3056               fraction: 1.0
3057            respectFlipped: YES
3058                 hints: nil];
3060   if (s->hl == DRAW_CURSOR)
3061     {
3062     [FRAME_CURSOR_COLOR (s->f) set];
3063     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3064       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3065     else
3066       /* Currently on NS img->mask is always 0. Since
3067          get_window_cursor_type specifies a hollow box cursor when on
3068          a non-masked image we never reach this clause. But we put it
3069          in in anticipation of better support for image masks on
3070          NS. */
3071       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3072     }
3073   else
3074     {
3075       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3076     }
3078   /* Draw underline, overline, strike-through. */
3079   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3081   /* Draw relief, if requested */
3082   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3083     {
3084       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3085         {
3086           th = tool_bar_button_relief >= 0 ?
3087             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3088           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3089         }
3090       else
3091         {
3092           th = abs (s->img->relief);
3093           raised_p = (s->img->relief > 0);
3094         }
3096       r.origin.x = x - th;
3097       r.origin.y = y - th;
3098       r.size.width = s->slice.width + 2*th-1;
3099       r.size.height = s->slice.height + 2*th-1;
3100       ns_draw_relief (r, th, raised_p,
3101                       s->slice.y == 0,
3102                       s->slice.y + s->slice.height == s->img->height,
3103                       s->slice.x == 0,
3104                       s->slice.x + s->slice.width == s->img->width, s);
3105     }
3107   /* If there is no mask, the background won't be seen,
3108      so draw a rectangle on the image for the cursor.
3109      Do this for all images, getting transparency right is not reliable.  */
3110   if (s->hl == DRAW_CURSOR)
3111     {
3112       int thickness = abs (s->img->relief);
3113       if (thickness == 0) thickness = 1;
3114       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3115     }
3119 static void
3120 ns_dumpglyphs_stretch (struct glyph_string *s)
3122   NSRect r[2];
3123   int n, i;
3124   struct face *face;
3125   NSColor *fgCol, *bgCol;
3127   if (!s->background_filled_p)
3128     {
3129       n = ns_get_glyph_string_clip_rect (s, r);
3130       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3132       ns_focus (s->f, r, n);
3134       if (s->hl == DRAW_MOUSE_FACE)
3135        {
3136          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3137          if (!face)
3138            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3139        }
3140       else
3141        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3143       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3144       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3146       for (i=0; i<n; i++)
3147         {
3148           if (!s->row->full_width_p)
3149             {
3150               int overrun, leftoverrun;
3152               /* truncate to avoid overwriting fringe and/or scrollbar */
3153               overrun = max (0, (s->x + s->background_width)
3154                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3155                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3156               r[i].size.width -= overrun;
3158               /* truncate to avoid overwriting to left of the window box */
3159               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3160                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3162               if (leftoverrun > 0)
3163                 {
3164                   r[i].origin.x += leftoverrun;
3165                   r[i].size.width -= leftoverrun;
3166                 }
3168               /* XXX: Try to work between problem where a stretch glyph on
3169                  a partially-visible bottom row will clear part of the
3170                  modeline, and another where list-buffers headers and similar
3171                  rows erroneously have visible_height set to 0.  Not sure
3172                  where this is coming from as other terms seem not to show. */
3173               r[i].size.height = min (s->height, s->row->visible_height);
3174             }
3176           /* expand full-width rows over internal borders */
3177           else
3178             {
3179               r[i] = ns_fix_rect_ibw (r[i], FRAME_INTERNAL_BORDER_WIDTH (s->f),
3180                                       FRAME_PIXEL_WIDTH (s->f));
3181             }
3183           [bgCol set];
3185           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3186              overwriting cursor (usually when cursor on a tab) */
3187           if (s->hl == DRAW_CURSOR)
3188             {
3189               CGFloat x, width;
3191               x = r[i].origin.x;
3192               width = s->w->phys_cursor_width;
3193               r[i].size.width -= width;
3194               r[i].origin.x += width;
3196               NSRectFill (r[i]);
3198               /* Draw overlining, etc. on the cursor. */
3199               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3200                 ns_draw_text_decoration (s, face, bgCol, width, x);
3201               else
3202                 ns_draw_text_decoration (s, face, fgCol, width, x);
3203             }
3204           else
3205             {
3206               NSRectFill (r[i]);
3207             }
3209           /* Draw overlining, etc. on the stretch glyph (or the part
3210              of the stretch glyph after the cursor). */
3211           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3212                                    r[i].origin.x);
3213         }
3214       ns_unfocus (s->f);
3215       s->background_filled_p = 1;
3216     }
3220 static void
3221 ns_draw_glyph_string (struct glyph_string *s)
3222 /* --------------------------------------------------------------------------
3223       External (RIF): Main draw-text call.
3224    -------------------------------------------------------------------------- */
3226   /* TODO (optimize): focus for box and contents draw */
3227   NSRect r[2];
3228   int n;
3229   char box_drawn_p = 0;
3231   NSTRACE (ns_draw_glyph_string);
3233   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3234     {
3235       int width;
3236       struct glyph_string *next;
3238       for (width = 0, next = s->next;
3239            next && width < s->right_overhang;
3240            width += next->width, next = next->next)
3241         if (next->first_glyph->type != IMAGE_GLYPH)
3242           {
3243             if (next->first_glyph->type != STRETCH_GLYPH)
3244               {
3245                 n = ns_get_glyph_string_clip_rect (s->next, r);
3246                 ns_focus (s->f, r, n);
3247                 ns_maybe_dumpglyphs_background (s->next, 1);
3248                 ns_unfocus (s->f);
3249               }
3250             else
3251               {
3252                 ns_dumpglyphs_stretch (s->next);
3253               }
3254             next->num_clips = 0;
3255           }
3256     }
3258   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3259         && (s->first_glyph->type == CHAR_GLYPH
3260             || s->first_glyph->type == COMPOSITE_GLYPH))
3261     {
3262       n = ns_get_glyph_string_clip_rect (s, r);
3263       ns_focus (s->f, r, n);
3264       ns_maybe_dumpglyphs_background (s, 1);
3265       ns_dumpglyphs_box_or_relief (s);
3266       ns_unfocus (s->f);
3267       box_drawn_p = 1;
3268     }
3270   switch (s->first_glyph->type)
3271     {
3273     case IMAGE_GLYPH:
3274       n = ns_get_glyph_string_clip_rect (s, r);
3275       ns_focus (s->f, r, n);
3276       ns_dumpglyphs_image (s, r[0]);
3277       ns_unfocus (s->f);
3278       break;
3280     case STRETCH_GLYPH:
3281       ns_dumpglyphs_stretch (s);
3282       break;
3284     case CHAR_GLYPH:
3285     case COMPOSITE_GLYPH:
3286       n = ns_get_glyph_string_clip_rect (s, r);
3287       ns_focus (s->f, r, n);
3289       if (s->for_overlaps || (s->cmp_from > 0
3290                               && ! s->first_glyph->u.cmp.automatic))
3291         s->background_filled_p = 1;
3292       else
3293         ns_maybe_dumpglyphs_background
3294           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3296       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3297                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3298                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3299                       NS_DUMPGLYPH_NORMAL));
3300       ns_tmp_font = (struct nsfont_info *)s->face->font;
3301       if (ns_tmp_font == NULL)
3302           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
3304       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3305         {
3306           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3307           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3308           NS_FACE_FOREGROUND (s->face) = tmp;
3309         }
3311       ns_tmp_font->font.driver->draw
3312         (s, 0, s->nchars, s->x, s->y,
3313          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3314          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
3316       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3317         {
3318           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3319           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3320           NS_FACE_FOREGROUND (s->face) = tmp;
3321         }
3323       ns_unfocus (s->f);
3324       break;
3326     case GLYPHLESS_GLYPH:
3327       n = ns_get_glyph_string_clip_rect (s, r);
3328       ns_focus (s->f, r, n);
3330       if (s->for_overlaps || (s->cmp_from > 0
3331                               && ! s->first_glyph->u.cmp.automatic))
3332         s->background_filled_p = 1;
3333       else
3334         ns_maybe_dumpglyphs_background
3335           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3336       /* ... */
3337       /* Not yet implemented.  */
3338       /* ... */
3339       ns_unfocus (s->f);
3340       break;
3342     default:
3343       abort ();
3344     }
3346   /* Draw box if not done already. */
3347   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3348     {
3349       n = ns_get_glyph_string_clip_rect (s, r);
3350       ns_focus (s->f, r, n);
3351       ns_dumpglyphs_box_or_relief (s);
3352       ns_unfocus (s->f);
3353     }
3355   s->num_clips = 0;
3360 /* ==========================================================================
3362     Event loop
3364    ========================================================================== */
3367 static void
3368 ns_send_appdefined (int value)
3369 /* --------------------------------------------------------------------------
3370     Internal: post an appdefined event which EmacsApp-sendEvent will
3371               recognize and take as a command to halt the event loop.
3372    -------------------------------------------------------------------------- */
3374   /*NSTRACE (ns_send_appdefined); */
3376   /* Only post this event if we haven't already posted one.  This will end
3377        the [NXApp run] main loop after having processed all events queued at
3378        this moment.  */
3379   if (send_appdefined)
3380     {
3381       NSEvent *nxev;
3383       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3384       send_appdefined = NO;
3386       /* Don't need wakeup timer any more */
3387       if (timed_entry)
3388         {
3389           [timed_entry invalidate];
3390           [timed_entry release];
3391           timed_entry = nil;
3392         }
3394       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3395                                 location: NSMakePoint (0, 0)
3396                            modifierFlags: 0
3397                                timestamp: 0
3398                             windowNumber: [[NSApp mainWindow] windowNumber]
3399                                  context: [NSApp context]
3400                                  subtype: 0
3401                                    data1: value
3402                                    data2: 0];
3404       /* Post an application defined event on the event queue.  When this is
3405          received the [NXApp run] will return, thus having processed all
3406          events which are currently queued.  */
3407       [NSApp postEvent: nxev atStart: NO];
3408     }
3411 static int
3412 ns_read_socket (struct terminal *terminal, int expected,
3413                 struct input_event *hold_quit)
3414 /* --------------------------------------------------------------------------
3415      External (hook): Post an event to ourself and keep reading events until
3416      we read it back again.  In effect process all events which were waiting.
3417      From 21+ we have to manage the event buffer ourselves.
3418    -------------------------------------------------------------------------- */
3420   struct input_event ev;
3421   int nevents;
3423 /* NSTRACE (ns_read_socket); */
3425   if ([NSApp modalWindow] != nil)
3426     return -1;
3428   if (interrupt_input_blocked)
3429     {
3430       interrupt_input_pending = 1;
3431 #ifdef SYNC_INPUT
3432       pending_signals = 1;
3433 #endif
3434       return -1;
3435     }
3437   interrupt_input_pending = 0;
3438 #ifdef SYNC_INPUT
3439   pending_signals = pending_atimers;
3440 #endif
3442   BLOCK_INPUT;
3443   n_emacs_events_pending = 0;
3444   EVENT_INIT (ev);
3445   emacs_event = &ev;
3446   q_event_ptr = hold_quit;
3448   /* we manage autorelease pools by allocate/reallocate each time around
3449      the loop; strict nesting is occasionally violated but seems not to
3450      matter.. earlier methods using full nesting caused major memory leaks */
3451   [outerpool release];
3452   outerpool = [[NSAutoreleasePool alloc] init];
3454   /* If have pending open-file requests, attend to the next one of those. */
3455   if (ns_pending_files && [ns_pending_files count] != 0
3456       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3457     {
3458       [ns_pending_files removeObjectAtIndex: 0];
3459     }
3460   /* Deal with pending service requests. */
3461   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3462     && [(EmacsApp *)
3463          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3464                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3465     {
3466       [ns_pending_service_names removeObjectAtIndex: 0];
3467       [ns_pending_service_args removeObjectAtIndex: 0];
3468     }
3469   else
3470     {
3471       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3472          to ourself, otherwise [NXApp run] will never exit.  */
3473       send_appdefined = YES;
3474       ns_send_appdefined (-1);
3476       if (++apploopnr != 1)
3477         {
3478           abort ();
3479         }
3480       [NSApp run];
3481       --apploopnr;
3482     }
3484   nevents = n_emacs_events_pending;
3485   n_emacs_events_pending = 0;
3486   emacs_event = q_event_ptr = NULL;
3487   UNBLOCK_INPUT;
3489   return nevents;
3494 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3495            fd_set *exceptfds, EMACS_TIME *timeout, sigset_t *sigmask)
3496 /* --------------------------------------------------------------------------
3497      Replacement for select, checking for events
3498    -------------------------------------------------------------------------- */
3500   int result;
3501   NSEvent *ev;
3502   int k, nr = 0;
3503   struct input_event event;
3504   char c;
3506 /*  NSTRACE (ns_select); */
3508   for (k = 0; readfds && k < nfds+1; k++)
3509     if (FD_ISSET(k, readfds)) ++nr;
3511   if (NSApp == nil
3512       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3513     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3515   [outerpool release];
3516   outerpool = [[NSAutoreleasePool alloc] init];
3518   
3519   send_appdefined = YES;
3520   if (nr > 0)
3521     {
3522       pthread_mutex_lock (&select_mutex);
3523       select_nfds = nfds;
3524       select_valid = 0;
3525       if (readfds)
3526         {
3527           select_readfds = *readfds;
3528           select_valid += SELECT_HAVE_READ;
3529         }
3530       if (writefds)
3531         {
3532           select_writefds = *writefds;
3533           select_valid += SELECT_HAVE_WRITE;
3534         }
3536       if (timeout)
3537         {
3538           select_timeout = *timeout;
3539           select_valid += SELECT_HAVE_TMO;
3540         }
3542       pthread_mutex_unlock (&select_mutex);
3544       /* Inform fd_handler that select should be called */
3545       c = 'g';
3546       write (selfds[1], &c, 1);
3547     }
3548   else if (nr == 0 && timeout)
3549     {
3550       /* No file descriptor, just a timeout, no need to wake fd_handler  */
3551       double time = EMACS_TIME_TO_DOUBLE (*timeout);
3552       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3553                                                       target: NSApp
3554                                                     selector:
3555                                   @selector (timeout_handler:)
3556                                                     userInfo: 0
3557                                                      repeats: NO]
3558                       retain];
3559     }
3560   else /* No timeout and no file descriptors, can this happen?  */
3561     {
3562       /* Send appdefined so we exit from the loop */
3563       ns_send_appdefined (-1);
3564     }
3566   EVENT_INIT (event);
3567   BLOCK_INPUT;
3568   emacs_event = &event;
3569   if (++apploopnr != 1)
3570     {
3571       abort();
3572     }
3573   [NSApp run];
3574   --apploopnr;
3575   emacs_event = NULL;
3576   if (nr > 0 && readfds)
3577     {
3578       c = 's';
3579       write (selfds[1], &c, 1);
3580     }
3581   UNBLOCK_INPUT;
3583   ev = last_appdefined_event;
3585   if (ev)
3586     {
3587       int t;
3588       if ([ev type] != NSApplicationDefined)
3589         abort ();
3591       t = [ev data1];
3592       last_appdefined_event = 0;
3594       if (t == -2)
3595         {
3596           /* The NX_APPDEFINED event we received was a timeout. */
3597           result = 0;
3598         }
3599       else if (t == -1)
3600         {
3601           /* The NX_APPDEFINED event we received was the result of
3602              at least one real input event arriving.  */
3603           errno = EINTR;
3604           result = -1;
3605         }
3606       else
3607         {
3608           /* Received back from select () in fd_handler; copy the results */
3609           pthread_mutex_lock (&select_mutex);
3610           if (readfds) *readfds = select_readfds;
3611           if (writefds) *writefds = select_writefds;
3612           if (timeout) *timeout = select_timeout;
3613           pthread_mutex_unlock (&select_mutex);
3614           result = t;
3615         }
3616     }
3618   return result;
3623 /* ==========================================================================
3625     Scrollbar handling
3627    ========================================================================== */
3630 static void
3631 ns_set_vertical_scroll_bar (struct window *window,
3632                            int portion, int whole, int position)
3633 /* --------------------------------------------------------------------------
3634       External (hook): Update or add scrollbar
3635    -------------------------------------------------------------------------- */
3637   Lisp_Object win;
3638   NSRect r, v;
3639   struct frame *f = XFRAME (WINDOW_FRAME (window));
3640   EmacsView *view = FRAME_NS_VIEW (f);
3641   int window_y, window_height;
3642   BOOL barOnVeryLeft, barOnVeryRight;
3643   int top, left, height, width, sb_width, sb_left;
3644   EmacsScroller *bar;
3646   /* optimization; display engine sends WAY too many of these.. */
3647   if (!NILP (window->vertical_scroll_bar))
3648     {
3649       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3650       if ([bar checkSamePosition: position portion: portion whole: whole])
3651         {
3652           if (view->scrollbarsNeedingUpdate == 0)
3653             {
3654               if (!windows_or_buffers_changed)
3655                   return;
3656             }
3657           else
3658             view->scrollbarsNeedingUpdate--;
3659         }
3660     }
3662   NSTRACE (ns_set_vertical_scroll_bar);
3664   /* Get dimensions.  */
3665   window_box (window, -1, 0, &window_y, 0, &window_height);
3666   top = window_y;
3667   height = window_height;
3668   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3669   left = WINDOW_SCROLL_BAR_AREA_X (window);
3671   if (top < 5) /* top scrollbar adjustment */
3672     {
3673       top -= FRAME_INTERNAL_BORDER_WIDTH (f);
3674       height += FRAME_INTERNAL_BORDER_WIDTH (f);
3675     }
3677   /* allow for displaying a skinnier scrollbar than char area allotted */
3678   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3679     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3681   barOnVeryLeft = left < 5;
3682   barOnVeryRight = FRAME_PIXEL_WIDTH (f) - left - width < 5;
3683   sb_left = left + FRAME_INTERNAL_BORDER_WIDTH (f)
3684       * (barOnVeryLeft ? -1 : (barOnVeryRight ? 1 : 0));
3686   r = NSMakeRect (sb_left, top, sb_width, height);
3687   /* the parent view is flipped, so we need to flip y value */
3688   v = [view frame];
3689   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3691   XSETWINDOW (win, window);
3692   BLOCK_INPUT;
3694   /* we want at least 5 lines to display a scrollbar */
3695   if (WINDOW_TOTAL_LINES (window) < 5)
3696     {
3697       if (!NILP (window->vertical_scroll_bar))
3698         {
3699           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3700           [bar removeFromSuperview];
3701           wset_vertical_scroll_bar (window, Qnil);
3702         }
3703       ns_clear_frame_area (f, sb_left, top, width, height);
3704       UNBLOCK_INPUT;
3705       return;
3706     }
3708   if (NILP (window->vertical_scroll_bar))
3709     {
3710       ns_clear_frame_area (f, sb_left, top, width, height);
3711       bar = [[EmacsScroller alloc] initFrame: r window: win];
3712       wset_vertical_scroll_bar (window, make_save_value (bar, 0));
3713     }
3714   else
3715     {
3716       NSRect oldRect;
3717       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3718       oldRect = [bar frame];
3719       r.size.width = oldRect.size.width;
3720       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3721         {
3722           if (oldRect.origin.x != r.origin.x)
3723               ns_clear_frame_area (f, sb_left, top, width, height);
3724           [bar setFrame: r];
3725         }
3726     }
3728   [bar setPosition: position portion: portion whole: whole];
3729   UNBLOCK_INPUT;
3733 static void
3734 ns_condemn_scroll_bars (struct frame *f)
3735 /* --------------------------------------------------------------------------
3736      External (hook): arrange for all frame's scrollbars to be removed
3737      at next call to judge_scroll_bars, except for those redeemed.
3738    -------------------------------------------------------------------------- */
3740   int i;
3741   id view;
3742   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3744   NSTRACE (ns_condemn_scroll_bars);
3746   for (i =[subviews count]-1; i >= 0; i--)
3747     {
3748       view = [subviews objectAtIndex: i];
3749       if ([view isKindOfClass: [EmacsScroller class]])
3750         [view condemn];
3751     }
3755 static void
3756 ns_redeem_scroll_bar (struct window *window)
3757 /* --------------------------------------------------------------------------
3758      External (hook): arrange to spare this window's scrollbar
3759      at next call to judge_scroll_bars.
3760    -------------------------------------------------------------------------- */
3762   id bar;
3763   NSTRACE (ns_redeem_scroll_bar);
3764   if (!NILP (window->vertical_scroll_bar))
3765     {
3766       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3767       [bar reprieve];
3768     }
3772 static void
3773 ns_judge_scroll_bars (struct frame *f)
3774 /* --------------------------------------------------------------------------
3775      External (hook): destroy all scrollbars on frame that weren't
3776      redeemed after call to condemn_scroll_bars.
3777    -------------------------------------------------------------------------- */
3779   int i;
3780   id view;
3781   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3782   NSTRACE (ns_judge_scroll_bars);
3783   for (i =[subviews count]-1; i >= 0; i--)
3784     {
3785       view = [subviews objectAtIndex: i];
3786       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3787       [view judge];
3788     }
3792 void
3793 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
3795   /* XXX irrelevant under NS */
3800 /* ==========================================================================
3802     Initialization
3804    ========================================================================== */
3807 x_display_pixel_height (struct ns_display_info *dpyinfo)
3809   NSScreen *screen = [NSScreen mainScreen];
3810   return [screen frame].size.height;
3814 x_display_pixel_width (struct ns_display_info *dpyinfo)
3816   NSScreen *screen = [NSScreen mainScreen];
3817   return [screen frame].size.width;
3821 static Lisp_Object ns_string_to_lispmod (const char *s)
3822 /* --------------------------------------------------------------------------
3823      Convert modifier name to lisp symbol
3824    -------------------------------------------------------------------------- */
3826   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
3827     return Qmeta;
3828   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
3829     return Qsuper;
3830   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3831     return Qcontrol;
3832   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
3833     return Qalt;
3834   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
3835     return Qhyper;
3836   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
3837     return Qnone;
3838   else
3839     return Qnil;
3843 static void
3844 ns_default (const char *parameter, Lisp_Object *result,
3845            Lisp_Object yesval, Lisp_Object noval,
3846            BOOL is_float, BOOL is_modstring)
3847 /* --------------------------------------------------------------------------
3848       Check a parameter value in user's preferences
3849    -------------------------------------------------------------------------- */
3851   const char *value = ns_get_defaults_value (parameter);
3853   if (value)
3854     {
3855       double f;
3856       char *pos;
3857       if (c_strcasecmp (value, "YES") == 0)
3858         *result = yesval;
3859       else if (c_strcasecmp (value, "NO") == 0)
3860         *result = noval;
3861       else if (is_float && (f = strtod (value, &pos), pos != value))
3862         *result = make_float (f);
3863       else if (is_modstring && value)
3864         *result = ns_string_to_lispmod (value);
3865       else fprintf (stderr,
3866                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3867     }
3871 static void
3872 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3873 /* --------------------------------------------------------------------------
3874       Initialize global info and storage for display.
3875    -------------------------------------------------------------------------- */
3877     NSScreen *screen = [NSScreen mainScreen];
3878     NSWindowDepth depth = [screen depth];
3879     Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
3881     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3882     dpyinfo->resy = 72.27;
3883     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3884                                                   NSColorSpaceFromDepth (depth)]
3885                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3886                                                  NSColorSpaceFromDepth (depth)];
3887     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3888     dpyinfo->image_cache = make_image_cache ();
3889     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
3890     dpyinfo->color_table->colors = NULL;
3891     dpyinfo->root_window = 42; /* a placeholder.. */
3893     hlinfo->mouse_face_mouse_frame = NULL;
3894     hlinfo->mouse_face_deferred_gc = 0;
3895     hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
3896     hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
3897     hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
3898     hlinfo->mouse_face_window = hlinfo->mouse_face_overlay = Qnil;
3899     hlinfo->mouse_face_hidden = 0;
3901     hlinfo->mouse_face_mouse_x = hlinfo->mouse_face_mouse_y = 0;
3902     hlinfo->mouse_face_defer = 0;
3904     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3906     dpyinfo->n_fonts = 0;
3907     dpyinfo->smallest_font_height = 1;
3908     dpyinfo->smallest_char_width = 1;
3912 /* This and next define (many of the) public functions in this file. */
3913 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3914          with using despite presence in the "system dependent" redisplay
3915          interface.  In addition, many of the ns_ methods have code that is
3916          shared with all terms, indicating need for further refactoring. */
3917 extern frame_parm_handler ns_frame_parm_handlers[];
3918 static struct redisplay_interface ns_redisplay_interface =
3920   ns_frame_parm_handlers,
3921   x_produce_glyphs,
3922   x_write_glyphs,
3923   x_insert_glyphs,
3924   x_clear_end_of_line,
3925   ns_scroll_run,
3926   ns_after_update_window_line,
3927   ns_update_window_begin,
3928   ns_update_window_end,
3929   x_cursor_to,
3930   ns_flush,
3931   0, /* flush_display_optional */
3932   x_clear_window_mouse_face,
3933   x_get_glyph_overhangs,
3934   x_fix_overlapping_area,
3935   ns_draw_fringe_bitmap,
3936   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3937   0, /* destroy_fringe_bitmap */
3938   ns_compute_glyph_string_overhangs,
3939   ns_draw_glyph_string, /* interface to nsfont.m */
3940   ns_define_frame_cursor,
3941   ns_clear_frame_area,
3942   ns_draw_window_cursor,
3943   ns_draw_vertical_window_border,
3944   ns_shift_glyphs_for_insert
3948 static void
3949 ns_delete_display (struct ns_display_info *dpyinfo)
3951   /* TODO... */
3955 /* This function is called when the last frame on a display is deleted. */
3956 static void
3957 ns_delete_terminal (struct terminal *terminal)
3959   struct ns_display_info *dpyinfo = terminal->display_info.ns;
3961   /* Protect against recursive calls.  delete_frame in
3962      delete_terminal calls us back when it deletes our last frame.  */
3963   if (!terminal->name)
3964     return;
3966   BLOCK_INPUT;
3968   x_destroy_all_bitmaps (dpyinfo);
3969   ns_delete_display (dpyinfo);
3970   UNBLOCK_INPUT;
3974 static struct terminal *
3975 ns_create_terminal (struct ns_display_info *dpyinfo)
3976 /* --------------------------------------------------------------------------
3977       Set up use of NS before we make the first connection.
3978    -------------------------------------------------------------------------- */
3980   struct terminal *terminal;
3982   NSTRACE (ns_create_terminal);
3984   terminal = create_terminal ();
3986   terminal->type = output_ns;
3987   terminal->display_info.ns = dpyinfo;
3988   dpyinfo->terminal = terminal;
3990   terminal->rif = &ns_redisplay_interface;
3992   terminal->clear_frame_hook = ns_clear_frame;
3993   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
3994   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
3995   terminal->ring_bell_hook = ns_ring_bell;
3996   terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
3997   terminal->set_terminal_modes_hook = ns_set_terminal_modes;
3998   terminal->update_begin_hook = ns_update_begin;
3999   terminal->update_end_hook = ns_update_end;
4000   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
4001   terminal->read_socket_hook = ns_read_socket;
4002   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4003   terminal->mouse_position_hook = ns_mouse_position;
4004   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4005   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4007   terminal->fullscreen_hook = 0; /* see XTfullscreen_hook */
4009   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4010   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4011   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4012   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4014   terminal->delete_frame_hook = x_destroy_window;
4015   terminal->delete_terminal_hook = ns_delete_terminal;
4017   terminal->scroll_region_ok = 1;
4018   terminal->char_ins_del_ok = 1;
4019   terminal->line_ins_del_ok = 1;
4020   terminal->fast_clear_end_of_line = 1;
4021   terminal->memory_below_frame = 0;
4023   return terminal;
4027 struct ns_display_info *
4028 ns_term_init (Lisp_Object display_name)
4029 /* --------------------------------------------------------------------------
4030      Start the Application and get things rolling.
4031    -------------------------------------------------------------------------- */
4033   struct terminal *terminal;
4034   struct ns_display_info *dpyinfo;
4035   static int ns_initialized = 0;
4036   Lisp_Object tmp;
4038   NSTRACE (ns_term_init);
4040   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4041   /*GSDebugAllocationActive (YES); */
4042   BLOCK_INPUT;
4043   handling_signal = 0;
4045   if (!ns_initialized)
4046     {
4047       baud_rate = 38400;
4048       Fset_input_interrupt_mode (Qnil);
4050       if (selfds[0] == -1)
4051         {
4052           if (pipe (selfds) == -1)
4053             {
4054               fprintf (stderr, "Failed to create pipe: %s\n",
4055                        emacs_strerror (errno));
4056               abort ();
4057             }
4059           fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4060           FD_ZERO (&select_readfds);
4061           FD_ZERO (&select_writefds);
4062           pthread_mutex_init (&select_mutex, NULL);
4063         }
4064       ns_initialized = 1;
4065     }
4067   ns_pending_files = [[NSMutableArray alloc] init];
4068   ns_pending_service_names = [[NSMutableArray alloc] init];
4069   ns_pending_service_args = [[NSMutableArray alloc] init];
4071 /* Start app and create the main menu, window, view.
4072      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4073      The view will then ask the NSApp to stop and return to Emacs. */
4074   [EmacsApp sharedApplication];
4075   if (NSApp == nil)
4076     return NULL;
4077   [NSApp setDelegate: NSApp];
4079   /* Start the select thread.  */
4080   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4081                            toTarget:NSApp
4082                          withObject:nil];
4084   /* debugging: log all notifications */
4085   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4086                                          selector: @selector (logNotification:)
4087                                              name: nil object: nil]; */
4089   dpyinfo = xzalloc (sizeof *dpyinfo);
4091   ns_initialize_display_info (dpyinfo);
4092   terminal = ns_create_terminal (dpyinfo);
4094   terminal->kboard = xmalloc (sizeof *terminal->kboard);
4095   init_kboard (terminal->kboard);
4096   kset_window_system (terminal->kboard, Qns);
4097   terminal->kboard->next_kboard = all_kboards;
4098   all_kboards = terminal->kboard;
4099   /* Don't let the initial kboard remain current longer than necessary.
4100      That would cause problems if a file loaded on startup tries to
4101      prompt in the mini-buffer.  */
4102   if (current_kboard == initial_kboard)
4103     current_kboard = terminal->kboard;
4104   terminal->kboard->reference_count++;
4106   dpyinfo->next = x_display_list;
4107   x_display_list = dpyinfo;
4109   /* Put it on ns_display_name_list */
4110   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
4111                                 ns_display_name_list);
4112   dpyinfo->name_list_element = XCAR (ns_display_name_list);
4114   terminal->name = xstrdup (SSDATA (display_name));
4116   UNBLOCK_INPUT;
4118   if (!inhibit_x_resources)
4119     {
4120       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4121                  Qt, Qnil, NO, NO);
4122       tmp = Qnil;
4123       /* this is a standard variable */
4124       ns_default ("AppleAntiAliasingThreshold", &tmp,
4125                  make_float (10.0), make_float (6.0), YES, NO);
4126       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4127     }
4129   ns_selection_color = [[NSUserDefaults standardUserDefaults]
4130                          stringForKey: @"AppleHighlightColor"];
4131   if (ns_selection_color == nil)
4132     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
4134   {
4135     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4137     if ( cl == nil )
4138       {
4139         Lisp_Object color_file, color_map, color;
4140         unsigned long c;
4141         char *name;
4143         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4144                          Fsymbol_value (intern ("data-directory")));
4145         if (NILP (Ffile_readable_p (color_file)))
4146           fatal ("Could not find %s.\n", SDATA (color_file));
4148         color_map = Fx_load_color_file (color_file);
4149         if (NILP (color_map))
4150           fatal ("Could not read %s.\n", SDATA (color_file));
4152         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4153         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4154           {
4155             color = XCAR (color_map);
4156             name = SSDATA (XCAR (color));
4157             c = XINT (XCDR (color));
4158             [cl setColor:
4159                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4160                                             green: GREEN_FROM_ULONG (c) / 255.0
4161                                              blue: BLUE_FROM_ULONG (c) / 255.0
4162                                             alpha: 1.0]
4163                   forKey: [NSString stringWithUTF8String: name]];
4164           }
4165         [cl writeToFile: nil];
4166       }
4167   }
4169   {
4170 #ifdef NS_IMPL_GNUSTEP
4171     Vwindow_system_version = build_string (gnustep_base_version);
4172 #else
4173     /*PSnextrelease (128, c); */
4174     char c[DBL_BUFSIZE_BOUND];
4175     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4176     Vwindow_system_version = make_unibyte_string (c, len);
4177 #endif
4178   }
4180   delete_keyboard_wait_descriptor (0);
4182   ns_app_name = [[NSProcessInfo processInfo] processName];
4184 /* Set up OS X app menu */
4185 #ifdef NS_IMPL_COCOA
4186   {
4187     NSMenu *appMenu;
4188     NSMenuItem *item;
4189     /* set up the application menu */
4190     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4191     [svcsMenu setAutoenablesItems: NO];
4192     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4193     [appMenu setAutoenablesItems: NO];
4194     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4195     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4197     [appMenu insertItemWithTitle: @"About Emacs"
4198                           action: @selector (orderFrontStandardAboutPanel:)
4199                    keyEquivalent: @""
4200                          atIndex: 0];
4201     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4202     [appMenu insertItemWithTitle: @"Preferences..."
4203                           action: @selector (showPreferencesWindow:)
4204                    keyEquivalent: @","
4205                          atIndex: 2];
4206     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4207     item = [appMenu insertItemWithTitle: @"Services"
4208                                  action: @selector (menuDown:)
4209                           keyEquivalent: @""
4210                                 atIndex: 4];
4211     [appMenu setSubmenu: svcsMenu forItem: item];
4212     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4213     [appMenu insertItemWithTitle: @"Hide Emacs"
4214                           action: @selector (hide:)
4215                    keyEquivalent: @"h"
4216                          atIndex: 6];
4217     item =  [appMenu insertItemWithTitle: @"Hide Others"
4218                           action: @selector (hideOtherApplications:)
4219                    keyEquivalent: @"h"
4220                          atIndex: 7];
4221     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4222     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4223     [appMenu insertItemWithTitle: @"Quit Emacs"
4224                           action: @selector (terminate:)
4225                    keyEquivalent: @"q"
4226                          atIndex: 9];
4228     item = [mainMenu insertItemWithTitle: ns_app_name
4229                                   action: @selector (menuDown:)
4230                            keyEquivalent: @""
4231                                  atIndex: 0];
4232     [mainMenu setSubmenu: appMenu forItem: item];
4233     [dockMenu insertItemWithTitle: @"New Frame"
4234                            action: @selector (newFrame:)
4235                     keyEquivalent: @""
4236                           atIndex: 0];
4238     [NSApp setMainMenu: mainMenu];
4239     [NSApp setAppleMenu: appMenu];
4240     [NSApp setServicesMenu: svcsMenu];
4241     /* Needed at least on Cocoa, to get dock menu to show windows */
4242     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4244     [[NSNotificationCenter defaultCenter]
4245       addObserver: mainMenu
4246          selector: @selector (trackingNotification:)
4247              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4248     [[NSNotificationCenter defaultCenter]
4249       addObserver: mainMenu
4250          selector: @selector (trackingNotification:)
4251              name: NSMenuDidEndTrackingNotification object: mainMenu];
4252   }
4253 #endif /* MAC OS X menu setup */
4255   [NSApp run];
4256   ns_do_open_file = YES;
4257   return dpyinfo;
4261 void
4262 ns_term_shutdown (int sig)
4264   [[NSUserDefaults standardUserDefaults] synchronize];
4266   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4267   if (STRINGP (Vauto_save_list_file_name))
4268     unlink (SSDATA (Vauto_save_list_file_name));
4270   if (sig == 0 || sig == SIGTERM)
4271     {
4272       [NSApp terminate: NSApp];
4273     }
4274   else // force a stack trace to happen
4275     {
4276       abort();
4277     }
4281 /* ==========================================================================
4283     EmacsApp implementation
4285    ========================================================================== */
4288 @implementation EmacsApp
4290 - (void)logNotification: (NSNotification *)notification
4292   const char *name = [[notification name] UTF8String];
4293   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4294       && !strstr (name, "WindowNumber"))
4295     NSLog (@"notification: '%@'", [notification name]);
4299 - (void)sendEvent: (NSEvent *)theEvent
4300 /* --------------------------------------------------------------------------
4301      Called when NSApp is running for each event received.  Used to stop
4302      the loop when we choose, since there's no way to just run one iteration.
4303    -------------------------------------------------------------------------- */
4305   int type = [theEvent type];
4306   NSWindow *window = [theEvent window];
4307 /*  NSTRACE (sendEvent); */
4308 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4310 #ifdef NS_IMPL_COCOA
4311   if (type == NSApplicationDefined
4312       && [theEvent data2] == NSAPP_DATA2_RUNASSCRIPT)
4313     {
4314       ns_run_ascript ();
4315       [self stop: self];
4316       return;
4317     }
4318 #endif
4320   if (type == NSCursorUpdate && window == nil)
4321     {
4322       fprintf (stderr, "Dropping external cursor update event.\n");
4323       return;
4324     }
4326 #ifdef NS_IMPL_COCOA
4327   /* pass mouse down in resize handle and subsequent drags directly to
4328      EmacsWindow so we can generate continuous redisplays */
4329   if (ns_in_resize)
4330     {
4331       if (type == NSLeftMouseDragged)
4332         {
4333           [window mouseDragged: theEvent];
4334           return;
4335         }
4336       else if (type == NSLeftMouseUp)
4337         {
4338           [window mouseUp: theEvent];
4339           return;
4340         }
4341     }
4342   else if (type == NSLeftMouseDown)
4343     {
4344       NSRect r = ns_resize_handle_rect (window);
4345       if (NSPointInRect ([theEvent locationInWindow], r))
4346         {
4347           ns_in_resize = YES;
4348           [window mouseDown: theEvent];
4349           return;
4350         }
4351     }
4352 #endif
4354   if (type == NSApplicationDefined)
4355     {
4356       /* Events posted by ns_send_appdefined interrupt the run loop here.
4357          But, if a modal window is up, an appdefined can still come through,
4358          (e.g., from a makeKeyWindow event) but stopping self also stops the
4359          modal loop. Just defer it until later. */
4360       if ([NSApp modalWindow] == nil)
4361         {
4362           last_appdefined_event = theEvent;
4363           [self stop: self];
4364         }
4365       else
4366         {
4367           send_appdefined = YES;
4368         }
4369     }
4371   [super sendEvent: theEvent];
4375 - (void)showPreferencesWindow: (id)sender
4377   struct frame *emacsframe = SELECTED_FRAME ();
4378   NSEvent *theEvent = [NSApp currentEvent];
4380   if (!emacs_event)
4381     return;
4382   emacs_event->kind = NS_NONKEY_EVENT;
4383   emacs_event->code = KEY_NS_SHOW_PREFS;
4384   emacs_event->modifiers = 0;
4385   EV_TRAILER (theEvent);
4389 - (void)newFrame: (id)sender
4391   struct frame *emacsframe = SELECTED_FRAME ();
4392   NSEvent *theEvent = [NSApp currentEvent];
4394   if (!emacs_event)
4395     return;
4396   emacs_event->kind = NS_NONKEY_EVENT;
4397   emacs_event->code = KEY_NS_NEW_FRAME;
4398   emacs_event->modifiers = 0;
4399   EV_TRAILER (theEvent);
4403 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4404 - (BOOL) openFile: (NSString *)fileName
4406   struct frame *emacsframe = SELECTED_FRAME ();
4407   NSEvent *theEvent = [NSApp currentEvent];
4409   if (!emacs_event)
4410     return NO;
4412   emacs_event->kind = NS_NONKEY_EVENT;
4413   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4414   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4415   ns_input_line = Qnil; /* can be start or cons start,end */
4416   emacs_event->modifiers =0;
4417   EV_TRAILER (theEvent);
4419   return YES;
4423 /* **************************************************************************
4425       EmacsApp delegate implementation
4427    ************************************************************************** */
4429 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4430 /* --------------------------------------------------------------------------
4431      When application is loaded, terminate event loop in ns_term_init
4432    -------------------------------------------------------------------------- */
4434   NSTRACE (applicationDidFinishLaunching);
4435   [NSApp setServicesProvider: NSApp];
4436   ns_send_appdefined (-2);
4440 /* Termination sequences:
4441     C-x C-c:
4442     Cmd-Q:
4443     MenuBar | File | Exit:
4444     Select Quit from App menubar:
4445         -terminate
4446         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4447         ns_term_shutdown()
4449     Select Quit from Dock menu:
4450     Logout attempt:
4451         -appShouldTerminate
4452           Cancel -> Nothing else
4453           Accept ->
4455           -terminate
4456           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4457           ns_term_shutdown()
4461 - (void) terminate: (id)sender
4463   struct frame *emacsframe = SELECTED_FRAME ();
4465   if (!emacs_event)
4466     return;
4468   emacs_event->kind = NS_NONKEY_EVENT;
4469   emacs_event->code = KEY_NS_POWER_OFF;
4470   emacs_event->arg = Qt; /* mark as non-key event */
4471   EV_TRAILER ((id)nil);
4475 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4477   int ret;
4479   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4480     return NSTerminateNow;
4482     ret = NSRunAlertPanel(ns_app_name,
4483                           @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
4484                           @"Save Buffers and Exit", @"Cancel", nil);
4486     if (ret == NSAlertDefaultReturn)
4487         return NSTerminateNow;
4488     else if (ret == NSAlertAlternateReturn)
4489         return NSTerminateCancel;
4490     return NSTerminateNow;  /* just in case */
4493 static int
4494 not_in_argv (NSString *arg)
4496   int k;
4497   const char *a = [arg UTF8String];
4498   for (k = 1; k < initial_argc; ++k)
4499     if (strcmp (a, initial_argv[k]) == 0) return 0;
4500   return 1;
4503 /*   Notification from the Workspace to open a file */
4504 - (BOOL)application: sender openFile: (NSString *)file
4506   if (ns_do_open_file || not_in_argv (file))
4507     [ns_pending_files addObject: file];
4508   return YES;
4512 /*   Open a file as a temporary file */
4513 - (BOOL)application: sender openTempFile: (NSString *)file
4515   if (ns_do_open_file || not_in_argv (file))
4516     [ns_pending_files addObject: file];
4517   return YES;
4521 /*   Notification from the Workspace to open a file noninteractively (?) */
4522 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4524   if (ns_do_open_file || not_in_argv (file))
4525     [ns_pending_files addObject: file];
4526   return YES;
4529 /*   Notification from the Workspace to open multiple files */
4530 - (void)application: sender openFiles: (NSArray *)fileList
4532   NSEnumerator *files = [fileList objectEnumerator];
4533   NSString *file;
4534   /* Don't open files from the command line unconditionally,
4535      Cocoa parses the command line wrong, --option value tries to open value
4536      if --option is the last option.  */
4537   while ((file = [files nextObject]) != nil) 
4538     if (ns_do_open_file || not_in_argv (file))
4539       [ns_pending_files addObject: file];
4540   
4541   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4546 /* Handle dock menu requests.  */
4547 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4549   return dockMenu;
4553 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4554 - (void)applicationWillBecomeActive: (NSNotification *)notification
4556   //ns_app_active=YES;
4558 - (void)applicationDidBecomeActive: (NSNotification *)notification
4560   NSTRACE (applicationDidBecomeActive);
4562   //ns_app_active=YES;
4564   ns_update_auto_hide_menu_bar ();
4565   // No constraining takes place when the application is not active.
4566   ns_constrain_all_frames ();
4568 - (void)applicationDidResignActive: (NSNotification *)notification
4570   //ns_app_active=NO;
4571   ns_send_appdefined (-1);
4576 /* ==========================================================================
4578     EmacsApp aux handlers for managing event loop
4580    ========================================================================== */
4583 - (void)timeout_handler: (NSTimer *)timedEntry
4584 /* --------------------------------------------------------------------------
4585      The timeout specified to ns_select has passed.
4586    -------------------------------------------------------------------------- */
4588   /*NSTRACE (timeout_handler); */
4589   ns_send_appdefined (-2);
4592 - (void)fd_handler:(id)unused
4593 /* --------------------------------------------------------------------------
4594      Check data waiting on file descriptors and terminate if so
4595    -------------------------------------------------------------------------- */
4597   int result;
4598   int waiting = 1, nfds;
4599   char c;
4601   SELECT_TYPE readfds, writefds, *wfds;
4602   EMACS_TIME timeout, *tmo;
4604   /* NSTRACE (fd_handler); */
4606   for (;;) 
4607     {
4608       if (waiting)
4609         {
4610           SELECT_TYPE fds;
4612           FD_SET (selfds[0], &fds);
4613           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
4614           if (result > 0)
4615             {
4616               read (selfds[0], &c, 1);
4617               if (c == 'g') waiting = 0;
4618             }
4619         }
4620       else
4621         {
4622           pthread_mutex_lock (&select_mutex);
4623           nfds = select_nfds;
4625           if (select_valid & SELECT_HAVE_READ)
4626             readfds = select_readfds;
4627           else
4628             FD_ZERO (&readfds);
4630           if (select_valid & SELECT_HAVE_WRITE)
4631             {
4632               writefds = select_writefds;
4633               wfds = &writefds;
4634             }
4635           else
4636             wfds = NULL;
4637           if (select_valid & SELECT_HAVE_TMO)
4638             {
4639               timeout = select_timeout;
4640               tmo = &timeout;
4641             }
4642           else
4643             tmo = NULL;
4645           pthread_mutex_unlock (&select_mutex);
4647           FD_SET (selfds[0], &readfds);
4648           if (selfds[0] >= nfds) nfds = selfds[0]+1;
4650           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
4652           if (result == 0)
4653             ns_send_appdefined (-2);
4654           else if (result > 0)
4655             {
4656               if (FD_ISSET (selfds[0], &readfds))
4657                 {
4658                   read (selfds[0], &c, 1);
4659                   if (c == 's') waiting = 1;
4660                 }
4661               else
4662                 {
4663                   pthread_mutex_lock (&select_mutex);
4664                   if (select_valid & SELECT_HAVE_READ)
4665                     select_readfds = readfds;
4666                   if (select_valid & SELECT_HAVE_WRITE)
4667                     select_writefds = writefds;
4668                   if (select_valid & SELECT_HAVE_TMO)
4669                     select_timeout = timeout;
4670                   pthread_mutex_unlock (&select_mutex);
4672                   ns_send_appdefined (result);
4673                 }
4674             }
4675           waiting = 1;
4676         }
4677     }
4682 /* ==========================================================================
4684     Service provision
4686    ========================================================================== */
4688 /* called from system: queue for next pass through event loop */
4689 - (void)requestService: (NSPasteboard *)pboard
4690               userData: (NSString *)userData
4691                  error: (NSString **)error
4693   [ns_pending_service_names addObject: userData];
4694   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4695       SSDATA (ns_string_from_pasteboard (pboard))]];
4699 /* called from ns_read_socket to clear queue */
4700 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4702   struct frame *emacsframe = SELECTED_FRAME ();
4703   NSEvent *theEvent = [NSApp currentEvent];
4705   if (!emacs_event)
4706     return NO;
4708   emacs_event->kind = NS_NONKEY_EVENT;
4709   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4710   ns_input_spi_name = build_string ([name UTF8String]);
4711   ns_input_spi_arg = build_string ([arg UTF8String]);
4712   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4713   EV_TRAILER (theEvent);
4715   return YES;
4719 @end  /* EmacsApp */
4723 /* ==========================================================================
4725     EmacsView implementation
4727    ========================================================================== */
4730 @implementation EmacsView
4732 /* needed to inform when window closed from LISP */
4733 - (void) setWindowClosing: (BOOL)closing
4735   windowClosing = closing;
4739 - (void)dealloc
4741   NSTRACE (EmacsView_dealloc);
4742   [toolbar release];
4743   [super dealloc];
4747 /* called on font panel selection */
4748 - (void)changeFont: (id)sender
4750   NSEvent *e =[[self window] currentEvent];
4751   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4752   id newFont;
4753   float size;
4755   NSTRACE (changeFont);
4756   if (!emacs_event)
4757     return;
4759   if ((newFont = [sender convertFont:
4760                            ((struct nsfont_info *)face->font)->nsfont]))
4761     {
4762       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4764       emacs_event->kind = NS_NONKEY_EVENT;
4765       emacs_event->modifiers = 0;
4766       emacs_event->code = KEY_NS_CHANGE_FONT;
4768       size = [newFont pointSize];
4769       ns_input_fontsize = make_number (lrint (size));
4770       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4771       EV_TRAILER (e);
4772     }
4776 - (BOOL)acceptsFirstResponder
4778   NSTRACE (acceptsFirstResponder);
4779   return YES;
4783 - (void)resetCursorRects
4785   NSRect visible = [self visibleRect];
4786   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4787   NSTRACE (resetCursorRects);
4789   if (currentCursor == nil)
4790     currentCursor = [NSCursor arrowCursor];
4792   if (!NSIsEmptyRect (visible))
4793     [self addCursorRect: visible cursor: currentCursor];
4794   [currentCursor setOnMouseEntered: YES];
4799 /*****************************************************************************/
4800 /* Keyboard handling. */
4801 #define NS_KEYLOG 0
4803 - (void)keyDown: (NSEvent *)theEvent
4805   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4806   int code;
4807   unsigned fnKeysym = 0;
4808   int flags;
4809   static NSMutableArray *nsEvArray;
4810 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4811   static BOOL firstTime = YES;
4812 #endif
4813   int left_is_none;
4815   NSTRACE (keyDown);
4817   /* Rhapsody and OS X give up and down events for the arrow keys */
4818   if (ns_fake_keydown == YES)
4819     ns_fake_keydown = NO;
4820   else if ([theEvent type] != NSKeyDown)
4821     return;
4823   if (!emacs_event)
4824     return;
4826  if (![[self window] isKeyWindow]
4827      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4828      /* we must avoid an infinite loop here. */
4829      && (EmacsView *)[[theEvent window] delegate] != self)
4830    {
4831      /* XXX: There is an occasional condition in which, when Emacs display
4832          updates a different frame from the current one, and temporarily
4833          selects it, then processes some interrupt-driven input
4834          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4835          for some reason that window has its first responder set to the NSView
4836          most recently updated (I guess), which is not the correct one. */
4837      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4838      return;
4839    }
4841   if (nsEvArray == nil)
4842     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4844   [NSCursor setHiddenUntilMouseMoves: YES];
4846   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4847     {
4848       clear_mouse_face (hlinfo);
4849       hlinfo->mouse_face_hidden = 1;
4850     }
4852   if (!processingCompose)
4853     {
4854       /* When using screen sharing, no left or right information is sent,
4855          so use Left key in those cases.  */
4856       int is_left_key, is_right_key;
4858       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4859         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4861       /* (Carbon way: [theEvent keyCode]) */
4863       /* is it a "function key"? */
4864       fnKeysym = ns_convert_key (code);
4865       if (fnKeysym)
4866         {
4867           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4868              because Emacs treats Delete and KP-Delete same (in simple.el). */
4869           if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4870             code = 0xFF08; /* backspace */
4871           else
4872             code = fnKeysym;
4873         }
4875       /* are there modifiers? */
4876       emacs_event->modifiers = 0;
4877       flags = [theEvent modifierFlags];
4879       if (flags & NSHelpKeyMask)
4880           emacs_event->modifiers |= hyper_modifier;
4882       if (flags & NSShiftKeyMask)
4883         emacs_event->modifiers |= shift_modifier;
4885       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
4886       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
4887         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
4888       
4889       if (is_right_key)
4890         emacs_event->modifiers |= parse_solitary_modifier
4891           (EQ (ns_right_command_modifier, Qleft)
4892            ? ns_command_modifier
4893            : ns_right_command_modifier);
4895       if (is_left_key)
4896         {
4897           emacs_event->modifiers |= parse_solitary_modifier
4898             (ns_command_modifier);
4900           /* if super (default), take input manager's word so things like
4901              dvorak / qwerty layout work */
4902           if (EQ (ns_command_modifier, Qsuper)
4903               && !fnKeysym
4904               && [[theEvent characters] length] != 0)
4905             {
4906               /* XXX: the code we get will be unshifted, so if we have
4907                  a shift modifier, must convert ourselves */
4908               if (!(flags & NSShiftKeyMask))
4909                 code = [[theEvent characters] characterAtIndex: 0];
4910 #if 0
4911               /* this is ugly and also requires linking w/Carbon framework
4912                  (for LMGetKbdType) so for now leave this rare (?) case
4913                  undealt with.. in future look into CGEvent methods */
4914               else
4915                 {
4916                   long smv = GetScriptManagerVariable (smKeyScript);
4917                   Handle uchrHandle = GetResource
4918                     ('uchr', GetScriptVariable (smv, smScriptKeys));
4919                   UInt32 dummy = 0;
4920                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
4921                                  [[theEvent characters] characterAtIndex: 0],
4922                                  kUCKeyActionDisplay,
4923                                  (flags & ~NSCommandKeyMask) >> 8,
4924                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
4925                                  &dummy, 1, &dummy, &code);
4926                   code &= 0xFF;
4927                 }
4928 #endif
4929             }
4930         }
4932       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
4933       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
4934         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
4936       if (is_right_key)
4937           emacs_event->modifiers |= parse_solitary_modifier
4938               (EQ (ns_right_control_modifier, Qleft)
4939                ? ns_control_modifier
4940                : ns_right_control_modifier);
4942       if (is_left_key)
4943         emacs_event->modifiers |= parse_solitary_modifier
4944           (ns_control_modifier);
4946       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
4947           emacs_event->modifiers |=
4948             parse_solitary_modifier (ns_function_modifier);
4950       left_is_none = NILP (ns_alternate_modifier)
4951         || EQ (ns_alternate_modifier, Qnone);
4953       is_right_key = (flags & NSRightAlternateKeyMask)
4954         == NSRightAlternateKeyMask;
4955       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
4956         || (! is_right_key
4957             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
4959       if (is_right_key)
4960         {
4961           if ((NILP (ns_right_alternate_modifier)
4962                || EQ (ns_right_alternate_modifier, Qnone)
4963                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
4964               && !fnKeysym)
4965             {   /* accept pre-interp alt comb */
4966               if ([[theEvent characters] length] > 0)
4967                 code = [[theEvent characters] characterAtIndex: 0];
4968               /*HACK: clear lone shift modifier to stop next if from firing */
4969               if (emacs_event->modifiers == shift_modifier)
4970                 emacs_event->modifiers = 0;
4971             }
4972           else
4973             emacs_event->modifiers |= parse_solitary_modifier
4974               (EQ (ns_right_alternate_modifier, Qleft)
4975                ? ns_alternate_modifier
4976                : ns_right_alternate_modifier);
4977         }
4979       if (is_left_key) /* default = meta */
4980         {
4981           if (left_is_none && !fnKeysym)
4982             {   /* accept pre-interp alt comb */
4983               if ([[theEvent characters] length] > 0)
4984                 code = [[theEvent characters] characterAtIndex: 0];
4985               /*HACK: clear lone shift modifier to stop next if from firing */
4986               if (emacs_event->modifiers == shift_modifier)
4987                 emacs_event->modifiers = 0;
4988             }
4989           else
4990               emacs_event->modifiers |=
4991                 parse_solitary_modifier (ns_alternate_modifier);
4992         }
4994   if (NS_KEYLOG)
4995     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
4996              code, fnKeysym, flags, emacs_event->modifiers);
4998       /* if it was a function key or had modifiers, pass it directly to emacs */
4999       if (fnKeysym || (emacs_event->modifiers
5000                        && (emacs_event->modifiers != shift_modifier)
5001                        && [[theEvent charactersIgnoringModifiers] length] > 0))
5002 /*[[theEvent characters] length] */
5003         {
5004           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5005           if (code < 0x20)
5006             code |= (1<<28)|(3<<16);
5007           else if (code == 0x7f)
5008             code |= (1<<28)|(3<<16);
5009           else if (!fnKeysym)
5010             emacs_event->kind = code > 0xFF
5011               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5013           emacs_event->code = code;
5014           EV_TRAILER (theEvent);
5015           return;
5016         }
5017     }
5020 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
5021   /* if we get here we should send the key for input manager processing */
5022   if (firstTime && [[NSInputManager currentInputManager]
5023                      wantsToDelayTextChangeNotifications] == NO)
5024     fprintf (stderr,
5025           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
5026   firstTime = NO;
5027 #endif
5028   if (NS_KEYLOG && !processingCompose)
5029     fprintf (stderr, "keyDown: Begin compose sequence.\n");
5031   processingCompose = YES;
5032   [nsEvArray addObject: theEvent];
5033   [self interpretKeyEvents: nsEvArray];
5034   [nsEvArray removeObject: theEvent];
5038 #ifdef NS_IMPL_COCOA
5039 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5040    decided not to send key-down for.
5041    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5042    This only applies on Tiger and earlier.
5043    If it matches one of these, send it on to keyDown. */
5044 -(void)keyUp: (NSEvent *)theEvent
5046   int flags = [theEvent modifierFlags];
5047   int code = [theEvent keyCode];
5048   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5049       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5050     {
5051       if (NS_KEYLOG)
5052         fprintf (stderr, "keyUp: passed test");
5053       ns_fake_keydown = YES;
5054       [self keyDown: theEvent];
5055     }
5057 #endif
5060 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5063 /* <NSTextInput>: called when done composing;
5064    NOTE: also called when we delete over working text, followed immed.
5065          by doCommandBySelector: deleteBackward: */
5066 - (void)insertText: (id)aString
5068   int code;
5069   int len = [(NSString *)aString length];
5070   int i;
5072   if (NS_KEYLOG)
5073     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5074   processingCompose = NO;
5076   if (!emacs_event)
5077     return;
5079   /* first, clear any working text */
5080   if (workingText != nil)
5081     [self deleteWorkingText];
5083   /* now insert the string as keystrokes */
5084   for (i =0; i<len; i++)
5085     {
5086       code = [aString characterAtIndex: i];
5087       /* TODO: still need this? */
5088       if (code == 0x2DC)
5089         code = '~'; /* 0x7E */
5090       emacs_event->modifiers = 0;
5091       emacs_event->kind
5092         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5093       emacs_event->code = code;
5094       EV_TRAILER ((id)nil);
5095     }
5099 /* <NSTextInput>: inserts display of composing characters */
5100 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5102   NSString *str = [aString respondsToSelector: @selector (string)] ?
5103     [aString string] : aString;
5104   if (NS_KEYLOG)
5105     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
5106            selRange.length, selRange.location);
5108   if (workingText != nil)
5109     [self deleteWorkingText];
5110   if ([str length] == 0)
5111     return;
5113   if (!emacs_event)
5114     return;
5116   processingCompose = YES;
5117   workingText = [str copy];
5118   ns_working_text = build_string ([workingText UTF8String]);
5120   emacs_event->kind = NS_TEXT_EVENT;
5121   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5122   EV_TRAILER ((id)nil);
5126 /* delete display of composing characters [not in <NSTextInput>] */
5127 - (void)deleteWorkingText
5129   if (workingText == nil)
5130     return;
5131   if (NS_KEYLOG)
5132     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
5133   [workingText release];
5134   workingText = nil;
5135   processingCompose = NO;
5137   if (!emacs_event)
5138     return;
5140   emacs_event->kind = NS_TEXT_EVENT;
5141   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5142   EV_TRAILER ((id)nil);
5146 - (BOOL)hasMarkedText
5148   return workingText != nil;
5152 - (NSRange)markedRange
5154   NSRange rng = workingText != nil
5155     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5156   if (NS_KEYLOG)
5157     NSLog (@"markedRange request");
5158   return rng;
5162 - (void)unmarkText
5164   if (NS_KEYLOG)
5165     NSLog (@"unmark (accept) text");
5166   [self deleteWorkingText];
5167   processingCompose = NO;
5171 /* used to position char selection windows, etc. */
5172 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5174   NSRect rect;
5175   NSPoint pt;
5176   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5177   if (NS_KEYLOG)
5178     NSLog (@"firstRectForCharRange request");
5180   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5181   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5182   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5183   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5184                                        +FRAME_LINE_HEIGHT (emacsframe));
5186   pt = [self convertPoint: pt toView: nil];
5187   pt = [[self window] convertBaseToScreen: pt];
5188   rect.origin = pt;
5189   return rect;
5193 - (NSInteger)conversationIdentifier
5195   return (NSInteger)self;
5199 - (void)doCommandBySelector: (SEL)aSelector
5201   if (NS_KEYLOG)
5202     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5204   if (aSelector == @selector (deleteBackward:))
5205     {
5206       /* happens when user backspaces over an ongoing composition:
5207          throw a 'delete' into the event queue */
5208       if (!emacs_event)
5209         return;
5210       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5211       emacs_event->code = 0xFF08;
5212       EV_TRAILER ((id)nil);
5213     }
5216 - (NSArray *)validAttributesForMarkedText
5218   static NSArray *arr = nil;
5219   if (arr == nil) arr = [NSArray new];
5220  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5221   return arr;
5224 - (NSRange)selectedRange
5226   if (NS_KEYLOG)
5227     NSLog (@"selectedRange request");
5228   return NSMakeRange (NSNotFound, 0);
5231 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5233   if (NS_KEYLOG)
5234     NSLog (@"characterIndexForPoint request");
5235   return 0;
5238 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5240   static NSAttributedString *str = nil;
5241   if (str == nil) str = [NSAttributedString new];
5242   if (NS_KEYLOG)
5243     NSLog (@"attributedSubstringFromRange request");
5244   return str;
5247 /* End <NSTextInput> impl. */
5248 /*****************************************************************************/
5251 /* This is what happens when the user presses a mouse button.  */
5252 - (void)mouseDown: (NSEvent *)theEvent
5254   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5256   NSTRACE (mouseDown);
5258   [self deleteWorkingText];
5260   if (!emacs_event)
5261     return;
5263   last_mouse_frame = emacsframe;
5264   /* appears to be needed to prevent spurious movement events generated on
5265      button clicks */
5266   last_mouse_frame->mouse_moved = 0;
5268   if ([theEvent type] == NSScrollWheel)
5269     {
5270       float delta = [theEvent deltaY];
5271       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5272       if (delta == 0)
5273         return;
5274       emacs_event->kind = WHEEL_EVENT;
5275       emacs_event->code = 0;
5276       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5277         ((delta > 0) ? up_modifier : down_modifier);
5278     }
5279   else
5280     {
5281       emacs_event->kind = MOUSE_CLICK_EVENT;
5282       emacs_event->code = EV_BUTTON (theEvent);
5283       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5284                              | EV_UDMODIFIERS (theEvent);
5285     }
5286   XSETINT (emacs_event->x, lrint (p.x));
5287   XSETINT (emacs_event->y, lrint (p.y));
5288   EV_TRAILER (theEvent);
5292 - (void)rightMouseDown: (NSEvent *)theEvent
5294   NSTRACE (rightMouseDown);
5295   [self mouseDown: theEvent];
5299 - (void)otherMouseDown: (NSEvent *)theEvent
5301   NSTRACE (otherMouseDown);
5302   [self mouseDown: theEvent];
5306 - (void)mouseUp: (NSEvent *)theEvent
5308   NSTRACE (mouseUp);
5309   [self mouseDown: theEvent];
5313 - (void)rightMouseUp: (NSEvent *)theEvent
5315   NSTRACE (rightMouseUp);
5316   [self mouseDown: theEvent];
5320 - (void)otherMouseUp: (NSEvent *)theEvent
5322   NSTRACE (otherMouseUp);
5323   [self mouseDown: theEvent];
5327 - (void) scrollWheel: (NSEvent *)theEvent
5329   NSTRACE (scrollWheel);
5330   [self mouseDown: theEvent];
5334 /* Tell emacs the mouse has moved. */
5335 - (void)mouseMoved: (NSEvent *)e
5337   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5338   Lisp_Object frame;
5340 //  NSTRACE (mouseMoved);
5342   last_mouse_movement_time = EV_TIMESTAMP (e);
5343   last_mouse_motion_position
5344     = [self convertPoint: [e locationInWindow] fromView: nil];
5346   /* update any mouse face */
5347   if (hlinfo->mouse_face_hidden)
5348     {
5349       hlinfo->mouse_face_hidden = 0;
5350       clear_mouse_face (hlinfo);
5351     }
5353   /* tooltip handling */
5354   previous_help_echo_string = help_echo_string;
5355   help_echo_string = Qnil;
5357   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
5358                             last_mouse_motion_position.y))
5359     help_echo_string = previous_help_echo_string;
5361   XSETFRAME (frame, emacsframe);
5362   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5363     {
5364       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5365          (note_mouse_highlight), which is called through the
5366          note_mouse_movement () call above */
5367       gen_help_event (help_echo_string, frame, help_echo_window,
5368                       help_echo_object, help_echo_pos);
5369     }
5370   else
5371     {
5372       help_echo_string = Qnil;
5373       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5374     }
5376   if (emacsframe->mouse_moved && send_appdefined)
5377     ns_send_appdefined (-1);
5381 - (void)mouseDragged: (NSEvent *)e
5383   NSTRACE (mouseDragged);
5384   [self mouseMoved: e];
5388 - (void)rightMouseDragged: (NSEvent *)e
5390   NSTRACE (rightMouseDragged);
5391   [self mouseMoved: e];
5395 - (void)otherMouseDragged: (NSEvent *)e
5397   NSTRACE (otherMouseDragged);
5398   [self mouseMoved: e];
5402 - (BOOL)windowShouldClose: (id)sender
5404   NSEvent *e =[[self window] currentEvent];
5406   NSTRACE (windowShouldClose);
5407   windowClosing = YES;
5408   if (!emacs_event)
5409     return NO;
5410   emacs_event->kind = DELETE_WINDOW_EVENT;
5411   emacs_event->modifiers = 0;
5412   emacs_event->code = 0;
5413   EV_TRAILER (e);
5414   /* Don't close this window, let this be done from lisp code.  */
5415   return NO;
5419 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5420 /* normalize frame to gridded text size */
5422   NSTRACE (windowWillResize);
5423 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5425   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5426 #ifdef NS_IMPL_GNUSTEP
5427                                         frameSize.width + 3);
5428 #else
5429                                         frameSize.width);
5430 #endif
5431   if (cols < MINWIDTH)
5432     cols = MINWIDTH;
5434   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, frameSize.height
5435 #ifdef NS_IMPL_GNUSTEP
5436       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + 3
5437         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5438 #else
5439       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5440         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5441 #endif
5442   if (rows < MINHEIGHT)
5443     rows = MINHEIGHT;
5444 #ifdef NS_IMPL_COCOA
5445   {
5446     /* this sets window title to have size in it; the wm does this under GS */
5447     NSRect r = [[self window] frame];
5448     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5449       {
5450         if (old_title != 0)
5451           {
5452             xfree (old_title);
5453             old_title = 0;
5454           }
5455       }
5456     else
5457       {
5458         char *size_title;
5459         NSWindow *window = [self window];
5460         if (old_title == 0)
5461           {
5462             const char *t = [[[self window] title] UTF8String];
5463             char *pos = strstr (t, "  â€”  ");
5464             if (pos)
5465               *pos = '\0';
5466             old_title = xstrdup (t);
5467           }
5468         size_title = xmalloc (strlen (old_title) + 40);
5469         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5470         [window setTitle: [NSString stringWithUTF8String: size_title]];
5471         [window display];
5472         xfree (size_title);
5473       }
5474   }
5475 #endif /* NS_IMPL_COCOA */
5476 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5478   return frameSize;
5482 - (void)windowDidResize: (NSNotification *)notification
5484 #ifdef NS_IMPL_GNUSTEP
5485   NSWindow *theWindow = [notification object];
5487    /* in GNUstep, at least currently, it's possible to get a didResize
5488       without getting a willResize.. therefore we need to act as if we got
5489       the willResize now */
5490   NSSize sz = [theWindow frame].size;
5491   sz = [self windowWillResize: theWindow toSize: sz];
5492 #endif /* NS_IMPL_GNUSTEP */
5494   NSTRACE (windowDidResize);
5495 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5497 #ifdef NS_IMPL_COCOA
5498   if (old_title != 0)
5499     {
5500       xfree (old_title);
5501       old_title = 0;
5502     }
5503 #endif /* NS_IMPL_COCOA */
5505   /* Avoid loop under GNUstep due to call at beginning of this function.
5506      (x_set_window_size causes a resize which causes
5507      a "windowDidResize" which calls x_set_window_size).  */
5508 #ifndef NS_IMPL_GNUSTEP
5509   if (cols > 0 && rows > 0)
5510     {
5511       if (ns_in_resize)
5512         x_set_window_size (emacsframe, 0, cols, rows);
5513       else
5514         {
5515           NSWindow *window = [self window];
5516           NSRect wr = [window frame];
5517           FRAME_PIXEL_WIDTH (emacsframe) = (int)wr.size.width
5518             - emacsframe->border_width;
5519           FRAME_PIXEL_HEIGHT (emacsframe) = (int)wr.size.height
5520             - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5521             - FRAME_TOOLBAR_HEIGHT (emacsframe);
5522           change_frame_size (emacsframe, rows, cols, 0, 0, 1);
5523           SET_FRAME_GARBAGED (emacsframe);
5524           cancel_mouse_face (emacsframe);
5525         }
5526     }
5527 #endif
5529   ns_send_appdefined (-1);
5533 - (void)windowDidBecomeKey: (NSNotification *)notification
5534 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5536   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5537   struct frame *old_focus = dpyinfo->x_focus_frame;
5539   NSTRACE (windowDidBecomeKey);
5541   if (emacsframe != old_focus)
5542     dpyinfo->x_focus_frame = emacsframe;
5544   ns_frame_rehighlight (emacsframe);
5546   if (emacs_event)
5547     {
5548       emacs_event->kind = FOCUS_IN_EVENT;
5549       EV_TRAILER ((id)nil);
5550     }
5554 - (void)windowDidResignKey: (NSNotification *)notification
5555 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5557   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5558   NSTRACE (windowDidResignKey);
5560   if (dpyinfo->x_focus_frame == emacsframe)
5561     dpyinfo->x_focus_frame = 0;
5563   ns_frame_rehighlight (emacsframe);
5565   /* FIXME: for some reason needed on second and subsequent clicks away
5566             from sole-frame Emacs to get hollow box to show */
5567   if (!windowClosing && [[self window] isVisible] == YES)
5568     {
5569       x_update_cursor (emacsframe, 1);
5570       x_set_frame_alpha (emacsframe);
5571     }
5573   if (emacs_event)
5574     {
5575       [self deleteWorkingText];
5576       emacs_event->kind = FOCUS_IN_EVENT;
5577       EV_TRAILER ((id)nil);
5578     }
5582 - (void)windowWillMiniaturize: sender
5584   NSTRACE (windowWillMiniaturize);
5588 - (BOOL)isFlipped
5590   return YES;
5594 - (BOOL)isOpaque
5596   return NO;
5600 - initFrameFromEmacs: (struct frame *)f
5602   NSRect r, wr;
5603   Lisp_Object tem;
5604   NSWindow *win;
5605   NSButton *toggleButton;
5606   NSSize sz;
5607   NSColor *col;
5608   NSString *name;
5610   NSTRACE (initFrameFromEmacs);
5612   windowClosing = NO;
5613   processingCompose = NO;
5614   scrollbarsNeedingUpdate = 0;
5616 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5618   ns_userRect = NSMakeRect (0, 0, 0, 0);
5619   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5620                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5621   [self initWithFrame: r];
5622   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5624   FRAME_NS_VIEW (f) = self;
5625   emacsframe = f;
5626   old_title = 0;
5628   win = [[EmacsWindow alloc]
5629             initWithContentRect: r
5630                       styleMask: (NSResizableWindowMask |
5631 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5632                                   NSTitledWindowMask |
5633 #endif
5634                                   NSMiniaturizableWindowMask |
5635                                   NSClosableWindowMask)
5636                         backing: NSBackingStoreBuffered
5637                           defer: YES];
5639   wr = [win frame];
5640   f->border_width = wr.size.width - r.size.width;
5641   FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5643   [win setAcceptsMouseMovedEvents: YES];
5644   [win setDelegate: self];
5645   [win useOptimizedDrawing: YES];
5647   sz.width = FRAME_COLUMN_WIDTH (f);
5648   sz.height = FRAME_LINE_HEIGHT (f);
5649   [win setResizeIncrements: sz];
5651   [[win contentView] addSubview: self];
5653   if (ns_drag_types)
5654     [self registerForDraggedTypes: ns_drag_types];
5656   tem = f->name;
5657   name = [NSString stringWithUTF8String:
5658                    NILP (tem) ? "Emacs" : SSDATA (tem)];
5659   [win setTitle: name];
5661   /* toolbar support */
5662   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5663                          [NSString stringWithFormat: @"Emacs Frame %d",
5664                                    ns_window_num]];
5665   [win setToolbar: toolbar];
5666   [toolbar setVisible: NO];
5667 #ifdef NS_IMPL_COCOA
5668   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5669   [toggleButton setTarget: self];
5670   [toggleButton setAction: @selector (toggleToolbar: )];
5671 #endif
5672   FRAME_TOOLBAR_HEIGHT (f) = 0;
5674   tem = f->icon_name;
5675   if (!NILP (tem))
5676     [win setMiniwindowTitle:
5677            [NSString stringWithUTF8String: SSDATA (tem)]];
5679   {
5680     NSScreen *screen = [win screen];
5682     if (screen != 0)
5683       [win setFrameTopLeftPoint: NSMakePoint
5684            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5685             IN_BOUND (-SCREENMAX,
5686                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5687   }
5689   [win makeFirstResponder: self];
5691   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5692                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5693   [win setBackgroundColor: col];
5694   if ([col alphaComponent] != 1.0)
5695     [win setOpaque: NO];
5697   [self allocateGState];
5699   [NSApp registerServicesMenuSendTypes: ns_send_types
5700                            returnTypes: nil];
5702   ns_window_num++;
5703   return self;
5707 - (void)windowDidMove: sender
5709   NSWindow *win = [self window];
5710   NSRect r = [win frame];
5711   NSArray *screens = [NSScreen screens];
5712   NSScreen *screen = [screens objectAtIndex: 0];
5714   NSTRACE (windowDidMove);
5716   if (!emacsframe->output_data.ns)
5717     return;
5718   if (screen != nil)
5719     {
5720       emacsframe->left_pos = r.origin.x;
5721       emacsframe->top_pos =
5722         [screen frame].size.height - (r.origin.y + r.size.height);
5723     }
5727 /* Called AFTER method below, but before our windowWillResize call there leads
5728    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5729    location so set_window_size moves the frame. */
5730 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5732   emacsframe->output_data.ns->zooming = 1;
5733   return YES;
5737 /* Override to do something slightly nonstandard, but nice.  First click on
5738    zoom button will zoom vertically.  Second will zoom completely.  Third
5739    returns to original. */
5740 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5741                         defaultFrame:(NSRect)defaultFrame
5743   NSRect result = [sender frame];
5745   NSTRACE (windowWillUseStandardFrame);
5747   if (abs (defaultFrame.size.height - result.size.height)
5748       > FRAME_LINE_HEIGHT (emacsframe))
5749     {
5750       /* first click */
5751       ns_userRect = result;
5752       result.size.height = defaultFrame.size.height;
5753       result.origin.y = defaultFrame.origin.y;
5754     }
5755   else
5756     {
5757       if (abs (defaultFrame.size.width - result.size.width)
5758           > FRAME_COLUMN_WIDTH (emacsframe))
5759         result = defaultFrame;  /* second click */
5760       else
5761         {
5762           /* restore */
5763           result = ns_userRect.size.height ? ns_userRect : result;
5764           ns_userRect = NSMakeRect (0, 0, 0, 0);
5765         }
5766     }
5768   [self windowWillResize: sender toSize: result.size];
5769   return result;
5773 - (void)windowDidDeminiaturize: sender
5775   NSTRACE (windowDidDeminiaturize);
5776   if (!emacsframe->output_data.ns)
5777     return;
5778   emacsframe->async_iconified = 0;
5779   emacsframe->async_visible   = 1;
5780   windows_or_buffers_changed++;
5782   if (emacs_event)
5783     {
5784       emacs_event->kind = ICONIFY_EVENT;
5785       EV_TRAILER ((id)nil);
5786     }
5790 - (void)windowDidExpose: sender
5792   NSTRACE (windowDidExpose);
5793   if (!emacsframe->output_data.ns)
5794     return;
5795   emacsframe->async_visible = 1;
5796   SET_FRAME_GARBAGED (emacsframe);
5798   if (send_appdefined)
5799     ns_send_appdefined (-1);
5803 - (void)windowDidMiniaturize: sender
5805   NSTRACE (windowDidMiniaturize);
5806   if (!emacsframe->output_data.ns)
5807     return;
5809   emacsframe->async_iconified = 1;
5810   emacsframe->async_visible = 0;
5812   if (emacs_event)
5813     {
5814       emacs_event->kind = ICONIFY_EVENT;
5815       EV_TRAILER ((id)nil);
5816     }
5820 - (void)mouseEntered: (NSEvent *)theEvent
5822   NSTRACE (mouseEntered);
5823   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5827 - (void)mouseExited: (NSEvent *)theEvent
5829   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
5831   NSTRACE (mouseExited);
5833   if (!hlinfo)
5834     return;
5836   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5838   if (emacsframe == hlinfo->mouse_face_mouse_frame)
5839     {
5840       clear_mouse_face (hlinfo);
5841       hlinfo->mouse_face_mouse_frame = 0;
5842     }
5846 - menuDown: sender
5848   NSTRACE (menuDown);
5849   if (context_menu_value == -1)
5850     context_menu_value = [sender tag];
5851   else 
5852     {
5853       NSInteger tag = [sender tag];
5854       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
5855                                     emacsframe->menu_bar_vector,
5856                                     (void *)tag);
5857     }
5859   ns_send_appdefined (-1);
5860   return self;
5864 - (EmacsToolbar *)toolbar
5866   return toolbar;
5870 /* this gets called on toolbar button click */
5871 - toolbarClicked: (id)item
5873   NSEvent *theEvent;
5874   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
5876   NSTRACE (toolbarClicked);
5878   if (!emacs_event)
5879     return self;
5881   /* send first event (for some reason two needed) */
5882   theEvent = [[self window] currentEvent];
5883   emacs_event->kind = TOOL_BAR_EVENT;
5884   XSETFRAME (emacs_event->arg, emacsframe);
5885   EV_TRAILER (theEvent);
5887   emacs_event->kind = TOOL_BAR_EVENT;
5888 /*   XSETINT (emacs_event->code, 0); */
5889   emacs_event->arg = AREF (emacsframe->tool_bar_items,
5890                            idx + TOOL_BAR_ITEM_KEY);
5891   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5892   EV_TRAILER (theEvent);
5893   return self;
5897 - toggleToolbar: (id)sender
5899   if (!emacs_event)
5900     return self;
5902   emacs_event->kind = NS_NONKEY_EVENT;
5903   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
5904   EV_TRAILER ((id)nil);
5905   return self;
5909 - (void)drawRect: (NSRect)rect
5911   int x = NSMinX (rect), y = NSMinY (rect);
5912   int width = NSWidth (rect), height = NSHeight (rect);
5914   NSTRACE (drawRect);
5916   if (!emacsframe || !emacsframe->output_data.ns || ns_in_resize)
5917     return;
5919   ns_clear_frame_area (emacsframe, x, y, width, height);
5920   expose_frame (emacsframe, x, y, width, height);
5922   /*
5923     drawRect: may be called (at least in OS X 10.5) for invisible
5924     views as well for some reason.  Thus, do not infer visibility
5925     here.
5927     emacsframe->async_visible = 1;
5928     emacsframe->async_iconified = 0;
5929   */
5933 /* NSDraggingDestination protocol methods.  Actually this is not really a
5934    protocol, but a category of Object.  O well...  */
5936 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
5938   NSTRACE (draggingEntered);
5939   return NSDragOperationGeneric;
5943 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
5945   return YES;
5949 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
5951   id pb;
5952   int x, y;
5953   NSString *type;
5954   NSEvent *theEvent = [[self window] currentEvent];
5955   NSPoint position;
5957   NSTRACE (performDragOperation);
5959   if (!emacs_event)
5960     return NO;
5962   position = [self convertPoint: [sender draggingLocation] fromView: nil];
5963   x = lrint (position.x);  y = lrint (position.y);
5965   pb = [sender draggingPasteboard];
5966   type = [pb availableTypeFromArray: ns_drag_types];
5967   if (type == 0)
5968     {
5969       return NO;
5970     }
5971   else if ([type isEqualToString: NSFilenamesPboardType])
5972     {
5973       NSArray *files;
5974       NSEnumerator *fenum;
5975       NSString *file;
5977       if (!(files = [pb propertyListForType: type]))
5978         return NO;
5980       fenum = [files objectEnumerator];
5981       while ( (file = [fenum nextObject]) )
5982         {
5983           emacs_event->kind = NS_NONKEY_EVENT;
5984           emacs_event->code = KEY_NS_DRAG_FILE;
5985           XSETINT (emacs_event->x, x);
5986           XSETINT (emacs_event->y, y);
5987           ns_input_file = append2 (ns_input_file,
5988                                    build_string ([file UTF8String]));
5989           emacs_event->modifiers = EV_MODIFIERS (theEvent);
5990           EV_TRAILER (theEvent);
5991         }
5992       return YES;
5993     }
5994   else if ([type isEqualToString: NSURLPboardType])
5995     {
5996       NSString *file;
5997       NSURL *fileURL;
5999       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
6000           [fileURL isFileURL] == NO)
6001         return NO;
6003       file = [fileURL path];
6004       emacs_event->kind = NS_NONKEY_EVENT;
6005       emacs_event->code = KEY_NS_DRAG_FILE;
6006       XSETINT (emacs_event->x, x);
6007       XSETINT (emacs_event->y, y);
6008       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
6009       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6010       EV_TRAILER (theEvent);
6011       return YES;
6012     }
6013   else if ([type isEqualToString: NSStringPboardType]
6014            || [type isEqualToString: NSTabularTextPboardType])
6015     {
6016       NSString *data;
6018       if (! (data = [pb stringForType: type]))
6019         return NO;
6021       emacs_event->kind = NS_NONKEY_EVENT;
6022       emacs_event->code = KEY_NS_DRAG_TEXT;
6023       XSETINT (emacs_event->x, x);
6024       XSETINT (emacs_event->y, y);
6025       ns_input_text = build_string ([data UTF8String]);
6026       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6027       EV_TRAILER (theEvent);
6028       return YES;
6029     }
6030   else if ([type isEqualToString: NSColorPboardType])
6031     {
6032       NSColor *c = [NSColor colorFromPasteboard: pb];
6033       emacs_event->kind = NS_NONKEY_EVENT;
6034       emacs_event->code = KEY_NS_DRAG_COLOR;
6035       XSETINT (emacs_event->x, x);
6036       XSETINT (emacs_event->y, y);
6037       ns_input_color = ns_color_to_lisp (c);
6038       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6039       EV_TRAILER (theEvent);
6040       return YES;
6041     }
6042   else if ([type isEqualToString: NSFontPboardType])
6043     {
6044       /* impl based on GNUstep NSTextView.m */
6045       NSData *data = [pb dataForType: NSFontPboardType];
6046       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
6047       NSFont *font = [dict objectForKey: NSFontAttributeName];
6048       char fontSize[10];
6050       if (font == nil)
6051         return NO;
6053       emacs_event->kind = NS_NONKEY_EVENT;
6054       emacs_event->code = KEY_NS_CHANGE_FONT;
6055       XSETINT (emacs_event->x, x);
6056       XSETINT (emacs_event->y, y);
6057       ns_input_font = build_string ([[font fontName] UTF8String]);
6058       snprintf (fontSize, 10, "%f", [font pointSize]);
6059       ns_input_fontsize = build_string (fontSize);
6060       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6061       EV_TRAILER (theEvent);
6062       return YES;
6063     }
6064   else
6065     {
6066       error ("Invalid data type in dragging pasteboard.");
6067       return NO;
6068     }
6072 - (id) validRequestorForSendType: (NSString *)typeSent
6073                       returnType: (NSString *)typeReturned
6075   NSTRACE (validRequestorForSendType);
6076   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6077       && typeReturned == nil)
6078     {
6079       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6080         return self;
6081     }
6083   return [super validRequestorForSendType: typeSent
6084                                returnType: typeReturned];
6088 /* The next two methods are part of NSServicesRequests informal protocol,
6089    supposedly called when a services menu item is chosen from this app.
6090    But this should not happen because we override the services menu with our
6091    own entries which call ns-perform-service.
6092    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6093    So let's at least stub them out until further investigation can be done. */
6095 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6097   /* we could call ns_string_from_pasteboard(pboard) here but then it should
6098      be written into the buffer in place of the existing selection..
6099      ordinary service calls go through functions defined in ns-win.el */
6100   return NO;
6103 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6105   NSArray *typesDeclared;
6106   Lisp_Object val;
6108   /* We only support NSStringPboardType */
6109   if ([types containsObject:NSStringPboardType] == NO) {
6110     return NO;
6111   }
6113   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6114   if (CONSP (val) && SYMBOLP (XCAR (val)))
6115     {
6116       val = XCDR (val);
6117       if (CONSP (val) && NILP (XCDR (val)))
6118         val = XCAR (val);
6119     }
6120   if (! STRINGP (val))
6121     return NO;
6123   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6124   [pb declareTypes:typesDeclared owner:nil];
6125   ns_string_to_pasteboard (pb, val);
6126   return YES;
6130 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6131    (gives a miniaturized version of the window); currently we use the latter for
6132    frames whose active buffer doesn't correspond to any file
6133    (e.g., '*scratch*') */
6134 - setMiniwindowImage: (BOOL) setMini
6136   id image = [[self window] miniwindowImage];
6137   NSTRACE (setMiniwindowImage);
6139   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6140      about "AppleDockIconEnabled" notwithstanding, however the set message
6141      below has its effect nonetheless. */
6142   if (image != emacsframe->output_data.ns->miniimage)
6143     {
6144       if (image && [image isKindOfClass: [EmacsImage class]])
6145         [image release];
6146       [[self window] setMiniwindowImage:
6147                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6148     }
6150   return self;
6154 - (void) setRows: (int) r andColumns: (int) c
6156   rows = r;
6157   cols = c;
6160 @end  /* EmacsView */
6164 /* ==========================================================================
6166     EmacsWindow implementation
6168    ========================================================================== */
6170 @implementation EmacsWindow
6172 #ifdef NS_IMPL_COCOA
6173 - (id)accessibilityAttributeValue:(NSString *)attribute
6175   Lisp_Object str = Qnil;
6176   struct frame *f = SELECTED_FRAME ();
6177   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->buffer);
6179   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6180     return NSAccessibilityTextFieldRole;
6182   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6183       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6184     {
6185       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6186     }
6187   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
6188     {
6189       if (! NILP (BVAR (curbuf, mark_active)))
6190           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6191       
6192       if (NILP (str))
6193         {
6194           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
6195           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
6196           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
6197           
6198           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
6199             str = make_uninit_multibyte_string (range, byte_range);
6200           else
6201             str = make_uninit_string (range);
6202           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
6203              Is this a problem?  */
6204           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
6205         }
6206     }
6207   
6208   
6209   if (! NILP (str)) 
6210     {
6211       if (CONSP (str) && SYMBOLP (XCAR (str)))
6212         {
6213           str = XCDR (str);
6214           if (CONSP (str) && NILP (XCDR (str)))
6215             str = XCAR (str);
6216         }
6217       if (STRINGP (str))
6218         {
6219           const char *utfStr = SSDATA (str);
6220           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
6221           return nsStr;
6222         }
6223     }
6224   
6225   return [super accessibilityAttributeValue:attribute];
6227 #endif /* NS_IMPL_COCOA */
6229 /* If we have multiple monitors, one above the other, we don't want to
6230    restrict the height to just one monitor.  So we override this.  */
6231 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6233   /* When making the frame visible for the first time or if there is just
6234      one screen, we want to constrain.  Other times not.  */
6235   NSUInteger nr_screens = [[NSScreen screens] count];
6236   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6237   NSTRACE (constrainFrameRect);
6239   if (nr_screens == 1)
6240     return [super constrainFrameRect:frameRect toScreen:screen];
6242   if (f->output_data.ns->dont_constrain
6243       || ns_menu_bar_should_be_hidden ())
6244     return frameRect;
6246   f->output_data.ns->dont_constrain = 1;
6247   return [super constrainFrameRect:frameRect toScreen:screen];
6251 /* called only on resize clicks by special case in EmacsApp-sendEvent */
6252 - (void)mouseDown: (NSEvent *)theEvent
6254   if (ns_in_resize)
6255     {
6256       NSSize size = [[theEvent window] frame].size;
6257       grabOffset = [theEvent locationInWindow];
6258       grabOffset.x = size.width - grabOffset.x;
6259     }
6260   else
6261     [super mouseDown: theEvent];
6265 /* stop resizing */
6266 - (void)mouseUp: (NSEvent *)theEvent
6268   if (ns_in_resize)
6269     {
6270       struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6271       ns_in_resize = NO;
6272       ns_set_name_as_filename (f);
6273       [self display];
6274       ns_send_appdefined (-1);
6275     }
6276   else
6277     [super mouseUp: theEvent];
6281 /* send resize events */
6282 - (void)mouseDragged: (NSEvent *)theEvent
6284   if (ns_in_resize)
6285     {
6286       NSPoint p = [theEvent locationInWindow];
6287       NSSize size, vettedSize, origSize = [self frame].size;
6289       size.width = p.x + grabOffset.x;
6290       size.height = origSize.height - p.y + grabOffset.y;
6292       if (size.width == origSize.width && size.height == origSize.height)
6293         return;
6295       vettedSize = [[self delegate] windowWillResize: self toSize: size];
6296       [[NSNotificationCenter defaultCenter]
6297             postNotificationName: NSWindowDidResizeNotification
6298                           object: self];
6299     }
6300   else
6301     [super mouseDragged: theEvent];
6304 @end /* EmacsWindow */
6307 /* ==========================================================================
6309     EmacsScroller implementation
6311    ========================================================================== */
6314 @implementation EmacsScroller
6316 /* for repeat button push */
6317 #define SCROLL_BAR_FIRST_DELAY 0.5
6318 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6320 + (CGFloat) scrollerWidth
6322   /* TODO: if we want to allow variable widths, this is the place to do it,
6323            however neither GNUstep nor Cocoa support it very well */
6324   return [NSScroller scrollerWidth];
6328 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6330   NSTRACE (EmacsScroller_initFrame);
6332   r.size.width = [EmacsScroller scrollerWidth];
6333   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6334   [self setContinuous: YES];
6335   [self setEnabled: YES];
6337   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6338      locked against the top and bottom edges, and right edge on OS X, where
6339      scrollers are on right. */
6340 #ifdef NS_IMPL_GNUSTEP
6341   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6342 #else
6343   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6344 #endif
6346   win = nwin;
6347   condemned = NO;
6348   pixel_height = NSHeight (r);
6349   if (pixel_height == 0) pixel_height = 1;
6350   min_portion = 20 / pixel_height;
6352   frame = XFRAME (XWINDOW (win)->frame);
6353   if (FRAME_LIVE_P (frame))
6354     {
6355       int i;
6356       EmacsView *view = FRAME_NS_VIEW (frame);
6357       NSView *sview = [[view window] contentView];
6358       NSArray *subs = [sview subviews];
6360       /* disable optimization stopping redraw of other scrollbars */
6361       view->scrollbarsNeedingUpdate = 0;
6362       for (i =[subs count]-1; i >= 0; i--)
6363         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6364           view->scrollbarsNeedingUpdate++;
6365       [sview addSubview: self];
6366     }
6368 /*  [self setFrame: r]; */
6370   return self;
6374 - (void)setFrame: (NSRect)newRect
6376   NSTRACE (EmacsScroller_setFrame);
6377 /*  BLOCK_INPUT; */
6378   pixel_height = NSHeight (newRect);
6379   if (pixel_height == 0) pixel_height = 1;
6380   min_portion = 20 / pixel_height;
6381   [super setFrame: newRect];
6382   [self display];
6383 /*  UNBLOCK_INPUT; */
6387 - (void)dealloc
6389   NSTRACE (EmacsScroller_dealloc);
6390   if (!NILP (win))
6391     wset_vertical_scroll_bar (XWINDOW (win), Qnil);
6392   [super dealloc];
6396 - condemn
6398   NSTRACE (condemn);
6399   condemned =YES;
6400   return self;
6404 - reprieve
6406   NSTRACE (reprieve);
6407   condemned =NO;
6408   return self;
6412 - judge
6414   NSTRACE (judge);
6415   if (condemned)
6416     {
6417       EmacsView *view;
6418       BLOCK_INPUT;
6419       /* ensure other scrollbar updates after deletion */
6420       view = (EmacsView *)FRAME_NS_VIEW (frame);
6421       if (view != nil)
6422         view->scrollbarsNeedingUpdate++;
6423       [self removeFromSuperview];
6424       [self release];
6425       UNBLOCK_INPUT;
6426     }
6427   return self;
6431 - (void)resetCursorRects
6433   NSRect visible = [self visibleRect];
6434   NSTRACE (resetCursorRects);
6436   if (!NSIsEmptyRect (visible))
6437     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6438   [[NSCursor arrowCursor] setOnMouseEntered: YES];
6442 - (int) checkSamePosition: (int) position portion: (int) portion
6443                     whole: (int) whole
6445   return em_position ==position && em_portion ==portion && em_whole ==whole
6446     && portion != whole; /* needed for resize empty buf */
6450 - setPosition: (int)position portion: (int)portion whole: (int)whole
6452   NSTRACE (setPosition);
6454   em_position = position;
6455   em_portion = portion;
6456   em_whole = whole;
6458   if (portion >= whole)
6459     {
6460 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6461       [self setKnobProportion: 1.0];
6462       [self setDoubleValue: 1.0];
6463 #else
6464       [self setFloatValue: 0.0 knobProportion: 1.0];
6465 #endif
6466     }
6467   else
6468     {
6469       float pos, por;
6470       portion = max ((float)whole*min_portion/pixel_height, portion);
6471       pos = (float)position / (whole - portion);
6472       por = (float)portion/whole;
6473 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6474       [self setKnobProportion: por];
6475       [self setDoubleValue: pos];
6476 #else
6477       [self setFloatValue: pos knobProportion: por];
6478 #endif
6479     }
6480   return self;
6483 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6484      drag events will go directly to the EmacsScroller.  Leaving in for now. */
6485 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6486                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
6488   *part = last_hit_part;
6489   *window = win;
6490   XSETINT (*y, pixel_height);
6491   if ([self floatValue] > 0.999)
6492     XSETINT (*x, pixel_height);
6493   else
6494     XSETINT (*x, pixel_height * [self floatValue]);
6498 /* set up emacs_event */
6499 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6501   if (!emacs_event)
6502     return;
6504   emacs_event->part = last_hit_part;
6505   emacs_event->code = 0;
6506   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
6507   emacs_event->frame_or_window = win;
6508   emacs_event->timestamp = EV_TIMESTAMP (e);
6509   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
6510   emacs_event->arg = Qnil;
6511   XSETINT (emacs_event->x, loc * pixel_height);
6512   XSETINT (emacs_event->y, pixel_height-20);
6514   if (q_event_ptr)
6515     {
6516       n_emacs_events_pending++;
6517       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
6518     }
6519   else
6520     kbd_buffer_store_event (emacs_event);
6521   EVENT_INIT (*emacs_event);
6522   ns_send_appdefined (-1);
6526 /* called manually thru timer to implement repeated button action w/hold-down */
6527 - repeatScroll: (NSTimer *)scrollEntry
6529   NSEvent *e = [[self window] currentEvent];
6530   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
6531   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
6533   /* clear timer if need be */
6534   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
6535     {
6536         [scroll_repeat_entry invalidate];
6537         [scroll_repeat_entry release];
6538         scroll_repeat_entry = nil;
6540         if (inKnob)
6541           return self;
6543         scroll_repeat_entry
6544           = [[NSTimer scheduledTimerWithTimeInterval:
6545                         SCROLL_BAR_CONTINUOUS_DELAY
6546                                             target: self
6547                                           selector: @selector (repeatScroll:)
6548                                           userInfo: 0
6549                                            repeats: YES]
6550               retain];
6551     }
6553   [self sendScrollEventAtLoc: 0 fromEvent: e];
6554   return self;
6558 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
6559    mouseDragged events without going into a modal loop. */
6560 - (void)mouseDown: (NSEvent *)e
6562   NSRect sr, kr;
6563   /* hitPart is only updated AFTER event is passed on */
6564   NSScrollerPart part = [self testPart: [e locationInWindow]];
6565   double inc = 0.0, loc, kloc, pos;
6566   int edge = 0;
6568   NSTRACE (EmacsScroller_mouseDown);
6570   switch (part)
6571     {
6572     case NSScrollerDecrementPage:
6573         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
6574     case NSScrollerIncrementPage:
6575         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
6576     case NSScrollerDecrementLine:
6577       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
6578     case NSScrollerIncrementLine:
6579       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
6580     case NSScrollerKnob:
6581       last_hit_part = scroll_bar_handle; break;
6582     case NSScrollerKnobSlot:  /* GNUstep-only */
6583       last_hit_part = scroll_bar_move_ratio; break;
6584     default:  /* NSScrollerNoPart? */
6585       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
6586                (long) part);
6587       return;
6588     }
6590   if (inc != 0.0)
6591     {
6592       pos = 0;      /* ignored */
6594       /* set a timer to repeat, as we can't let superclass do this modally */
6595       scroll_repeat_entry
6596         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
6597                                             target: self
6598                                           selector: @selector (repeatScroll:)
6599                                           userInfo: 0
6600                                            repeats: YES]
6601             retain];
6602     }
6603   else
6604     {
6605       /* handle, or on GNUstep possibly slot */
6606       NSEvent *fake_event;
6608       /* compute float loc in slot and mouse offset on knob */
6609       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6610                       toView: nil];
6611       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6612       if (loc <= 0.0)
6613         {
6614           loc = 0.0;
6615           edge = -1;
6616         }
6617       else if (loc >= NSHeight (sr))
6618         {
6619           loc = NSHeight (sr);
6620           edge = 1;
6621         }
6623       if (edge)
6624         kloc = 0.5 * edge;
6625       else
6626         {
6627           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
6628                           toView: nil];
6629           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
6630         }
6631       last_mouse_offset = kloc;
6633       /* if knob, tell emacs a location offset by knob pos
6634          (to indicate top of handle) */
6635       if (part == NSScrollerKnob)
6636           pos = (loc - last_mouse_offset) / NSHeight (sr);
6637       else
6638         /* else this is a slot click on GNUstep: go straight there */
6639         pos = loc / NSHeight (sr);
6641       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
6642       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
6643                                       location: [e locationInWindow]
6644                                  modifierFlags: [e modifierFlags]
6645                                      timestamp: [e timestamp]
6646                                   windowNumber: [e windowNumber]
6647                                        context: [e context]
6648                                    eventNumber: [e eventNumber]
6649                                     clickCount: [e clickCount]
6650                                       pressure: [e pressure]];
6651       [super mouseUp: fake_event];
6652     }
6654   if (part != NSScrollerKnob)
6655     [self sendScrollEventAtLoc: pos fromEvent: e];
6659 /* Called as we manually track scroller drags, rather than superclass. */
6660 - (void)mouseDragged: (NSEvent *)e
6662     NSRect sr;
6663     double loc, pos;
6664     int edge = 0;
6666     NSTRACE (EmacsScroller_mouseDragged);
6668       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6669                       toView: nil];
6670       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6672       if (loc <= 0.0)
6673         {
6674           loc = 0.0;
6675           edge = -1;
6676         }
6677       else if (loc >= NSHeight (sr) + last_mouse_offset)
6678         {
6679           loc = NSHeight (sr) + last_mouse_offset;
6680           edge = 1;
6681         }
6683       pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
6684       [self sendScrollEventAtLoc: pos fromEvent: e];
6688 - (void)mouseUp: (NSEvent *)e
6690   if (scroll_repeat_entry)
6691     {
6692       [scroll_repeat_entry invalidate];
6693       [scroll_repeat_entry release];
6694       scroll_repeat_entry = nil;
6695     }
6696   last_hit_part = 0;
6700 /* treat scrollwheel events in the bar as though they were in the main window */
6701 - (void) scrollWheel: (NSEvent *)theEvent
6703   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
6704   [view mouseDown: theEvent];
6707 @end  /* EmacsScroller */
6712 /* ==========================================================================
6714    Font-related functions; these used to be in nsfaces.m
6716    ========================================================================== */
6719 Lisp_Object
6720 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
6722   struct font *font = XFONT_OBJECT (font_object);
6724   if (fontset < 0)
6725     fontset = fontset_from_font (font_object);
6726   FRAME_FONTSET (f) = fontset;
6728   if (FRAME_FONT (f) == font)
6729     /* This font is already set in frame F.  There's nothing more to
6730        do.  */
6731     return font_object;
6733   FRAME_FONT (f) = font;
6735   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
6736   FRAME_COLUMN_WIDTH (f) = font->average_width;
6737   FRAME_SPACE_WIDTH (f) = font->space_width;
6738   FRAME_LINE_HEIGHT (f) = font->height;
6740   compute_fringe_widths (f, 1);
6742   /* Compute the scroll bar width in character columns.  */
6743   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6744     {
6745       int wid = FRAME_COLUMN_WIDTH (f);
6746       FRAME_CONFIG_SCROLL_BAR_COLS (f)
6747         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
6748     }
6749   else
6750     {
6751       int wid = FRAME_COLUMN_WIDTH (f);
6752       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6753     }
6755   /* Now make the frame display the given font.  */
6756   if (FRAME_NS_WINDOW (f) != 0)
6757         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6759   return font_object;
6763 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
6764 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
6765          in 1.43. */
6767 const char *
6768 ns_xlfd_to_fontname (const char *xlfd)
6769 /* --------------------------------------------------------------------------
6770     Convert an X font name (XLFD) to an NS font name.
6771     Only family is used.
6772     The string returned is temporarily allocated.
6773    -------------------------------------------------------------------------- */
6775   char *name = xmalloc (180);
6776   int i, len;
6777   const char *ret;
6779   if (!strncmp (xlfd, "--", 2))
6780     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
6781   else
6782     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
6784   /* stopgap for malformed XLFD input */
6785   if (strlen (name) == 0)
6786     strcpy (name, "Monaco");
6788   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
6789      also uppercase after '-' or ' ' */
6790   name[0] = c_toupper (name[0]);
6791   for (len =strlen (name), i =0; i<len; i++)
6792     {
6793       if (name[i] == '$')
6794         {
6795           name[i] = '-';
6796           if (i+1<len)
6797             name[i+1] = c_toupper (name[i+1]);
6798         }
6799       else if (name[i] == '_')
6800         {
6801           name[i] = ' ';
6802           if (i+1<len)
6803             name[i+1] = c_toupper (name[i+1]);
6804         }
6805     }
6806 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
6807   ret = [[NSString stringWithUTF8String: name] UTF8String];
6808   xfree (name);
6809   return ret;
6813 void
6814 syms_of_nsterm (void)
6816   NSTRACE (syms_of_nsterm);
6818   ns_antialias_threshold = 10.0;
6820   /* from 23+ we need to tell emacs what modifiers there are.. */
6821   DEFSYM (Qmodifier_value, "modifier-value");
6822   DEFSYM (Qalt, "alt");
6823   DEFSYM (Qhyper, "hyper");
6824   DEFSYM (Qmeta, "meta");
6825   DEFSYM (Qsuper, "super");
6826   DEFSYM (Qcontrol, "control");
6827   DEFSYM (QUTF8_STRING, "UTF8_STRING");
6829   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
6830   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
6831   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
6832   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
6833   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
6835   DEFVAR_LISP ("ns-input-file", ns_input_file,
6836               "The file specified in the last NS event.");
6837   ns_input_file =Qnil;
6839   DEFVAR_LISP ("ns-input-text", ns_input_text,
6840               "The data received in the last NS text drag event.");
6841   ns_input_text =Qnil;
6843   DEFVAR_LISP ("ns-working-text", ns_working_text,
6844               "String for visualizing working composition sequence.");
6845   ns_working_text =Qnil;
6847   DEFVAR_LISP ("ns-input-font", ns_input_font,
6848               "The font specified in the last NS event.");
6849   ns_input_font =Qnil;
6851   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
6852               "The fontsize specified in the last NS event.");
6853   ns_input_fontsize =Qnil;
6855   DEFVAR_LISP ("ns-input-line", ns_input_line,
6856                "The line specified in the last NS event.");
6857   ns_input_line =Qnil;
6859   DEFVAR_LISP ("ns-input-color", ns_input_color,
6860                "The color specified in the last NS event.");
6861   ns_input_color =Qnil;
6863   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
6864                "The service name specified in the last NS event.");
6865   ns_input_spi_name =Qnil;
6867   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
6868                "The service argument specified in the last NS event.");
6869   ns_input_spi_arg =Qnil;
6871   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
6872                "This variable describes the behavior of the alternate or option key.\n\
6873 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6874 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6875 at all, allowing it to be used at a lower level for accented character entry.");
6876   ns_alternate_modifier = Qmeta;
6878   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
6879                "This variable describes the behavior of the right alternate or option key.\n\
6880 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6881 Set to left means be the same key as `ns-alternate-modifier'.\n\
6882 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6883 at all, allowing it to be used at a lower level for accented character entry.");
6884   ns_right_alternate_modifier = Qleft;
6886   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
6887                "This variable describes the behavior of the command key.\n\
6888 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6889   ns_command_modifier = Qsuper;
6891   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
6892                "This variable describes the behavior of the right command key.\n\
6893 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6894 Set to left means be the same key as `ns-command-modifier'.\n\
6895 Set to none means that the command / option key is not interpreted by Emacs\n\
6896 at all, allowing it to be used at a lower level for accented character entry.");
6897   ns_right_command_modifier = Qleft;
6899   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
6900                "This variable describes the behavior of the control key.\n\
6901 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6902   ns_control_modifier = Qcontrol;
6904   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
6905                "This variable describes the behavior of the right control key.\n\
6906 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6907 Set to left means be the same key as `ns-control-modifier'.\n\
6908 Set to none means that the control / option key is not interpreted by Emacs\n\
6909 at all, allowing it to be used at a lower level for accented character entry.");
6910   ns_right_control_modifier = Qleft;
6912   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
6913                "This variable describes the behavior of the function key (on laptops).\n\
6914 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6915 Set to none means that the function key is not interpreted by Emacs at all,\n\
6916 allowing it to be used at a lower level for accented character entry.");
6917   ns_function_modifier = Qnone;
6919   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
6920                "Non-nil (the default) means to render text antialiased. Only has an effect on OS X Panther and above.");
6921   ns_antialias_text = Qt;
6923   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
6924                "Whether to confirm application quit using dialog.");
6925   ns_confirm_quit = Qnil;
6927   staticpro (&ns_display_name_list);
6928   ns_display_name_list = Qnil;
6930   staticpro (&last_mouse_motion_frame);
6931   last_mouse_motion_frame = Qnil;
6933   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
6934                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
6935 Only works on OSX 10.6 or later.  */);
6936   ns_auto_hide_menu_bar = Qnil;
6938   /* TODO: move to common code */
6939   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
6940                doc: /* Which toolkit scroll bars Emacs uses, if any.
6941 A value of nil means Emacs doesn't use toolkit scroll bars.
6942 With the X Window system, the value is a symbol describing the
6943 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
6944 With MS Windows or Nextstep, the value is t.  */);
6945   Vx_toolkit_scroll_bars = Qt;
6947   DEFVAR_BOOL ("x-use-underline-position-properties",
6948                x_use_underline_position_properties,
6949      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
6950 A value of nil means ignore them.  If you encounter fonts with bogus
6951 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
6952 to 4.1, set this to nil. */);
6953   x_use_underline_position_properties = 0;
6955   DEFVAR_BOOL ("x-underline-at-descent-line",
6956                x_underline_at_descent_line,
6957      doc: /* Non-nil means to draw the underline at the same place as the descent line.
6958 A value of nil means to draw the underline according to the value of the
6959 variable `x-use-underline-position-properties', which is usually at the
6960 baseline level.  The default value is nil.  */);
6961   x_underline_at_descent_line = 0;
6963   /* Tell emacs about this window system. */
6964   Fprovide (intern ("ns"), Qnil);