* lisp/emacs-lisp/rx.el (rx-constituents): Don't define as constant.
[emacs/old-mirror.git] / src / nsterm.m
blob807ff5642139b92b3b8fdea179f19c99027210d7
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>
39 #include <c-strcase.h>
40 #include <ftoastr.h>
42 #include "lisp.h"
43 #include "blockinput.h"
44 #include "sysselect.h"
45 #include "nsterm.h"
46 #include "systime.h"
47 #include "character.h"
48 #include "fontset.h"
49 #include "composite.h"
50 #include "ccl.h"
52 #include "termhooks.h"
53 #include "termopts.h"
54 #include "termchar.h"
56 #include "window.h"
57 #include "keyboard.h"
58 #include "buffer.h"
59 #include "font.h"
61 /* call tracing */
62 #if 0
63 int term_trace_num = 0;
64 #define NSTRACE(x)        fprintf (stderr, "%s:%d: [%d] " #x "\n",         \
65                                 __FILE__, __LINE__, ++term_trace_num)
66 #else
67 #define NSTRACE(x)
68 #endif
70 extern NSString *NSMenuDidBeginTrackingNotification;
72 /* ==========================================================================
74     Local declarations
76    ========================================================================== */
78 /* Convert a symbol indexed with an NSxxx value to a value as defined
79    in keyboard.c (lispy_function_key). I hope this is a correct way
80    of doing things... */
81 static unsigned convert_ns_to_X_keysym[] =
83   NSHomeFunctionKey,            0x50,
84   NSLeftArrowFunctionKey,       0x51,
85   NSUpArrowFunctionKey,         0x52,
86   NSRightArrowFunctionKey,      0x53,
87   NSDownArrowFunctionKey,       0x54,
88   NSPageUpFunctionKey,          0x55,
89   NSPageDownFunctionKey,        0x56,
90   NSEndFunctionKey,             0x57,
91   NSBeginFunctionKey,           0x58,
92   NSSelectFunctionKey,          0x60,
93   NSPrintFunctionKey,           0x61,
94   NSExecuteFunctionKey,         0x62,
95   NSInsertFunctionKey,          0x63,
96   NSUndoFunctionKey,            0x65,
97   NSRedoFunctionKey,            0x66,
98   NSMenuFunctionKey,            0x67,
99   NSFindFunctionKey,            0x68,
100   NSHelpFunctionKey,            0x6A,
101   NSBreakFunctionKey,           0x6B,
103   NSF1FunctionKey,              0xBE,
104   NSF2FunctionKey,              0xBF,
105   NSF3FunctionKey,              0xC0,
106   NSF4FunctionKey,              0xC1,
107   NSF5FunctionKey,              0xC2,
108   NSF6FunctionKey,              0xC3,
109   NSF7FunctionKey,              0xC4,
110   NSF8FunctionKey,              0xC5,
111   NSF9FunctionKey,              0xC6,
112   NSF10FunctionKey,             0xC7,
113   NSF11FunctionKey,             0xC8,
114   NSF12FunctionKey,             0xC9,
115   NSF13FunctionKey,             0xCA,
116   NSF14FunctionKey,             0xCB,
117   NSF15FunctionKey,             0xCC,
118   NSF16FunctionKey,             0xCD,
119   NSF17FunctionKey,             0xCE,
120   NSF18FunctionKey,             0xCF,
121   NSF19FunctionKey,             0xD0,
122   NSF20FunctionKey,             0xD1,
123   NSF21FunctionKey,             0xD2,
124   NSF22FunctionKey,             0xD3,
125   NSF23FunctionKey,             0xD4,
126   NSF24FunctionKey,             0xD5,
128   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
129   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
130   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
132   NSTabCharacter,               0x09,
133   0x19,                         0x09,  /* left tab->regular since pass shift */
134   NSCarriageReturnCharacter,    0x0D,
135   NSNewlineCharacter,           0x0D,
136   NSEnterCharacter,             0x8D,
138   0x1B,                         0x1B   /* escape */
141 static Lisp_Object Qmodifier_value;
142 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper;
143 extern Lisp_Object Qcursor_color, Qcursor_type, Qns, Qleft;
145 static Lisp_Object QUTF8_STRING;
147 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
148    the maximum font size to NOT antialias.  On GNUstep there is currently
149    no way to control this behavior. */
150 float ns_antialias_threshold;
152 /* Used to pick up AppleHighlightColor on OS X */
153 NSString *ns_selection_color;
155 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
156 NSString *ns_app_name = @"Emacs";  /* default changed later */
158 /* Display variables */
159 struct ns_display_info *x_display_list; /* Chain of existing displays */
160 Lisp_Object ns_display_name_list;
161 long context_menu_value = 0;
163 /* display update */
164 NSPoint last_mouse_motion_position;
165 static NSRect last_mouse_glyph;
166 static Time last_mouse_movement_time = 0;
167 static Lisp_Object last_mouse_motion_frame;
168 static EmacsScroller *last_mouse_scroll_bar = nil;
169 static struct frame *ns_updating_frame;
170 static NSView *focus_view = NULL;
171 static int ns_window_num = 0;
172 #ifdef NS_IMPL_GNUSTEP
173 static NSRect uRect;
174 #endif
175 static BOOL gsaved = NO;
176 BOOL ns_in_resize = NO;
177 static BOOL ns_fake_keydown = NO;
178 int ns_tmp_flags; /* FIXME */
179 struct nsfont_info *ns_tmp_font; /* FIXME */
180 static BOOL ns_menu_bar_is_hidden = NO;
181 /*static int debug_lock = 0; */
183 /* event loop */
184 static BOOL send_appdefined = YES;
185 static NSEvent *last_appdefined_event = 0;
186 static NSTimer *timed_entry = 0;
187 static NSTimer *fd_entry = nil;
188 static NSTimer *scroll_repeat_entry = nil;
189 static fd_set select_readfds, t_readfds;
190 static int select_nfds;
191 static NSAutoreleasePool *outerpool;
192 static struct input_event *emacs_event = NULL;
193 static struct input_event *q_event_ptr = NULL;
194 static int n_emacs_events_pending = 0;
195 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
196   *ns_pending_service_args;
197 static BOOL inNsSelect = 0;
198 static BOOL ns_do_open_file = NO;
200 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
201 #define NS_FUNCTION_KEY_MASK 0x800000
202 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
203 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
204 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
205 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
206 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
207 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
208 #define EV_MODIFIERS(e)                               \
209     ((([e modifierFlags] & NSHelpKeyMask) ?           \
210            hyper_modifier : 0)                        \
211      | (!EQ (ns_right_alternate_modifier, Qleft) && \
212         (([e modifierFlags] & NSRightAlternateKeyMask) \
213          == NSRightAlternateKeyMask) ? \
214            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
215      | (([e modifierFlags] & NSAlternateKeyMask) ?                 \
216            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
217      | (([e modifierFlags] & NSShiftKeyMask) ?     \
218            shift_modifier : 0)                        \
219      | (!EQ (ns_right_control_modifier, Qleft) && \
220         (([e modifierFlags] & NSRightControlKeyMask) \
221          == NSRightControlKeyMask) ? \
222            parse_solitary_modifier (ns_right_control_modifier) : 0) \
223      | (([e modifierFlags] & NSControlKeyMask) ?      \
224            parse_solitary_modifier (ns_control_modifier) : 0)     \
225      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
226            parse_solitary_modifier (ns_function_modifier) : 0)    \
227      | (!EQ (ns_right_command_modifier, Qleft) && \
228         (([e modifierFlags] & NSRightCommandKeyMask) \
229          == NSRightCommandKeyMask) ? \
230            parse_solitary_modifier (ns_right_command_modifier) : 0) \
231      | (([e modifierFlags] & NSCommandKeyMask) ?      \
232            parse_solitary_modifier (ns_command_modifier):0))
234 #define EV_UDMODIFIERS(e)                                      \
235     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
236      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
237      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
238      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
239      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
240      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
241      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
242      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
243      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
245 #define EV_BUTTON(e)                                                         \
246     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
247       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
248      [e buttonNumber] - 1)
250 /* Convert the time field to a timestamp in milliseconds. */
251 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
253 /* This is a piece of code which is common to all the event handling
254    methods.  Maybe it should even be a function.  */
255 #define EV_TRAILER(e)                                         \
256   {                                                           \
257   XSETFRAME (emacs_event->frame_or_window, emacsframe);       \
258   if (e) emacs_event->timestamp = EV_TIMESTAMP (e);           \
259   n_emacs_events_pending++;                                   \
260   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);     \
261   EVENT_INIT (*emacs_event);                                  \
262   ns_send_appdefined (-1);                                    \
263   }
265 void x_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
267 /* TODO: get rid of need for these forward declarations */
268 static void ns_condemn_scroll_bars (struct frame *f);
269 static void ns_judge_scroll_bars (struct frame *f);
270 void x_set_frame_alpha (struct frame *f);
273 /* ==========================================================================
275     Utilities
277    ========================================================================== */
280 static Lisp_Object
281 append2 (Lisp_Object list, Lisp_Object item)
282 /* --------------------------------------------------------------------------
283    Utility to append to a list
284    -------------------------------------------------------------------------- */
286   Lisp_Object array[2];
287   array[0] = list;
288   array[1] = Fcons (item, Qnil);
289   return Fnconc (2, &array[0]);
293 const char *
294 ns_etc_directory (void)
295 /* If running as a self-contained app bundle, return as a string the
296    filename of the etc directory, if present; else nil.  */
298   NSBundle *bundle = [NSBundle mainBundle];
299   NSString *resourceDir = [bundle resourcePath];
300   NSString *resourcePath;
301   NSFileManager *fileManager = [NSFileManager defaultManager];
302   BOOL isDir;
304   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
305   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
306     {
307       if (isDir) return [resourcePath UTF8String];
308     }
309   return NULL;
313 const char *
314 ns_exec_path (void)
315 /* If running as a self-contained app bundle, return as a path string
316    the filenames of the libexec and bin directories, ie libexec:bin.
317    Otherwise, return nil.
318    Normally, Emacs does not add its own bin/ directory to the PATH.
319    However, a self-contained NS build has a different layout, with
320    bin/ and libexec/ subdirectories in the directory that contains
321    Emacs.app itself.
322    We put libexec first, because init_callproc_1 uses the first
323    element to initialize exec-directory.  An alternative would be
324    for init_callproc to check for invocation-directory/libexec.
327   NSBundle *bundle = [NSBundle mainBundle];
328   NSString *resourceDir = [bundle resourcePath];
329   NSString *binDir = [bundle bundlePath];
330   NSString *resourcePath, *resourcePaths;
331   NSRange range;
332   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
333   NSFileManager *fileManager = [NSFileManager defaultManager];
334   NSArray *paths;
335   NSEnumerator *pathEnum;
336   BOOL isDir;
338   range = [resourceDir rangeOfString: @"Contents"];
339   if (range.location != NSNotFound)
340     {
341       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
342 #ifdef NS_IMPL_COCOA
343       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
344 #endif
345     }
347   paths = [binDir stringsByAppendingPaths:
348                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
349   pathEnum = [paths objectEnumerator];
350   resourcePaths = @"";
352   while ((resourcePath = [pathEnum nextObject]))
353     {
354       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
355         if (isDir)
356           {
357             if ([resourcePaths length] > 0)
358               resourcePaths
359                 = [resourcePaths stringByAppendingString: pathSeparator];
360             resourcePaths
361               = [resourcePaths stringByAppendingString: resourcePath];
362           }
363     }
364   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
366   return NULL;
370 const char *
371 ns_load_path (void)
372 /* If running as a self-contained app bundle, return as a path string
373    the filenames of the site-lisp, lisp and leim directories.
374    Ie, site-lisp:lisp:leim.  Otherwise, return nil.  */
376   NSBundle *bundle = [NSBundle mainBundle];
377   NSString *resourceDir = [bundle resourcePath];
378   NSString *resourcePath, *resourcePaths;
379   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
380   NSFileManager *fileManager = [NSFileManager defaultManager];
381   BOOL isDir;
382   NSArray *paths = [resourceDir stringsByAppendingPaths:
383                               [NSArray arrayWithObjects:
384                                          @"site-lisp", @"lisp", @"leim", nil]];
385   NSEnumerator *pathEnum = [paths objectEnumerator];
386   resourcePaths = @"";
388   /* Hack to skip site-lisp.  */
389   if (no_site_lisp) resourcePath = [pathEnum nextObject];
391   while ((resourcePath = [pathEnum nextObject]))
392     {
393       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
394         if (isDir)
395           {
396             if ([resourcePaths length] > 0)
397               resourcePaths
398                 = [resourcePaths stringByAppendingString: pathSeparator];
399             resourcePaths
400               = [resourcePaths stringByAppendingString: resourcePath];
401           }
402     }
403   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
405   return NULL;
408 static void
409 ns_timeout (int usecs)
410 /* --------------------------------------------------------------------------
411      Blocking timer utility used by ns_ring_bell
412    -------------------------------------------------------------------------- */
414   EMACS_TIME wakeup = add_emacs_time (current_emacs_time (),
415                                       make_emacs_time (0, usecs * 1000));
417   /* Keep waiting until past the time wakeup.  */
418   while (1)
419     {
420       EMACS_TIME timeout, now = current_emacs_time ();
421       if (EMACS_TIME_LE (wakeup, now))
422         break;
423       timeout = sub_emacs_time (wakeup, now);
425       /* Try to wait that long--but we might wake up sooner.  */
426       pselect (0, NULL, NULL, NULL, &timeout, NULL);
427     }
431 void
432 ns_release_object (void *obj)
433 /* --------------------------------------------------------------------------
434     Release an object (callable from C)
435    -------------------------------------------------------------------------- */
437     [(id)obj release];
441 void
442 ns_retain_object (void *obj)
443 /* --------------------------------------------------------------------------
444     Retain an object (callable from C)
445    -------------------------------------------------------------------------- */
447     [(id)obj retain];
451 void *
452 ns_alloc_autorelease_pool (void)
453 /* --------------------------------------------------------------------------
454      Allocate a pool for temporary objects (callable from C)
455    -------------------------------------------------------------------------- */
457   return [[NSAutoreleasePool alloc] init];
461 void
462 ns_release_autorelease_pool (void *pool)
463 /* --------------------------------------------------------------------------
464      Free a pool and temporary objects it refers to (callable from C)
465    -------------------------------------------------------------------------- */
467   ns_release_object (pool);
472 /* ==========================================================================
474     Focus (clipping) and screen update
476    ========================================================================== */
478 static NSRect
479 ns_resize_handle_rect (NSWindow *window)
481   NSRect r = [window frame];
482   r.origin.x = r.size.width - RESIZE_HANDLE_SIZE;
483   r.origin.y = 0;
484   r.size.width = r.size.height = RESIZE_HANDLE_SIZE;
485   return r;
490 // Window constraining
491 // -------------------
493 // To ensure that the windows are not placed under the menu bar, they
494 // are typically moved by the call-back constrainFrameRect. However,
495 // by overriding it, it's possible to inhibit this, leaving the window
496 // in it's original position.
498 // It's possible to hide the menu bar. However, technically, it's only
499 // possible to hide it when the application is active. To ensure that
500 // this work properly, the menu bar and window constraining are
501 // deferred until the application becomes active.
503 // Even though it's not possible to manually move a window above the
504 // top of the screen, it is allowed if it's done programmatically,
505 // when the menu is hidden. This allows the editable area to cover the
506 // full screen height.
508 // Test cases
509 // ----------
511 // Use the following extra files:
513 //    init.el:
514 //       ;; Hide menu and place frame slightly above the top of the screen.
515 //       (setq ns-auto-hide-menu-bar t)
516 //       (set-frame-position (selected-frame) 0 -20)
518 // Test 1:
520 //    emacs -Q -l init.el
522 //    Result: No menu bar, and the title bar should be above the screen.
524 // Test 2:
526 //    emacs -Q
528 //    Result: Menu bar visible, frame placed immediately below the menu.
531 static void
532 ns_constrain_all_frames (void)
534   Lisp_Object tail, frame;
536   FOR_EACH_FRAME (tail, frame)
537     {
538       struct frame *f = XFRAME (frame);
539       if (FRAME_NS_P (f))
540         {
541           NSView *view = FRAME_NS_VIEW (f);
542           /* This no-op will trigger the default window placing
543            * constraint system. */
544           f->output_data.ns->dont_constrain = 0;
545           [[view window] setFrameOrigin:[[view window] frame].origin];
546         }
547     }
551 /* True, if the menu bar should be hidden.  */
553 static BOOL
554 ns_menu_bar_should_be_hidden (void)
556   return !NILP (ns_auto_hide_menu_bar)
557     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
561 /* Show or hide the menu bar, based on user setting.  */
563 static void
564 ns_update_auto_hide_menu_bar (void)
566 #ifndef MAC_OS_X_VERSION_10_6
567 #define MAC_OS_X_VERSION_10_6 1060
568 #endif
569 #ifdef NS_IMPL_COCOA
570 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
571   BLOCK_INPUT;
573   NSTRACE (ns_update_auto_hide_menu_bar);
575   if (NSApp != nil
576       && [NSApp isActive]
577       && [NSApp respondsToSelector:@selector(setPresentationOptions:)])
578     {
579       // Note, "setPresentationOptions" triggers an error unless the
580       // application is active.
581       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
583       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
584         {
585           NSApplicationPresentationOptions options
586             = NSApplicationPresentationAutoHideDock;
588           if (menu_bar_should_be_hidden)
589             options |= NSApplicationPresentationAutoHideMenuBar;
591           [NSApp setPresentationOptions: options];
593           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
595           if (!ns_menu_bar_is_hidden)
596             {
597               ns_constrain_all_frames ();
598             }
599         }
600     }
602   UNBLOCK_INPUT;
603 #endif
604 #endif
608 static void
609 ns_update_begin (struct frame *f)
610 /* --------------------------------------------------------------------------
611    Prepare for a grouped sequence of drawing calls
612    external (RIF) call; whole frame, called before update_window_begin
613    -------------------------------------------------------------------------- */
615   NSView *view = FRAME_NS_VIEW (f);
616   NSTRACE (ns_update_begin);
618   ns_update_auto_hide_menu_bar ();
620   ns_updating_frame = f;
621   [view lockFocus];
623 #ifdef NS_IMPL_GNUSTEP
624   uRect = NSMakeRect (0, 0, 0, 0);
625 #endif
629 static void
630 ns_update_window_begin (struct window *w)
631 /* --------------------------------------------------------------------------
632    Prepare for a grouped sequence of drawing calls
633    external (RIF) call; for one window, called after update_begin
634    -------------------------------------------------------------------------- */
636   struct frame *f = XFRAME (WINDOW_FRAME (w));
637  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
638   NSTRACE (ns_update_window_begin);
640   updated_window = w;
641   set_output_cursor (&w->cursor);
643   BLOCK_INPUT;
645   if (f == hlinfo->mouse_face_mouse_frame)
646     {
647       /* Don't do highlighting for mouse motion during the update.  */
648       hlinfo->mouse_face_defer = 1;
650         /* If the frame needs to be redrawn,
651            simply forget about any prior mouse highlighting.  */
652       if (FRAME_GARBAGED_P (f))
653         hlinfo->mouse_face_window = Qnil;
655       /* (further code for mouse faces ifdef'd out in other terms elided) */
656     }
658   UNBLOCK_INPUT;
662 static void
663 ns_update_window_end (struct window *w, int cursor_on_p,
664                       int mouse_face_overwritten_p)
665 /* --------------------------------------------------------------------------
666    Finished a grouped sequence of drawing calls
667    external (RIF) call; for one window called before update_end
668    -------------------------------------------------------------------------- */
670   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
672   /* note: this fn is nearly identical in all terms */
673   if (!w->pseudo_window_p)
674     {
675       BLOCK_INPUT;
677       if (cursor_on_p)
678         display_and_set_cursor (w, 1,
679                                 output_cursor.hpos, output_cursor.vpos,
680                                 output_cursor.x, output_cursor.y);
682       if (draw_window_fringes (w, 1))
683         x_draw_vertical_border (w);
685       UNBLOCK_INPUT;
686     }
688   /* If a row with mouse-face was overwritten, arrange for
689      frame_up_to_date to redisplay the mouse highlight.  */
690   if (mouse_face_overwritten_p)
691     {
692       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
693       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
694       hlinfo->mouse_face_window = Qnil;
695     }
697   updated_window = NULL;
698   NSTRACE (update_window_end);
702 static void
703 ns_update_end (struct frame *f)
704 /* --------------------------------------------------------------------------
705    Finished a grouped sequence of drawing calls
706    external (RIF) call; for whole frame, called after update_window_end
707    -------------------------------------------------------------------------- */
709   NSView *view = FRAME_NS_VIEW (f);
711 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
712     MOUSE_HL_INFO (f)->mouse_face_defer = 0;
714   BLOCK_INPUT;
716 #ifdef NS_IMPL_GNUSTEP
717   /* trigger flush only in the rectangle we tracked as being drawn */
718   [view unlockFocusNeedsFlush: NO];
719 /*fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", uRect.origin.x, uRect.origin.y, uRect.size.width, uRect.size.height); */
720   [view lockFocusInRect: uRect];
721 #endif
723   [view unlockFocus];
724   [[view window] flushWindow];
726   UNBLOCK_INPUT;
727   ns_updating_frame = NULL;
728   NSTRACE (ns_update_end);
732 static void
733 ns_flush (struct frame *f)
734 /* --------------------------------------------------------------------------
735    external (RIF) call
736    NS impl is no-op since currently we flush in ns_update_end and elsewhere
737    -------------------------------------------------------------------------- */
739     NSTRACE (ns_flush);
743 static void
744 ns_focus (struct frame *f, NSRect *r, int n)
745 /* --------------------------------------------------------------------------
746    Internal: Focus on given frame.  During small local updates this is used to
747      draw, however during large updates, ns_update_begin and ns_update_end are
748      called to wrap the whole thing, in which case these calls are stubbed out.
749      Except, on GNUstep, we accumulate the rectangle being drawn into, because
750      the back end won't do this automatically, and will just end up flushing
751      the entire window.
752    -------------------------------------------------------------------------- */
754 //  NSTRACE (ns_focus);
755 #ifdef NS_IMPL_GNUSTEP
756   NSRect u;
757     if (n == 2)
758       u = NSUnionRect (r[0], r[1]);
759     else if (r)
760       u = *r;
761 #endif
762 /* static int c =0;
763    fprintf (stderr, "focus: %d", c++);
764    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
765    fprintf (stderr, "\n"); */
767   if (f != ns_updating_frame)
768     {
769       NSView *view = FRAME_NS_VIEW (f);
770       if (view != focus_view)
771         {
772           if (focus_view != NULL)
773             {
774               [focus_view unlockFocus];
775               [[focus_view window] flushWindow];
776 /*debug_lock--; */
777             }
779           if (view)
780 #ifdef NS_IMPL_GNUSTEP
781             r ? [view lockFocusInRect: u] : [view lockFocus];
782 #else
783             [view lockFocus];
784 #endif
785           focus_view = view;
786 /*if (view) debug_lock++; */
787         }
788 #ifdef NS_IMPL_GNUSTEP
789       else
790         {
791           /* more than one rect being drawn into */
792           if (view && r)
793             {
794               [view unlockFocus]; /* add prev rect to redraw list */
795               [view lockFocusInRect: u]; /* focus for draw in new rect */
796             }
797         }
798 #endif
799     }
800 #ifdef NS_IMPL_GNUSTEP
801   else
802     {
803       /* in batch mode, but in GNUstep must still track rectangles explicitly */
804       uRect = (r ? NSUnionRect (uRect, u) : [FRAME_NS_VIEW (f) visibleRect]);
805     }
806 #endif
808   /* clipping */
809   if (r)
810     {
811       [[NSGraphicsContext currentContext] saveGraphicsState];
812       if (n == 2)
813         NSRectClipList (r, 2);
814       else
815         NSRectClip (*r);
816       gsaved = YES;
817     }
821 static void
822 ns_unfocus (struct frame *f)
823 /* --------------------------------------------------------------------------
824      Internal: Remove focus on given frame
825    -------------------------------------------------------------------------- */
827 //  NSTRACE (ns_unfocus);
829   if (gsaved)
830     {
831       [[NSGraphicsContext currentContext] restoreGraphicsState];
832       gsaved = NO;
833     }
835   if (f != ns_updating_frame)
836     {
837       if (focus_view != NULL)
838         {
839           [focus_view unlockFocus];
840           [[focus_view window] flushWindow];
841           focus_view = NULL;
842 /*debug_lock--; */
843         }
844     }
848 static void
849 ns_clip_to_row (struct window *w, struct glyph_row *row, int area, BOOL gc)
850 /* --------------------------------------------------------------------------
851      Internal (but parallels other terms): Focus drawing on given row
852    -------------------------------------------------------------------------- */
854   struct frame *f = XFRAME (WINDOW_FRAME (w));
855   NSRect clip_rect;
856   int window_x, window_y, window_width;
858   window_box (w, area, &window_x, &window_y, &window_width, 0);
860   clip_rect.origin.x = window_x - FRAME_INTERNAL_BORDER_WIDTH (f);
861   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
862   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
863   clip_rect.size.width = window_width + 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
864   clip_rect.size.height = row->visible_height;
866   /* allow a full-height row at the top when requested
867      (used to draw fringe all the way through internal border area) */
868   if (gc && clip_rect.origin.y < 5)
869     {
870       clip_rect.origin.y -= FRAME_INTERNAL_BORDER_WIDTH (f);
871       clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
872     }
874   /* likewise at bottom */
875   if (gc &&
876       FRAME_PIXEL_HEIGHT (f) - (clip_rect.origin.y + clip_rect.size.height) < 5)
877     clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
879   ns_focus (f, &clip_rect, 1);
883 static void
884 ns_ring_bell (struct frame *f)
885 /* --------------------------------------------------------------------------
886      "Beep" routine
887    -------------------------------------------------------------------------- */
889   NSTRACE (ns_ring_bell);
890   if (visible_bell)
891     {
892       NSAutoreleasePool *pool;
893       struct frame *frame = SELECTED_FRAME ();
894       NSView *view;
896       BLOCK_INPUT;
897       pool = [[NSAutoreleasePool alloc] init];
899       view = FRAME_NS_VIEW (frame);
900       if (view != nil)
901         {
902           NSRect r, surr;
903           NSPoint dim = NSMakePoint (128, 128);
905           r = [view bounds];
906           r.origin.x += (r.size.width - dim.x) / 2;
907           r.origin.y += (r.size.height - dim.y) / 2;
908           r.size.width = dim.x;
909           r.size.height = dim.y;
910           surr = NSInsetRect (r, -2, -2);
911           ns_focus (frame, &surr, 1);
912           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
913           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
914                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
915           NSRectFill (r);
916           [[view window] flushWindow];
917           ns_timeout (150000);
918           [[view window] restoreCachedImage];
919           [[view window] flushWindow];
920           ns_unfocus (frame);
921         }
922       [pool release];
923       UNBLOCK_INPUT;
924     }
925   else
926     {
927       NSBeep ();
928     }
932 static void
933 ns_reset_terminal_modes (struct terminal *terminal)
934 /*  Externally called as hook */
936   NSTRACE (ns_reset_terminal_modes);
940 static void
941 ns_set_terminal_modes (struct terminal *terminal)
942 /*  Externally called as hook */
944   NSTRACE (ns_set_terminal_modes);
949 /* ==========================================================================
951     Frame / window manager related functions
953    ========================================================================== */
956 static void
957 ns_raise_frame (struct frame *f)
958 /* --------------------------------------------------------------------------
959      Bring window to foreground and make it active
960    -------------------------------------------------------------------------- */
962   NSView *view = FRAME_NS_VIEW (f);
963   check_ns ();
964   BLOCK_INPUT;
965   FRAME_SAMPLE_VISIBILITY (f);
966   if (FRAME_VISIBLE_P (f))
967     {
968       [[view window] makeKeyAndOrderFront: NSApp];
969     }
970   UNBLOCK_INPUT;
974 static void
975 ns_lower_frame (struct frame *f)
976 /* --------------------------------------------------------------------------
977      Send window to back
978    -------------------------------------------------------------------------- */
980   NSView *view = FRAME_NS_VIEW (f);
981   check_ns ();
982   BLOCK_INPUT;
983   [[view window] orderBack: NSApp];
984   UNBLOCK_INPUT;
988 static void
989 ns_frame_raise_lower (struct frame *f, int raise)
990 /* --------------------------------------------------------------------------
991      External (hook)
992    -------------------------------------------------------------------------- */
994   NSTRACE (ns_frame_raise_lower);
996   if (raise)
997     ns_raise_frame (f);
998   else
999     ns_lower_frame (f);
1003 static void
1004 ns_frame_rehighlight (struct frame *frame)
1005 /* --------------------------------------------------------------------------
1006      External (hook): called on things like window switching within frame
1007    -------------------------------------------------------------------------- */
1009   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
1010   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1012   NSTRACE (ns_frame_rehighlight);
1013   if (dpyinfo->x_focus_frame)
1014     {
1015       dpyinfo->x_highlight_frame
1016         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1017            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1018            : dpyinfo->x_focus_frame);
1019       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1020         {
1021           FSET (dpyinfo->x_focus_frame, focus_frame, Qnil);
1022           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1023         }
1024     }
1025   else
1026       dpyinfo->x_highlight_frame = 0;
1028   if (dpyinfo->x_highlight_frame &&
1029          dpyinfo->x_highlight_frame != old_highlight)
1030     {
1031       if (old_highlight)
1032         {
1033           x_update_cursor (old_highlight, 1);
1034           x_set_frame_alpha (old_highlight);
1035         }
1036       if (dpyinfo->x_highlight_frame)
1037         {
1038           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1039           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1040         }
1041     }
1045 void
1046 x_make_frame_visible (struct frame *f)
1047 /* --------------------------------------------------------------------------
1048      External: Show the window (X11 semantics)
1049    -------------------------------------------------------------------------- */
1051   NSTRACE (x_make_frame_visible);
1052   /* XXX: at some points in past this was not needed, as the only place that
1053      called this (frame.c:Fraise_frame ()) also called raise_lower;
1054      if this ends up the case again, comment this out again. */
1055   if (!FRAME_VISIBLE_P (f))
1056     {
1057       f->async_visible = 1;
1058       ns_raise_frame (f);
1059     }
1063 void
1064 x_make_frame_invisible (struct frame *f)
1065 /* --------------------------------------------------------------------------
1066      External: Hide the window (X11 semantics)
1067    -------------------------------------------------------------------------- */
1069   NSView * view = FRAME_NS_VIEW (f);
1070   NSTRACE (x_make_frame_invisible);
1071   check_ns ();
1072   [[view window] orderOut: NSApp];
1073   f->async_visible = 0;
1074   f->async_iconified = 0;
1078 void
1079 x_iconify_frame (struct frame *f)
1080 /* --------------------------------------------------------------------------
1081      External: Iconify window
1082    -------------------------------------------------------------------------- */
1084   NSView * view = FRAME_NS_VIEW (f);
1085   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1086   NSTRACE (x_iconify_frame);
1087   check_ns ();
1089   if (dpyinfo->x_highlight_frame == f)
1090     dpyinfo->x_highlight_frame = 0;
1092   if ([[view window] windowNumber] <= 0)
1093     {
1094       /* the window is still deferred.  Make it very small, bring it
1095          on screen and order it out. */
1096       NSRect s = { { 100, 100}, {0, 0} };
1097       NSRect t;
1098       t = [[view window] frame];
1099       [[view window] setFrame: s display: NO];
1100       [[view window] orderBack: NSApp];
1101       [[view window] orderOut: NSApp];
1102       [[view window] setFrame: t display: NO];
1103     }
1104   [[view window] miniaturize: NSApp];
1107 /* Free X resources of frame F.  */
1109 void
1110 x_free_frame_resources (struct frame *f)
1112   NSView *view = FRAME_NS_VIEW (f);
1113   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1114   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1115   NSTRACE (x_free_frame_resources);
1116   check_ns ();
1118   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1120   BLOCK_INPUT;
1122   free_frame_menubar (f);
1124   if (FRAME_FACE_CACHE (f))
1125     free_frame_faces (f);
1127   if (f == dpyinfo->x_focus_frame)
1128     dpyinfo->x_focus_frame = 0;
1129   if (f == dpyinfo->x_highlight_frame)
1130     dpyinfo->x_highlight_frame = 0;
1131   if (f == hlinfo->mouse_face_mouse_frame)
1132     {
1133       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
1134       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
1135       hlinfo->mouse_face_window = Qnil;
1136       hlinfo->mouse_face_deferred_gc = 0;
1137       hlinfo->mouse_face_mouse_frame = 0;
1138     }
1140   if (f->output_data.ns->miniimage != nil)
1141     [f->output_data.ns->miniimage release];
1143   [[view window] close];
1144   [view release];
1146   xfree (f->output_data.ns);
1148   UNBLOCK_INPUT;
1151 void
1152 x_destroy_window (struct frame *f)
1153 /* --------------------------------------------------------------------------
1154      External: Delete the window
1155    -------------------------------------------------------------------------- */
1157   NSTRACE (x_destroy_window);
1158   check_ns ();
1159   x_free_frame_resources (f);
1160   ns_window_num--;
1164 void
1165 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1166 /* --------------------------------------------------------------------------
1167      External: Position the window
1168    -------------------------------------------------------------------------- */
1170   NSView *view = FRAME_NS_VIEW (f);
1171   NSArray *screens = [NSScreen screens];
1172   NSScreen *fscreen = [screens objectAtIndex: 0];
1173   NSScreen *screen = [[view window] screen];
1175   NSTRACE (x_set_offset);
1177   BLOCK_INPUT;
1179   f->left_pos = xoff;
1180   f->top_pos = yoff;
1182   if (view != nil && screen && fscreen)
1183     {
1184       f->left_pos = f->size_hint_flags & XNegative
1185         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1186         : f->left_pos;
1187       /* We use visibleFrame here to take menu bar into account.
1188          Ideally we should also adjust left/top with visibleFrame.origin.  */
1190       f->top_pos = f->size_hint_flags & YNegative
1191         ? ([screen visibleFrame].size.height + f->top_pos
1192            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1193            - FRAME_TOOLBAR_HEIGHT (f))
1194         : f->top_pos;
1195 #ifdef NS_IMPL_GNUSTEP
1196       if (f->left_pos < 100)
1197         f->left_pos = 100;  /* don't overlap menu */
1198 #endif
1199       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1200          menu bar.  */
1201       f->output_data.ns->dont_constrain = 0;
1202       [[view window] setFrameTopLeftPoint:
1203                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1204                                     SCREENMAXBOUND ([fscreen frame].size.height
1205                                                     - NS_TOP_POS (f)))];
1206       f->size_hint_flags &= ~(XNegative|YNegative);
1207     }
1209   UNBLOCK_INPUT;
1213 void
1214 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1215 /* --------------------------------------------------------------------------
1216      Adjust window pixel size based on given character grid size
1217      Impl is a bit more complex than other terms, need to do some
1218      internal clipping.
1219    -------------------------------------------------------------------------- */
1221   EmacsView *view = FRAME_NS_VIEW (f);
1222   NSWindow *window = [view window];
1223   NSRect wr = [window frame];
1224   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1225   int pixelwidth, pixelheight;
1226   static int oldRows, oldCols, oldFontWidth, oldFontHeight;
1227   static int oldTB;
1228   static struct frame *oldF;
1230   NSTRACE (x_set_window_size);
1232   if (view == nil ||
1233       (f == oldF
1234        && rows == oldRows && cols == oldCols
1235        && oldFontWidth == FRAME_COLUMN_WIDTH (f)
1236        && oldFontHeight == FRAME_LINE_HEIGHT (f)
1237        && oldTB == tb))
1238     return;
1240 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1242   BLOCK_INPUT;
1244   check_frame_size (f, &rows, &cols);
1245   oldF = f;
1246   oldRows = rows;
1247   oldCols = cols;
1248   oldFontWidth = FRAME_COLUMN_WIDTH (f);
1249   oldFontHeight = FRAME_LINE_HEIGHT (f);
1250   oldTB = tb;
1252   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1253   compute_fringe_widths (f, 0);
1255   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1256   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1258   /* If we have a toolbar, take its height into account. */
1259   if (tb)
1260     /* NOTE: previously this would generate wrong result if toolbar not
1261              yet displayed and fixing toolbar_height=32 helped, but
1262              now (200903) seems no longer needed */
1263     FRAME_TOOLBAR_HEIGHT (f) =
1264       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1265         - FRAME_NS_TITLEBAR_HEIGHT (f);
1266   else
1267     FRAME_TOOLBAR_HEIGHT (f) = 0;
1269   wr.size.width = pixelwidth + f->border_width;
1270   wr.size.height = pixelheight + FRAME_NS_TITLEBAR_HEIGHT (f)
1271                   + FRAME_TOOLBAR_HEIGHT (f);
1273   /* Do not try to constrain to this screen.  We may have multiple
1274      screens, and want Emacs to span those.  Constraining to screen
1275      prevents that, and that is not nice to the user.  */
1276  if (f->output_data.ns->zooming)
1277    f->output_data.ns->zooming = 0;
1278  else
1279    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1281   [view setRows: rows andColumns: cols];
1282   [window setFrame: wr display: YES];
1284 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1286   /* This is a trick to compensate for Emacs' managing the scrollbar area
1287      as a fixed number of standard character columns.  Instead of leaving
1288      blank space for the extra, we chopped it off above.  Now for
1289      left-hand scrollbars, we shift all rendering to the left by the
1290      difference between the real width and Emacs' imagined one.  For
1291      right-hand bars, don't worry about it since the extra is never used.
1292      (Obviously doesn't work for vertically split windows tho..) */
1293   {
1294     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1295       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1296                      - NS_SCROLL_BAR_WIDTH (f), 0)
1297       : NSMakePoint (0, 0);
1298     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1299     [view setBoundsOrigin: origin];
1300   }
1302   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1303   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1304   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1305 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1307   mark_window_cursors_off (XWINDOW (f->root_window));
1308   cancel_mouse_face (f);
1310   UNBLOCK_INPUT;
1315 /* ==========================================================================
1317     Color management
1319    ========================================================================== */
1322 NSColor *
1323 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1325   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1326   if (idx < 1 || idx >= color_table->avail)
1327     return nil;
1328   return color_table->colors[idx];
1332 unsigned long
1333 ns_index_color (NSColor *color, struct frame *f)
1335   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1336   ptrdiff_t idx;
1337   ptrdiff_t i;
1339   if (!color_table->colors)
1340     {
1341       color_table->size = NS_COLOR_CAPACITY;
1342       color_table->avail = 1; /* skip idx=0 as marker */
1343       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1344       color_table->colors[0] = nil;
1345       color_table->empty_indices = [[NSMutableSet alloc] init];
1346     }
1348   /* do we already have this color ? */
1349   for (i = 1; i < color_table->avail; i++)
1350     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1351       return i;
1353   if ([color_table->empty_indices count] > 0)
1354     {
1355       NSNumber *index = [color_table->empty_indices anyObject];
1356       [color_table->empty_indices removeObject: index];
1357       idx = [index unsignedLongValue];
1358     }
1359   else
1360     {
1361       if (color_table->avail == color_table->size)
1362         color_table->colors =
1363           xpalloc (color_table->colors, &color_table->size, 1,
1364                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1365       idx = color_table->avail++;
1366     }
1368   color_table->colors[idx] = color;
1369   [color retain];
1370 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1371   return idx;
1375 void
1376 ns_free_indexed_color (unsigned long idx, struct frame *f)
1378   struct ns_color_table *color_table;
1379   NSColor *color;
1380   NSNumber *index;
1382   if (!f)
1383     return;
1385   color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1387   if (idx <= 0 || idx >= color_table->size) {
1388     message1 ("ns_free_indexed_color: Color index out of range.\n");
1389     return;
1390   }
1392   index = [NSNumber numberWithUnsignedInt: idx];
1393   if ([color_table->empty_indices containsObject: index]) {
1394     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1395     return;
1396   }
1398   color = color_table->colors[idx];
1399   [color release];
1400   color_table->colors[idx] = nil;
1401   [color_table->empty_indices addObject: index];
1402 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1406 static int
1407 ns_get_color (const char *name, NSColor **col)
1408 /* --------------------------------------------------------------------------
1409      Parse a color name
1410    -------------------------------------------------------------------------- */
1411 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1412    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1413    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1415   NSColor *new = nil;
1416   static char hex[20];
1417   int scaling;
1418   float r = -1.0, g, b;
1419   NSString *nsname = [NSString stringWithUTF8String: name];
1421 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1422   BLOCK_INPUT;
1424   if ([nsname isEqualToString: @"ns_selection_color"])
1425     {
1426       nsname = ns_selection_color;
1427       name = [ns_selection_color UTF8String];
1428     }
1430   /* First, check for some sort of numeric specification. */
1431   hex[0] = '\0';
1433   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1434     {
1435       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1436       [scanner scanFloat: &r];
1437       [scanner scanFloat: &g];
1438       [scanner scanFloat: &b];
1439     }
1440   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1441     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1442   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1443     {
1444       int len = (strlen(name) - 1);
1445       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1446       int i;
1447       scaling = strlen(name+start) / 3;
1448       for (i = 0; i < 3; i++)
1449         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1450                  name + start + i * scaling);
1451       hex[3 * (scaling + 1) - 1] = '\0';
1452     }
1454   if (hex[0])
1455     {
1456       int rr, gg, bb;
1457       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1458       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1459         {
1460           r = rr / fscale;
1461           g = gg / fscale;
1462           b = bb / fscale;
1463         }
1464     }
1466   if (r >= 0.0)
1467     {
1468       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1469       UNBLOCK_INPUT;
1470       return 0;
1471     }
1473   /* Otherwise, color is expected to be from a list */
1474   {
1475     NSEnumerator *lenum, *cenum;
1476     NSString *name;
1477     NSColorList *clist;
1479 #ifdef NS_IMPL_GNUSTEP
1480     /* XXX: who is wrong, the requestor or the implementation? */
1481     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1482         == NSOrderedSame)
1483       nsname = @"highlightColor";
1484 #endif
1486     lenum = [[NSColorList availableColorLists] objectEnumerator];
1487     while ( (clist = [lenum nextObject]) && new == nil)
1488       {
1489         cenum = [[clist allKeys] objectEnumerator];
1490         while ( (name = [cenum nextObject]) && new == nil )
1491           {
1492             if ([name compare: nsname
1493                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1494               new = [clist colorWithKey: name];
1495           }
1496       }
1497   }
1499   if (new)
1500     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1501   UNBLOCK_INPUT;
1502   return new ? 0 : 1;
1507 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1508 /* --------------------------------------------------------------------------
1509      Convert a Lisp string object to a NS color
1510    -------------------------------------------------------------------------- */
1512   NSTRACE (ns_lisp_to_color);
1513   if (STRINGP (color))
1514     return ns_get_color (SSDATA (color), col);
1515   else if (SYMBOLP (color))
1516     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1517   return 1;
1521 Lisp_Object
1522 ns_color_to_lisp (NSColor *col)
1523 /* --------------------------------------------------------------------------
1524      Convert a color to a lisp string with the RGB equivalent
1525    -------------------------------------------------------------------------- */
1527   CGFloat red, green, blue, alpha, gray;
1528   char buf[1024];
1529   const char *str;
1530   NSTRACE (ns_color_to_lisp);
1532   BLOCK_INPUT;
1533   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1535       if ((str =[[col colorNameComponent] UTF8String]))
1536         {
1537           UNBLOCK_INPUT;
1538           return build_string ((char *)str);
1539         }
1541     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1542         getRed: &red green: &green blue: &blue alpha: &alpha];
1543   if (red ==green && red ==blue)
1544     {
1545       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1546             getWhite: &gray alpha: &alpha];
1547       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1548                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1549       UNBLOCK_INPUT;
1550       return build_string (buf);
1551     }
1553   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1554             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1556   UNBLOCK_INPUT;
1557   return build_string (buf);
1561 void
1562 ns_query_color(void *col, XColor *color_def, int setPixel)
1563 /* --------------------------------------------------------------------------
1564          Get ARGB values out of NSColor col and put them into color_def.
1565          If setPixel, set the pixel to a concatenated version.
1566          and set color_def pixel to the resulting index.
1567    -------------------------------------------------------------------------- */
1569   CGFloat r, g, b, a;
1571   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1572   color_def->red   = r * 65535;
1573   color_def->green = g * 65535;
1574   color_def->blue  = b * 65535;
1576   if (setPixel == YES)
1577     color_def->pixel
1578       = ARGB_TO_ULONG((int)(a*255),
1579                       (int)(r*255), (int)(g*255), (int)(b*255));
1584 ns_defined_color (struct frame *f,
1585                   const char *name,
1586                   XColor *color_def,
1587                   int alloc,
1588                   char makeIndex)
1589 /* --------------------------------------------------------------------------
1590          Return 1 if named color found, and set color_def rgb accordingly.
1591          If makeIndex and alloc are nonzero put the color in the color_table,
1592          and set color_def pixel to the resulting index.
1593          If makeIndex is zero, set color_def pixel to ARGB.
1594          Return 0 if not found
1595    -------------------------------------------------------------------------- */
1597   NSColor *col;
1598   NSTRACE (ns_defined_color);
1600   BLOCK_INPUT;
1601   if (ns_get_color (name, &col) != 0) /* Color not found  */
1602     {
1603       UNBLOCK_INPUT;
1604       return 0;
1605     }
1606   if (makeIndex && alloc)
1607     color_def->pixel = ns_index_color (col, f);
1608   ns_query_color (col, color_def, !makeIndex);
1609   UNBLOCK_INPUT;
1610   return 1;
1614 unsigned long
1615 ns_get_rgb_color (struct frame *f, float r, float g, float b, float a)
1616 /* --------------------------------------------------------------------------
1617     return an autoreleased RGB color
1618    -------------------------------------------------------------------------- */
1620 /*static int c = 1; fprintf (stderr, "color request %d\n", c++); */
1621   if (r < 0.0) r = 0.0;
1622   else if (r > 1.0) r = 1.0;
1623   if (g < 0.0) g = 0.0;
1624   else if (g > 1.0) g = 1.0;
1625   if (b < 0.0) b = 0.0;
1626   else if (b > 1.0) b = 1.0;
1627   if (a < 0.0) a = 0.0;
1628   else if (a > 1.0) a = 1.0;
1629   return (unsigned long) ns_index_color(
1630     [NSColor colorWithCalibratedRed: r green: g blue: b alpha: a], f);
1634 void
1635 x_set_frame_alpha (struct frame *f)
1636 /* --------------------------------------------------------------------------
1637      change the entire-frame transparency
1638    -------------------------------------------------------------------------- */
1640   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1641   EmacsView *view = FRAME_NS_VIEW (f);
1642   double alpha = 1.0;
1643   double alpha_min = 1.0;
1645   if (dpyinfo->x_highlight_frame == f)
1646     alpha = f->alpha[0];
1647   else
1648     alpha = f->alpha[1];
1650   if (FLOATP (Vframe_alpha_lower_limit))
1651     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1652   else if (INTEGERP (Vframe_alpha_lower_limit))
1653     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1655   if (alpha < 0.0)
1656     return;
1657   else if (1.0 < alpha)
1658     alpha = 1.0;
1659   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1660     alpha = alpha_min;
1662 #ifdef NS_IMPL_COCOA
1663   [[view window] setAlphaValue: alpha];
1664 #endif
1668 /* ==========================================================================
1670     Mouse handling
1672    ========================================================================== */
1675 void
1676 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1677 /* --------------------------------------------------------------------------
1678      Programmatically reposition mouse pointer in pixel coordinates
1679    -------------------------------------------------------------------------- */
1681   NSTRACE (x_set_mouse_pixel_position);
1682   ns_raise_frame (f);
1683 #if 0
1684   /* FIXME: this does not work, and what about GNUstep? */
1685 #ifdef NS_IMPL_COCOA
1686   [FRAME_NS_VIEW (f) lockFocus];
1687   PSsetmouse ((float)pix_x, (float)pix_y);
1688   [FRAME_NS_VIEW (f) unlockFocus];
1689 #endif
1690 #endif
1694 void
1695 x_set_mouse_position (struct frame *f, int h, int v)
1696 /* --------------------------------------------------------------------------
1697      Programmatically reposition mouse pointer in character coordinates
1698    -------------------------------------------------------------------------- */
1700   int pix_x, pix_y;
1702   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1703   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1705   if (pix_x < 0) pix_x = 0;
1706   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1708   if (pix_y < 0) pix_y = 0;
1709   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1711   x_set_mouse_pixel_position (f, pix_x, pix_y);
1715 static int
1716 note_mouse_movement (struct frame *frame, float x, float y)
1717 /*   ------------------------------------------------------------------------
1718      Called by EmacsView on mouseMovement events.  Passes on
1719      to emacs mainstream code if we moved off of a rect of interest
1720      known as last_mouse_glyph.
1721      ------------------------------------------------------------------------ */
1723 //  NSTRACE (note_mouse_movement);
1725   XSETFRAME (last_mouse_motion_frame, frame);
1727   /* Note, this doesn't get called for enter/leave, since we don't have a
1728      position.  Those are taken care of in the corresponding NSView methods. */
1730   /* has movement gone beyond last rect we were tracking? */
1731   if (x < last_mouse_glyph.origin.x ||
1732       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1733       y < last_mouse_glyph.origin.y ||
1734       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1735     {
1736       ns_update_begin(frame);
1737       frame->mouse_moved = 1;
1738       note_mouse_highlight (frame, x, y);
1739       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1740       ns_update_end(frame);
1741       return 1;
1742     }
1744   return 0;
1748 static void
1749 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1750                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1751                    Time *time)
1752 /* --------------------------------------------------------------------------
1753     External (hook): inform emacs about mouse position and hit parts.
1754     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1755     x & y should be position in the scrollbar (the whole bar, not the handle)
1756     and length of scrollbar respectively
1757    -------------------------------------------------------------------------- */
1759   id view;
1760   NSPoint position;
1761   Lisp_Object frame, tail;
1762   struct frame *f;
1763   struct ns_display_info *dpyinfo;
1765   NSTRACE (ns_mouse_position);
1767   if (*fp == NULL)
1768     {
1769       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1770       return;
1771     }
1773   dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1775   BLOCK_INPUT;
1777   if (last_mouse_scroll_bar != nil && insist == 0)
1778     {
1779       /* TODO: we do not use this path at the moment because drag events will
1780            go directly to the EmacsScroller.  Leaving code in for now. */
1781       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1782                                               x: x y: y];
1783       if (time) *time = last_mouse_movement_time;
1784       last_mouse_scroll_bar = nil;
1785     }
1786   else
1787     {
1788       /* Clear the mouse-moved flag for every frame on this display.  */
1789       FOR_EACH_FRAME (tail, frame)
1790         if (FRAME_NS_P (XFRAME (frame))
1791             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1792           XFRAME (frame)->mouse_moved = 0;
1794       last_mouse_scroll_bar = nil;
1795       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1796         f = last_mouse_frame;
1797       else
1798         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1799                                     : SELECTED_FRAME ();
1801       if (f && f->output_data.ns)  /* TODO: 2nd check no longer needed? */
1802         {
1803           view = FRAME_NS_VIEW (*fp);
1805           position = [[view window] mouseLocationOutsideOfEventStream];
1806           position = [view convertPoint: position fromView: nil];
1807           remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1808 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1810           if (bar_window) *bar_window = Qnil;
1811           if (part) *part = 0; /*scroll_bar_handle; */
1813           if (x) XSETINT (*x, lrint (position.x));
1814           if (y) XSETINT (*y, lrint (position.y));
1815           if (time) *time = last_mouse_movement_time;
1816           *fp = f;
1817         }
1818     }
1820   UNBLOCK_INPUT;
1824 static void
1825 ns_frame_up_to_date (struct frame *f)
1826 /* --------------------------------------------------------------------------
1827     External (hook): Fix up mouse highlighting right after a full update.
1828     Some highlighting was deferred if GC was happening during
1829     note_mouse_highlight (), while other highlighting was deferred for update.
1830    -------------------------------------------------------------------------- */
1832   NSTRACE (ns_frame_up_to_date);
1834   if (FRAME_NS_P (f))
1835     {
1836       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1837       if ((hlinfo->mouse_face_deferred_gc || f ==hlinfo->mouse_face_mouse_frame)
1838       /*&& hlinfo->mouse_face_mouse_frame*/)
1839         {
1840           BLOCK_INPUT;
1841           ns_update_begin(f);
1842           if (hlinfo->mouse_face_mouse_frame)
1843             note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1844                                   hlinfo->mouse_face_mouse_x,
1845                                   hlinfo->mouse_face_mouse_y);
1846           hlinfo->mouse_face_deferred_gc = 0;
1847           ns_update_end(f);
1848           UNBLOCK_INPUT;
1849         }
1850     }
1854 static void
1855 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1856 /* --------------------------------------------------------------------------
1857     External (RIF): set frame mouse pointer type.
1858    -------------------------------------------------------------------------- */
1860   NSTRACE (ns_define_frame_cursor);
1861   if (FRAME_POINTER_TYPE (f) != cursor)
1862     {
1863       EmacsView *view = FRAME_NS_VIEW (f);
1864       FRAME_POINTER_TYPE (f) = cursor;
1865       [[view window] invalidateCursorRectsForView: view];
1866       /* Redisplay assumes this function also draws the changed frame
1867          cursor, but this function doesn't, so do it explicitly.  */
1868       x_update_cursor (f, 1);
1869     }
1874 /* ==========================================================================
1876     Keyboard handling
1878    ========================================================================== */
1881 static unsigned
1882 ns_convert_key (unsigned code)
1883 /* --------------------------------------------------------------------------
1884     Internal call used by NSView-keyDown.
1885    -------------------------------------------------------------------------- */
1887   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1888                                 / sizeof (convert_ns_to_X_keysym[0]));
1889   unsigned keysym;
1890   /* An array would be faster, but less easy to read. */
1891   for (keysym = 0; keysym < last_keysym; keysym += 2)
1892     if (code == convert_ns_to_X_keysym[keysym])
1893       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1894   return 0;
1895 /* if decide to use keyCode and Carbon table, use this line:
1896      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1900 char *
1901 x_get_keysym_name (int keysym)
1902 /* --------------------------------------------------------------------------
1903     Called by keyboard.c.  Not sure if the return val is important, except
1904     that it be unique.
1905    -------------------------------------------------------------------------- */
1907   static char value[16];
1908   NSTRACE (x_get_keysym_name);
1909   sprintf (value, "%d", keysym);
1910   return value;
1915 /* ==========================================================================
1917     Block drawing operations
1919    ========================================================================== */
1922 static void
1923 ns_redraw_scroll_bars (struct frame *f)
1925   int i;
1926   id view;
1927   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1928   NSTRACE (ns_judge_scroll_bars);
1929   for (i =[subviews count]-1; i >= 0; i--)
1930     {
1931       view = [subviews objectAtIndex: i];
1932       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1933       [view display];
1934     }
1938 void
1939 ns_clear_frame (struct frame *f)
1940 /* --------------------------------------------------------------------------
1941       External (hook): Erase the entire frame
1942    -------------------------------------------------------------------------- */
1944   NSView *view = FRAME_NS_VIEW (f);
1945   NSRect r;
1947   NSTRACE (ns_clear_frame);
1948   if (ns_in_resize)
1949     return;
1951  /* comes on initial frame because we have
1952     after-make-frame-functions = select-frame */
1953  if (!FRAME_DEFAULT_FACE (f))
1954    return;
1956   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
1958   output_cursor.hpos = output_cursor.vpos = 0;
1959   output_cursor.x = -1;
1961   r = [view bounds];
1963   BLOCK_INPUT;
1964   ns_focus (f, &r, 1);
1965   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
1966   NSRectFill (r);
1967   ns_unfocus (f);
1969 #ifdef NS_IMPL_COCOA
1970   [[view window] display];  /* redraw resize handle */
1971 #endif
1973   /* as of 2006/11 or so this is now needed */
1974   ns_redraw_scroll_bars (f);
1975   UNBLOCK_INPUT;
1979 static void
1980 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
1981 /* --------------------------------------------------------------------------
1982     External (RIF):  Clear section of frame
1983    -------------------------------------------------------------------------- */
1985   NSRect r = NSMakeRect (x, y, width, height);
1986   NSView *view = FRAME_NS_VIEW (f);
1987   struct face *face = FRAME_DEFAULT_FACE (f);
1989   if (!view || !face)
1990     return;
1992   NSTRACE (ns_clear_frame_area);
1994   r = NSIntersectionRect (r, [view frame]);
1995   ns_focus (f, &r, 1);
1996   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
1998 #ifdef NS_IMPL_COCOA
1999   {
2000     /* clip out the resize handle */
2001     NSWindow *window = [FRAME_NS_VIEW (f) window];
2002     NSRect ir
2003       = [view convertRect: ns_resize_handle_rect (window) fromView: nil];
2005     ir = NSIntersectionRect (r, ir);
2006     if (NSIsEmptyRect (ir))
2007       {
2008 #endif
2010   NSRectFill (r);
2012 #ifdef NS_IMPL_COCOA
2013       }
2014     else
2015       {
2016         NSRect r1 = r, r2 = r; /* upper and lower non-intersecting */
2017         r1.size.height -= ir.size.height;
2018         r2.origin.y += r1.size.height;
2019         r2.size.width -= ir.size.width;
2020         r2.size.height = ir.size.height;
2021         NSRectFill (r1);
2022         NSRectFill (r2);
2023       }
2024   }
2025 #endif
2027   ns_unfocus (f);
2028   return;
2032 static void
2033 ns_scroll_run (struct window *w, struct run *run)
2034 /* --------------------------------------------------------------------------
2035     External (RIF):  Insert or delete n lines at line vpos
2036    -------------------------------------------------------------------------- */
2038   struct frame *f = XFRAME (w->frame);
2039   int x, y, width, height, from_y, to_y, bottom_y;
2041   NSTRACE (ns_scroll_run);
2043   /* begin copy from other terms */
2044   /* Get frame-relative bounding box of the text display area of W,
2045      without mode lines.  Include in this box the left and right
2046      fringe of W.  */
2047   window_box (w, -1, &x, &y, &width, &height);
2049   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2050   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2051   bottom_y = y + height;
2053   if (to_y < from_y)
2054     {
2055       /* Scrolling up.  Make sure we don't copy part of the mode
2056          line at the bottom.  */
2057       if (from_y + run->height > bottom_y)
2058         height = bottom_y - from_y;
2059       else
2060         height = run->height;
2061     }
2062   else
2063     {
2064       /* Scrolling down.  Make sure we don't copy over the mode line.
2065          at the bottom.  */
2066       if (to_y + run->height > bottom_y)
2067         height = bottom_y - to_y;
2068       else
2069         height = run->height;
2070     }
2071   /* end copy from other terms */
2073   if (height == 0)
2074       return;
2076   BLOCK_INPUT;
2078   updated_window = w;
2079   x_clear_cursor (w);
2081   {
2082     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2083     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2084     NSPoint dstOrigin = NSMakePoint (x, to_y);
2086     ns_focus (f, &dstRect, 1);
2087     NSCopyBits (0, srcRect , dstOrigin);
2088     ns_unfocus (f);
2089   }
2091   UNBLOCK_INPUT;
2095 static void
2096 ns_after_update_window_line (struct glyph_row *desired_row)
2097 /* --------------------------------------------------------------------------
2098     External (RIF): preparatory to fringe update after text was updated
2099    -------------------------------------------------------------------------- */
2101   struct window *w = updated_window;
2102   struct frame *f;
2103   int width, height;
2105   NSTRACE (ns_after_update_window_line);
2107   /* begin copy from other terms */
2108   eassert (w);
2110   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2111     desired_row->redraw_fringe_bitmaps_p = 1;
2113   /* When a window has disappeared, make sure that no rest of
2114      full-width rows stays visible in the internal border.
2115      Under NS this is drawn inside the fringes. */
2116   if (windows_or_buffers_changed
2117       && (f = XFRAME (w->frame),
2118           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2119           width != 0)
2120       && (height = desired_row->visible_height,
2121           height > 0))
2122     {
2123       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2125       /* Internal border is drawn below the tool bar.  */
2126       if (WINDOWP (f->tool_bar_window)
2127           && w == XWINDOW (f->tool_bar_window))
2128         y -= width;
2129       /* end copy from other terms */
2131       BLOCK_INPUT;
2132       if (!desired_row->full_width_p)
2133         {
2134           int x1 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2135             + WINDOW_LEFT_FRINGE_WIDTH (w);
2136           int x2 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2137             + FRAME_PIXEL_WIDTH (f) - NS_SCROLL_BAR_WIDTH (f)
2138             - WINDOW_RIGHT_FRINGE_WIDTH (w)
2139             - FRAME_INTERNAL_BORDER_WIDTH (f);
2140           ns_clear_frame_area (f, x1, y, width, height);
2141           ns_clear_frame_area (f, x2, y, width, height);
2142         }
2143       UNBLOCK_INPUT;
2144     }
2148 static void
2149 ns_shift_glyphs_for_insert (struct frame *f,
2150                            int x, int y, int width, int height,
2151                            int shift_by)
2152 /* --------------------------------------------------------------------------
2153     External (RIF): copy an area horizontally, don't worry about clearing src
2154    -------------------------------------------------------------------------- */
2156   NSRect srcRect = NSMakeRect (x, y, width, height);
2157   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2158   NSPoint dstOrigin = dstRect.origin;
2160   NSTRACE (ns_shift_glyphs_for_insert);
2162   ns_focus (f, &dstRect, 1);
2163   NSCopyBits (0, srcRect, dstOrigin);
2164   ns_unfocus (f);
2169 /* ==========================================================================
2171     Character encoding and metrics
2173    ========================================================================== */
2176 static inline void
2177 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2178 /* --------------------------------------------------------------------------
2179      External (RIF); compute left/right overhang of whole string and set in s
2180    -------------------------------------------------------------------------- */
2182   struct font *font = s->font;
2184   if (s->char2b)
2185     {
2186       struct font_metrics metrics;
2187       unsigned int codes[2];
2188       codes[0] = *(s->char2b);
2189       codes[1] = *(s->char2b + s->nchars - 1);
2191       font->driver->text_extents (font, codes, 2, &metrics);
2192       s->left_overhang = -metrics.lbearing;
2193       s->right_overhang
2194         = metrics.rbearing > metrics.width
2195         ? metrics.rbearing - metrics.width : 0;
2196     }
2197   else
2198     {
2199       s->left_overhang = 0;
2200       s->right_overhang = ((struct nsfont_info *)font)->ital ?
2201         FONT_HEIGHT (font) * 0.2 : 0;
2202     }
2207 /* ==========================================================================
2209     Fringe and cursor drawing
2211    ========================================================================== */
2214 extern int max_used_fringe_bitmap;
2215 static void
2216 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2217                       struct draw_fringe_bitmap_params *p)
2218 /* --------------------------------------------------------------------------
2219     External (RIF); fringe-related
2220    -------------------------------------------------------------------------- */
2222   struct frame *f = XFRAME (WINDOW_FRAME (w));
2223   struct face *face = p->face;
2224   int rowY;
2225   static EmacsImage **bimgs = NULL;
2226   static int nBimgs = 0;
2227   /* NS-specific: move internal border inside fringe */
2228   int x = p->bx < 0 ? p->x : p->bx;
2229   int wd = p->bx < 0 ? p->wd : p->nx;
2230   BOOL fringeOnVeryLeft
2231     = x - WINDOW_LEFT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w)
2232       - FRAME_INTERNAL_BORDER_WIDTH (f) < 10;
2233   BOOL fringeOnVeryRight
2234     = FRAME_PIXEL_WIDTH (f) - x - wd - FRAME_INTERNAL_BORDER_WIDTH (f)
2235       - WINDOW_RIGHT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w) < 10;
2236   int xAdjust = FRAME_INTERNAL_BORDER_WIDTH (f) *
2237     (fringeOnVeryLeft ? -1 : (fringeOnVeryRight ? 1 : 0));
2239   /* grow bimgs if needed */
2240   if (nBimgs < max_used_fringe_bitmap)
2241     {
2242       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2243       memset (bimgs + nBimgs, 0,
2244               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2245       nBimgs = max_used_fringe_bitmap;
2246     }
2248   /* Must clip because of partially visible lines.  */
2249   rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2250   ns_clip_to_row (w, row, -1, YES);
2252   if (p->bx >= 0 && !p->overlay_p)
2253     {
2254       int yAdjust = rowY - FRAME_INTERNAL_BORDER_WIDTH (f) < 5 ?
2255         -FRAME_INTERNAL_BORDER_WIDTH (f) : 0;
2256       int yIncr = FRAME_PIXEL_HEIGHT (f) - (p->by+yAdjust + p->ny) < 5 ?
2257         FRAME_INTERNAL_BORDER_WIDTH (f) : 0
2258         + (yAdjust ? FRAME_INTERNAL_BORDER_WIDTH (f) : 0);
2259       NSRect r = NSMakeRect (p->bx+xAdjust, p->by+yAdjust, p->nx, p->ny+yIncr);
2260       NSRectClip (r);
2261       [ns_lookup_indexed_color(face->background, f) set];
2262       NSRectFill (r);
2263     }
2265   if (p->which)
2266     {
2267       NSRect r = NSMakeRect (p->x+xAdjust, p->y, p->wd, p->h);
2268       EmacsImage *img = bimgs[p->which - 1];
2270       if (!img)
2271         {
2272           unsigned short *bits = p->bits + p->dh;
2273           int len = p->h;
2274           int i;
2275           unsigned char *cbits = xmalloc (len);
2277           for (i =0; i<len; i++)
2278             cbits[i] = ~(bits[i] & 0xff);
2279           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2280                                            flip: NO];
2281           bimgs[p->which - 1] = img;
2282           xfree (cbits);
2283         }
2285       NSRectClip (r);
2286       /* Since we composite the bitmap instead of just blitting it, we need
2287          to erase the whole background. */
2288       [ns_lookup_indexed_color(face->background, f) set];
2289       NSRectFill (r);
2290       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2291       [img drawInRect: r
2292               fromRect: NSZeroRect
2293              operation: NSCompositeSourceOver
2294               fraction: 1.0
2295            respectFlipped: YES
2296                 hints: nil];
2297     }
2298   ns_unfocus (f);
2302 static void
2303 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2304                        int x, int y, int cursor_type, int cursor_width,
2305                        int on_p, int active_p)
2306 /* --------------------------------------------------------------------------
2307      External call (RIF): draw cursor.
2308      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2309    -------------------------------------------------------------------------- */
2311   NSRect r, s;
2312   int fx, fy, h, cursor_height;
2313   struct frame *f = WINDOW_XFRAME (w);
2314   struct glyph *phys_cursor_glyph;
2315   int overspill;
2316   struct glyph *cursor_glyph;
2317   struct face *face;
2318   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2320   /* If cursor is out of bounds, don't draw garbage.  This can happen
2321      in mini-buffer windows when switching between echo area glyphs
2322      and mini-buffer.  */
2324   NSTRACE (dumpcursor);
2326   if (!on_p)
2327     return;
2329   w->phys_cursor_type = cursor_type;
2330   w->phys_cursor_on_p = on_p;
2332   if (cursor_type == NO_CURSOR)
2333     {
2334       w->phys_cursor_width = 0;
2335       return;
2336     }
2338   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2339     {
2340       if (glyph_row->exact_window_width_line_p
2341           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2342         {
2343           glyph_row->cursor_in_fringe_p = 1;
2344           draw_fringe_bitmap (w, glyph_row, 0);
2345         }
2346       return;
2347     }
2349   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2350      (other terminals do it the other way round).  We must set
2351      w->phys_cursor_width to the cursor width.  For bar cursors, that
2352      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2353   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2355   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2356      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2357   if (cursor_type == BAR_CURSOR)
2358     {
2359       if (cursor_width < 1)
2360         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2361       w->phys_cursor_width = cursor_width;
2362     }
2363   /* If we have an HBAR, "cursor_width" MAY specify height. */
2364   else if (cursor_type == HBAR_CURSOR)
2365     {
2366       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2367       fy += h - cursor_height;
2368       h = cursor_height;
2369     }
2371   r.origin.x = fx, r.origin.y = fy;
2372   r.size.height = h;
2373   r.size.width = w->phys_cursor_width;
2375   /* FIXME: if we overwrite the internal border area, it does not get erased;
2376      fix by truncating cursor, but better would be to erase properly */
2377   overspill = r.origin.x + r.size.width -
2378     WINDOW_TEXT_TO_FRAME_PIXEL_X (w, WINDOW_BOX_RIGHT_EDGE_X (w)
2379       - WINDOW_TOTAL_FRINGE_WIDTH (w) - FRAME_INTERNAL_BORDER_WIDTH (f));
2380   if (overspill > 0)
2381     r.size.width -= overspill;
2383   /* TODO: only needed in rare cases with last-resort font in HELLO..
2384      should we do this more efficiently? */
2385   ns_clip_to_row (w, glyph_row, -1, NO); /* do ns_focus(f, &r, 1); if remove */
2388   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2389   if (face && NS_FACE_BACKGROUND (face)
2390       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2391     {
2392       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2393       hollow_color = FRAME_CURSOR_COLOR (f);
2394     }
2395   else
2396     [FRAME_CURSOR_COLOR (f) set];
2398 #ifdef NS_IMPL_COCOA
2399   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2400            atomic.  Cleaner ways of doing this should be investigated.
2401            One way would be to set a global variable DRAWING_CURSOR
2402            when making the call to draw_phys..(), don't focus in that
2403            case, then move the ns_unfocus() here after that call. */
2404   NSDisableScreenUpdates ();
2405 #endif
2407   switch (cursor_type)
2408     {
2409     case NO_CURSOR:
2410       break;
2411     case FILLED_BOX_CURSOR:
2412       NSRectFill (r);
2413       break;
2414     case HOLLOW_BOX_CURSOR:
2415       NSRectFill (r);
2416       [hollow_color set];
2417       NSRectFill (NSInsetRect (r, 1, 1));
2418       [FRAME_CURSOR_COLOR (f) set];
2419       break;
2420     case HBAR_CURSOR:
2421       NSRectFill (r);
2422       break;
2423     case BAR_CURSOR:
2424       s = r;
2425       /* If the character under cursor is R2L, draw the bar cursor
2426          on the right of its glyph, rather than on the left.  */
2427       cursor_glyph = get_phys_cursor_glyph (w);
2428       if ((cursor_glyph->resolved_level & 1) != 0)
2429         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2431       NSRectFill (s);
2432       break;
2433     }
2434   ns_unfocus (f);
2436   /* draw the character under the cursor */
2437   if (cursor_type != NO_CURSOR)
2438     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2440 #ifdef NS_IMPL_COCOA
2441   NSEnableScreenUpdates ();
2442 #endif
2447 static void
2448 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2449 /* --------------------------------------------------------------------------
2450      External (RIF): Draw a vertical line.
2451    -------------------------------------------------------------------------- */
2453   struct frame *f = XFRAME (WINDOW_FRAME (w));
2454   struct face *face;
2455   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2457   NSTRACE (ns_draw_vertical_window_border);
2459   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2460   if (face)
2461       [ns_lookup_indexed_color(face->foreground, f) set];
2463   ns_focus (f, &r, 1);
2464   NSRectFill(r);
2465   ns_unfocus (f);
2469 void
2470 show_hourglass (struct atimer *timer)
2472   if (hourglass_shown_p)
2473     return;
2475   BLOCK_INPUT;
2477   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2479   hourglass_shown_p = 1;
2480   UNBLOCK_INPUT;
2484 void
2485 hide_hourglass (void)
2487   if (!hourglass_shown_p)
2488     return;
2490   BLOCK_INPUT;
2492   /* TODO: remove NSProgressIndicator from all frames */
2494   hourglass_shown_p = 0;
2495   UNBLOCK_INPUT;
2500 /* ==========================================================================
2502     Glyph drawing operations
2504    ========================================================================== */
2507 static inline NSRect
2508 ns_fix_rect_ibw (NSRect r, int fibw, int frame_pixel_width)
2509 /* --------------------------------------------------------------------------
2510     Under NS we draw internal borders inside fringes, and want full-width
2511     rendering to go all the way to edge.  This function makes that correction.
2512    -------------------------------------------------------------------------- */
2514   if (r.origin.y <= fibw+1)
2515     {
2516       r.size.height += r.origin.y;
2517       r.origin.y = 0;
2518     }
2519   if (r.origin.x <= fibw+1)
2520     {
2521       r.size.width += r.origin.x;
2522       r.origin.x = 0;
2523     }
2524   if (frame_pixel_width - (r.origin.x+r.size.width) <= fibw+1)
2525     r.size.width += fibw;
2527   return r;
2531 static int
2532 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2533 /* --------------------------------------------------------------------------
2534     Wrapper utility to account for internal border width on full-width lines,
2535     and allow top full-width rows to hit the frame top.  nr should be pointer
2536     to two successive NSRects.  Number of rects actually used is returned.
2537    -------------------------------------------------------------------------- */
2539   int n = get_glyph_string_clip_rects (s, nr, 2);
2540   if (s->row->full_width_p)
2541     {
2542       *nr = ns_fix_rect_ibw (*nr, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2543                             FRAME_PIXEL_WIDTH (s->f));
2544       if (n == 2)
2545         *nr = ns_fix_rect_ibw (*(nr+1), FRAME_INTERNAL_BORDER_WIDTH (s->f),
2546                               FRAME_PIXEL_WIDTH (s->f));
2547     }
2548   return n;
2551 /* --------------------------------------------------------------------
2552    Draw a wavy line under glyph string s. The wave fills wave_height
2553    pixels from y.
2555                     x          wave_length = 3
2556                                  --
2557                 y    *   *   *   *   *
2558                      |* * * * * * * * *
2559     wave_height = 3  | *   *   *   *
2560   --------------------------------------------------------------------- */
2562 static void
2563 ns_draw_underwave (struct glyph_string *s, CGFloat width, CGFloat x)
2565   int wave_height = 3, wave_length = 3;
2566   int y, dx, dy, odd, xmax;
2567   NSPoint a, b;
2568   NSRect waveClip;
2570   dx = wave_length;
2571   dy = wave_height - 1;
2572   y =  s->ybase + 1;
2573   xmax = x + width;
2575   /* Find and set clipping rectangle */
2576   waveClip = NSMakeRect (x, y, width, wave_height);
2577   [[NSGraphicsContext currentContext] saveGraphicsState];
2578   NSRectClip (waveClip);
2580   /* Draw the waves */
2581   a.x = x - ((int)(x) % dx);
2582   b.x = a.x + dx;
2583   odd = (int)(a.x/dx) % 2;
2584   a.y = b.y = y;
2586   if (odd)
2587     a.y += dy;
2588   else
2589     b.y += dy;
2591   while (a.x <= xmax)
2592     {
2593       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2594       a.x = b.x, a.y = b.y;
2595       b.x += dx, b.y = y + odd*dy;
2596       odd = !odd;
2597     }
2599   /* Restore previous clipping rectangle(s) */
2600   [[NSGraphicsContext currentContext] restoreGraphicsState];
2605 void
2606 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2607                          NSColor *defaultCol, CGFloat width, CGFloat x)
2608 /* --------------------------------------------------------------------------
2609    Draw underline, overline, and strike-through on glyph string s.
2610    -------------------------------------------------------------------------- */
2612   if (s->for_overlaps)
2613     return;
2615   /* Do underline. */
2616   if (face->underline_p)
2617     {
2618       if (s->face->underline_type == FACE_UNDER_WAVE)
2619         {
2620           if (face->underline_defaulted_p)
2621             [defaultCol set];
2622           else
2623             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2625           ns_draw_underwave (s, width, x);
2626         }
2627       else if (s->face->underline_type == FACE_UNDER_LINE)
2628         {
2630           NSRect r;
2631           unsigned long thickness, position;
2633           /* If the prev was underlined, match its appearance. */
2634           if (s->prev && s->prev->face->underline_p
2635               && s->prev->underline_thickness > 0)
2636             {
2637               thickness = s->prev->underline_thickness;
2638               position = s->prev->underline_position;
2639             }
2640           else
2641             {
2642               struct font *font;
2643               unsigned long descent;
2645               font=s->font;
2646               descent = s->y + s->height - s->ybase;
2648               /* Use underline thickness of font, defaulting to 1. */
2649               thickness = (font && font->underline_thickness > 0)
2650                 ? font->underline_thickness : 1;
2652               /* Determine the offset of underlining from the baseline. */
2653               if (x_underline_at_descent_line)
2654                 position = descent - thickness;
2655               else if (x_use_underline_position_properties
2656                        && font && font->underline_position >= 0)
2657                 position = font->underline_position;
2658               else if (font)
2659                 position = lround (font->descent / 2);
2660               else
2661                 position = underline_minimum_offset;
2663               position = max (position, underline_minimum_offset);
2665               /* Ensure underlining is not cropped. */
2666               if (descent <= position)
2667                 {
2668                   position = descent - 1;
2669                   thickness = 1;
2670                 }
2671               else if (descent < position + thickness)
2672                 thickness = 1;
2673             }
2675           s->underline_thickness = thickness;
2676           s->underline_position = position;
2678           r = NSMakeRect (x, s->ybase + position, width, thickness);
2680           if (face->underline_defaulted_p)
2681             [defaultCol set];
2682           else
2683             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2684           NSRectFill (r);
2685         }
2686     }
2687   /* Do overline. We follow other terms in using a thickness of 1
2688      and ignoring overline_margin. */
2689   if (face->overline_p)
2690     {
2691       NSRect r;
2692       r = NSMakeRect (x, s->y, width, 1);
2694       if (face->overline_color_defaulted_p)
2695         [defaultCol set];
2696       else
2697         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2698       NSRectFill (r);
2699     }
2701   /* Do strike-through.  We follow other terms for thickness and
2702      vertical position.*/
2703   if (face->strike_through_p)
2704     {
2705       NSRect r;
2706       unsigned long dy;
2708       dy = lrint ((s->height - 1) / 2);
2709       r = NSMakeRect (x, s->y + dy, width, 1);
2711       if (face->strike_through_color_defaulted_p)
2712         [defaultCol set];
2713       else
2714         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2715       NSRectFill (r);
2716     }
2719 static void
2720 ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char right_p)
2721 /* --------------------------------------------------------------------------
2722     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2723     Note we can't just use an NSDrawRect command, because of the possibility
2724     of some sides not being drawn, and because the rect will be filled.
2725    -------------------------------------------------------------------------- */
2727   NSRect s = r;
2728   [col set];
2730   /* top, bottom */
2731   s.size.height = thickness;
2732   NSRectFill (s);
2733   s.origin.y += r.size.height - thickness;
2734   NSRectFill (s);
2736   s.size.height = r.size.height;
2737   s.origin.y = r.origin.y;
2739   /* left, right (optional) */
2740   s.size.width = thickness;
2741   if (left_p)
2742     NSRectFill (s);
2743   if (right_p)
2744     {
2745       s.origin.x += r.size.width - thickness;
2746       NSRectFill (s);
2747     }
2751 static void
2752 ns_draw_relief (NSRect r, int thickness, char raised_p,
2753                char top_p, char bottom_p, char left_p, char right_p,
2754                struct glyph_string *s)
2755 /* --------------------------------------------------------------------------
2756     Draw a relief rect inside r, optionally leaving some sides open.
2757     Note we can't just use an NSDrawBezel command, because of the possibility
2758     of some sides not being drawn, and because the rect will be filled.
2759    -------------------------------------------------------------------------- */
2761   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2762   NSColor *newBaseCol = nil;
2763   NSRect sr = r;
2765   NSTRACE (ns_draw_relief);
2767   /* set up colors */
2769   if (s->face->use_box_color_for_shadows_p)
2770     {
2771       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2772     }
2773 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2774            && s->img->pixmap
2775            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2776        {
2777          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2778        } */
2779   else
2780     {
2781       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2782     }
2784   if (newBaseCol == nil)
2785     newBaseCol = [NSColor grayColor];
2787   if (newBaseCol != baseCol)  /* TODO: better check */
2788     {
2789       [baseCol release];
2790       baseCol = [newBaseCol retain];
2791       [lightCol release];
2792       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2793       [darkCol release];
2794       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2795     }
2797   [(raised_p ? lightCol : darkCol) set];
2799   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2801   /* top */
2802   sr.size.height = thickness;
2803   if (top_p) NSRectFill (sr);
2805   /* left */
2806   sr.size.height = r.size.height;
2807   sr.size.width = thickness;
2808   if (left_p) NSRectFill (sr);
2810   [(raised_p ? darkCol : lightCol) set];
2812   /* bottom */
2813   sr.size.width = r.size.width;
2814   sr.size.height = thickness;
2815   sr.origin.y += r.size.height - thickness;
2816   if (bottom_p) NSRectFill (sr);
2818   /* right */
2819   sr.size.height = r.size.height;
2820   sr.origin.y = r.origin.y;
2821   sr.size.width = thickness;
2822   sr.origin.x += r.size.width - thickness;
2823   if (right_p) NSRectFill (sr);
2827 static void
2828 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2829 /* --------------------------------------------------------------------------
2830       Function modeled after x_draw_glyph_string_box ().
2831       Sets up parameters for drawing.
2832    -------------------------------------------------------------------------- */
2834   int right_x, last_x;
2835   char left_p, right_p;
2836   struct glyph *last_glyph;
2837   NSRect r;
2838   int thickness;
2839   struct face *face;
2841   if (s->hl == DRAW_MOUSE_FACE)
2842     {
2843       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2844       if (!face)
2845         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2846     }
2847   else
2848     face = s->face;
2850   thickness = face->box_line_width;
2852   NSTRACE (ns_dumpglyphs_box_or_relief);
2854   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2855             ? WINDOW_RIGHT_EDGE_X (s->w)
2856             : window_box_right (s->w, s->area));
2857   last_glyph = (s->cmp || s->img
2858                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2860   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2861               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2863   left_p = (s->first_glyph->left_box_line_p
2864             || (s->hl == DRAW_MOUSE_FACE
2865                 && (s->prev == NULL || s->prev->hl != s->hl)));
2866   right_p = (last_glyph->right_box_line_p
2867              || (s->hl == DRAW_MOUSE_FACE
2868                  && (s->next == NULL || s->next->hl != s->hl)));
2870   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2872   /* expand full-width row over internal borders */
2873   if (s->row->full_width_p)
2874     r = ns_fix_rect_ibw (r, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2875                         FRAME_PIXEL_WIDTH (s->f));
2877   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2878   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2879     {
2880       ns_draw_box (r, abs (thickness),
2881                    ns_lookup_indexed_color (face->box_color, s->f),
2882                   left_p, right_p);
2883     }
2884   else
2885     {
2886       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2887                      1, 1, left_p, right_p, s);
2888     }
2892 static void
2893 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2894 /* --------------------------------------------------------------------------
2895       Modeled after x_draw_glyph_string_background, which draws BG in
2896       certain cases.  Others are left to the text rendering routine.
2897    -------------------------------------------------------------------------- */
2899   NSTRACE (ns_maybe_dumpglyphs_background);
2901   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2902     {
2903       int box_line_width = max (s->face->box_line_width, 0);
2904       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2905           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2906         {
2907           struct face *face;
2908           if (s->hl == DRAW_MOUSE_FACE)
2909             {
2910               face = FACE_FROM_ID (s->f,
2911                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2912               if (!face)
2913                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2914             }
2915           else
2916             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2917           if (!face->stipple)
2918             [(NS_FACE_BACKGROUND (face) != 0
2919               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2920               : FRAME_BACKGROUND_COLOR (s->f)) set];
2921           else
2922             {
2923               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2924               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2925             }
2927           if (s->hl != DRAW_CURSOR)
2928             {
2929               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2930                                     s->background_width,
2931                                     s->height-2*box_line_width);
2933               /* expand full-width row over internal borders */
2934               if (s->row->full_width_p)
2935                 {
2936                   int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2937                   if (r.origin.y <= fibw+1 + box_line_width)
2938                     {
2939                       r.size.height += r.origin.y;
2940                       r.origin.y = 0;
2941                     }
2942                   if (r.origin.x <= fibw+1)
2943                     {
2944                       r.size.width += 2*r.origin.x;
2945                       r.origin.x = 0;
2946                     }
2947                   if (FRAME_PIXEL_WIDTH (s->f) - (r.origin.x + r.size.width)
2948                       <= fibw+1)
2949                     r.size.width += fibw;
2950                 }
2952               NSRectFill (r);
2953             }
2955           s->background_filled_p = 1;
2956         }
2957     }
2961 static void
2962 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2963 /* --------------------------------------------------------------------------
2964       Renders an image and associated borders.
2965    -------------------------------------------------------------------------- */
2967   EmacsImage *img = s->img->pixmap;
2968   int box_line_vwidth = max (s->face->box_line_width, 0);
2969   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2970   int bg_x, bg_y, bg_height;
2971   int th;
2972   char raised_p;
2973   NSRect br;
2974   struct face *face;
2975   NSColor *tdCol;
2977   NSTRACE (ns_dumpglyphs_image);
2979   if (s->face->box != FACE_NO_BOX
2980       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2981     x += abs (s->face->box_line_width);
2983   bg_x = x;
2984   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2985   bg_height = s->height;
2986   /* other terms have this, but was causing problems w/tabbar mode */
2987   /* - 2 * box_line_vwidth; */
2989   if (s->slice.x == 0) x += s->img->hmargin;
2990   if (s->slice.y == 0) y += s->img->vmargin;
2992   /* Draw BG: if we need larger area than image itself cleared, do that,
2993      otherwise, since we composite the image under NS (instead of mucking
2994      with its background color), we must clear just the image area. */
2995   if (s->hl == DRAW_MOUSE_FACE)
2996     {
2997       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2998       if (!face)
2999        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3000     }
3001   else
3002     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3004   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3006   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3007       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3008     {
3009       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3010       s->background_filled_p = 1;
3011     }
3012   else
3013     {
3014       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3015     }
3017   /* expand full-width row over internal borders */
3018   if (s->row->full_width_p)
3019     {
3020       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
3021       if (br.origin.y <= fibw+1 + box_line_vwidth)
3022         {
3023           br.size.height += br.origin.y;
3024           br.origin.y = 0;
3025         }
3026       if (br.origin.x <= fibw+1 + box_line_vwidth)
3027         {
3028           br.size.width += br.origin.x;
3029           br.origin.x = 0;
3030         }
3031       if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) <= fibw+1)
3032         br.size.width += fibw;
3033     }
3035   NSRectFill (br);
3037   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3038   if (img != nil)
3039       [img drawInRect: br
3040               fromRect: NSZeroRect
3041              operation: NSCompositeSourceOver
3042               fraction: 1.0
3043            respectFlipped: YES
3044                 hints: nil];
3046   if (s->hl == DRAW_CURSOR)
3047     {
3048     [FRAME_CURSOR_COLOR (s->f) set];
3049     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3050       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3051     else
3052       /* Currently on NS img->mask is always 0. Since
3053          get_window_cursor_type specifies a hollow box cursor when on
3054          a non-masked image we never reach this clause. But we put it
3055          in in anticipation of better support for image masks on
3056          NS. */
3057       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3058     }
3059   else
3060     {
3061       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3062     }
3064   /* Draw underline, overline, strike-through. */
3065   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3067   /* Draw relief, if requested */
3068   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3069     {
3070       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3071         {
3072           th = tool_bar_button_relief >= 0 ?
3073             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3074           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3075         }
3076       else
3077         {
3078           th = abs (s->img->relief);
3079           raised_p = (s->img->relief > 0);
3080         }
3082       r.origin.x = x - th;
3083       r.origin.y = y - th;
3084       r.size.width = s->slice.width + 2*th-1;
3085       r.size.height = s->slice.height + 2*th-1;
3086       ns_draw_relief (r, th, raised_p,
3087                       s->slice.y == 0,
3088                       s->slice.y + s->slice.height == s->img->height,
3089                       s->slice.x == 0,
3090                       s->slice.x + s->slice.width == s->img->width, s);
3091     }
3093   /* If there is no mask, the background won't be seen,
3094      so draw a rectangle on the image for the cursor.
3095      Do this for all images, getting transparency right is not reliable.  */
3096   if (s->hl == DRAW_CURSOR)
3097     {
3098       int thickness = abs (s->img->relief);
3099       if (thickness == 0) thickness = 1;
3100       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3101     }
3105 static void
3106 ns_dumpglyphs_stretch (struct glyph_string *s)
3108   NSRect r[2];
3109   int n, i;
3110   struct face *face;
3111   NSColor *fgCol, *bgCol;
3113   if (!s->background_filled_p)
3114     {
3115       n = ns_get_glyph_string_clip_rect (s, r);
3116       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3118       ns_focus (s->f, r, n);
3120       if (s->hl == DRAW_MOUSE_FACE)
3121        {
3122          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3123          if (!face)
3124            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3125        }
3126       else
3127        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3129       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3130       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3132       for (i=0; i<n; i++)
3133         {
3134           if (!s->row->full_width_p)
3135             {
3136               int overrun, leftoverrun;
3138               /* truncate to avoid overwriting fringe and/or scrollbar */
3139               overrun = max (0, (s->x + s->background_width)
3140                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3141                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3142               r[i].size.width -= overrun;
3144               /* truncate to avoid overwriting to left of the window box */
3145               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3146                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3148               if (leftoverrun > 0)
3149                 {
3150                   r[i].origin.x += leftoverrun;
3151                   r[i].size.width -= leftoverrun;
3152                 }
3154               /* XXX: Try to work between problem where a stretch glyph on
3155                  a partially-visible bottom row will clear part of the
3156                  modeline, and another where list-buffers headers and similar
3157                  rows erroneously have visible_height set to 0.  Not sure
3158                  where this is coming from as other terms seem not to show. */
3159               r[i].size.height = min (s->height, s->row->visible_height);
3160             }
3162           /* expand full-width rows over internal borders */
3163           else
3164             {
3165               r[i] = ns_fix_rect_ibw (r[i], FRAME_INTERNAL_BORDER_WIDTH (s->f),
3166                                       FRAME_PIXEL_WIDTH (s->f));
3167             }
3169           [bgCol set];
3171           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3172              overwriting cursor (usually when cursor on a tab) */
3173           if (s->hl == DRAW_CURSOR)
3174             {
3175               CGFloat x, width;
3177               x = r[i].origin.x;
3178               width = s->w->phys_cursor_width;
3179               r[i].size.width -= width;
3180               r[i].origin.x += width;
3182               NSRectFill (r[i]);
3184               /* Draw overlining, etc. on the cursor. */
3185               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3186                 ns_draw_text_decoration (s, face, bgCol, width, x);
3187               else
3188                 ns_draw_text_decoration (s, face, fgCol, width, x);
3189             }
3190           else
3191             {
3192               NSRectFill (r[i]);
3193             }
3195           /* Draw overlining, etc. on the stretch glyph (or the part
3196              of the stretch glyph after the cursor). */
3197           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3198                                    r[i].origin.x);
3199         }
3200       ns_unfocus (s->f);
3201       s->background_filled_p = 1;
3202     }
3206 static void
3207 ns_draw_glyph_string (struct glyph_string *s)
3208 /* --------------------------------------------------------------------------
3209       External (RIF): Main draw-text call.
3210    -------------------------------------------------------------------------- */
3212   /* TODO (optimize): focus for box and contents draw */
3213   NSRect r[2];
3214   int n;
3215   char box_drawn_p = 0;
3217   NSTRACE (ns_draw_glyph_string);
3219   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3220     {
3221       int width;
3222       struct glyph_string *next;
3224       for (width = 0, next = s->next;
3225            next && width < s->right_overhang;
3226            width += next->width, next = next->next)
3227         if (next->first_glyph->type != IMAGE_GLYPH)
3228           {
3229             if (next->first_glyph->type != STRETCH_GLYPH)
3230               {
3231                 n = ns_get_glyph_string_clip_rect (s->next, r);
3232                 ns_focus (s->f, r, n);
3233                 ns_maybe_dumpglyphs_background (s->next, 1);
3234                 ns_unfocus (s->f);
3235               }
3236             else
3237               {
3238                 ns_dumpglyphs_stretch (s->next);
3239               }
3240             next->num_clips = 0;
3241           }
3242     }
3244   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3245         && (s->first_glyph->type == CHAR_GLYPH
3246             || s->first_glyph->type == COMPOSITE_GLYPH))
3247     {
3248       n = ns_get_glyph_string_clip_rect (s, r);
3249       ns_focus (s->f, r, n);
3250       ns_maybe_dumpglyphs_background (s, 1);
3251       ns_dumpglyphs_box_or_relief (s);
3252       ns_unfocus (s->f);
3253       box_drawn_p = 1;
3254     }
3256   switch (s->first_glyph->type)
3257     {
3259     case IMAGE_GLYPH:
3260       n = ns_get_glyph_string_clip_rect (s, r);
3261       ns_focus (s->f, r, n);
3262       ns_dumpglyphs_image (s, r[0]);
3263       ns_unfocus (s->f);
3264       break;
3266     case STRETCH_GLYPH:
3267       ns_dumpglyphs_stretch (s);
3268       break;
3270     case CHAR_GLYPH:
3271     case COMPOSITE_GLYPH:
3272       n = ns_get_glyph_string_clip_rect (s, r);
3273       ns_focus (s->f, r, n);
3275       if (s->for_overlaps || (s->cmp_from > 0
3276                               && ! s->first_glyph->u.cmp.automatic))
3277         s->background_filled_p = 1;
3278       else
3279         ns_maybe_dumpglyphs_background
3280           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3282       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3283                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3284                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3285                       NS_DUMPGLYPH_NORMAL));
3286       ns_tmp_font = (struct nsfont_info *)s->face->font;
3287       if (ns_tmp_font == NULL)
3288           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
3290       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3291         {
3292           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3293           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3294           NS_FACE_FOREGROUND (s->face) = tmp;
3295         }
3297       ns_tmp_font->font.driver->draw
3298         (s, 0, s->nchars, s->x, s->y,
3299          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3300          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
3302       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3303         {
3304           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3305           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3306           NS_FACE_FOREGROUND (s->face) = tmp;
3307         }
3309       ns_unfocus (s->f);
3310       break;
3312     case GLYPHLESS_GLYPH:
3313       n = ns_get_glyph_string_clip_rect (s, r);
3314       ns_focus (s->f, r, n);
3316       if (s->for_overlaps || (s->cmp_from > 0
3317                               && ! s->first_glyph->u.cmp.automatic))
3318         s->background_filled_p = 1;
3319       else
3320         ns_maybe_dumpglyphs_background
3321           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3322       /* ... */
3323       /* Not yet implemented.  */
3324       /* ... */
3325       ns_unfocus (s->f);
3326       break;
3328     default:
3329       abort ();
3330     }
3332   /* Draw box if not done already. */
3333   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3334     {
3335       n = ns_get_glyph_string_clip_rect (s, r);
3336       ns_focus (s->f, r, n);
3337       ns_dumpglyphs_box_or_relief (s);
3338       ns_unfocus (s->f);
3339     }
3341   s->num_clips = 0;
3346 /* ==========================================================================
3348     Event loop
3350    ========================================================================== */
3353 static void
3354 ns_send_appdefined (int value)
3355 /* --------------------------------------------------------------------------
3356     Internal: post an appdefined event which EmacsApp-sendEvent will
3357               recognize and take as a command to halt the event loop.
3358    -------------------------------------------------------------------------- */
3360   /*NSTRACE (ns_send_appdefined); */
3362   /* Only post this event if we haven't already posted one.  This will end
3363        the [NXApp run] main loop after having processed all events queued at
3364        this moment.  */
3365   if (send_appdefined)
3366     {
3367       NSEvent *nxev;
3369       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3370       send_appdefined = NO;
3372       /* Don't need wakeup timer any more */
3373       if (timed_entry)
3374         {
3375           [timed_entry invalidate];
3376           [timed_entry release];
3377           timed_entry = nil;
3378         }
3380       /* Ditto for file descriptor poller */
3381       if (fd_entry)
3382         {
3383           [fd_entry invalidate];
3384           [fd_entry release];
3385           fd_entry = nil;
3386         }
3388       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3389                                 location: NSMakePoint (0, 0)
3390                            modifierFlags: 0
3391                                timestamp: 0
3392                             windowNumber: [[NSApp mainWindow] windowNumber]
3393                                  context: [NSApp context]
3394                                  subtype: 0
3395                                    data1: value
3396                                    data2: 0];
3398       /* Post an application defined event on the event queue.  When this is
3399          received the [NXApp run] will return, thus having processed all
3400          events which are currently queued.  */
3401       [NSApp postEvent: nxev atStart: NO];
3402     }
3406 static int
3407 ns_read_socket (struct terminal *terminal, int expected,
3408                 struct input_event *hold_quit)
3409 /* --------------------------------------------------------------------------
3410      External (hook): Post an event to ourself and keep reading events until
3411      we read it back again.  In effect process all events which were waiting.
3412      From 21+ we have to manage the event buffer ourselves.
3413    -------------------------------------------------------------------------- */
3415   struct input_event ev;
3416   int nevents;
3418 /* NSTRACE (ns_read_socket); */
3420   if ([NSApp modalWindow] != nil)
3421     return -1;
3423   if (interrupt_input_blocked)
3424     {
3425       interrupt_input_pending = 1;
3426 #ifdef SYNC_INPUT
3427       pending_signals = 1;
3428 #endif
3429       return -1;
3430     }
3432   interrupt_input_pending = 0;
3433 #ifdef SYNC_INPUT
3434   pending_signals = pending_atimers;
3435 #endif
3437   BLOCK_INPUT;
3438   n_emacs_events_pending = 0;
3439   EVENT_INIT (ev);
3440   emacs_event = &ev;
3441   q_event_ptr = hold_quit;
3443   /* we manage autorelease pools by allocate/reallocate each time around
3444      the loop; strict nesting is occasionally violated but seems not to
3445      matter.. earlier methods using full nesting caused major memory leaks */
3446   [outerpool release];
3447   outerpool = [[NSAutoreleasePool alloc] init];
3449   /* If have pending open-file requests, attend to the next one of those. */
3450   if (ns_pending_files && [ns_pending_files count] != 0
3451       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3452     {
3453       [ns_pending_files removeObjectAtIndex: 0];
3454     }
3455   /* Deal with pending service requests. */
3456   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3457     && [(EmacsApp *)
3458          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3459                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3460     {
3461       [ns_pending_service_names removeObjectAtIndex: 0];
3462       [ns_pending_service_args removeObjectAtIndex: 0];
3463     }
3464   else
3465     {
3466       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3467          to ourself, otherwise [NXApp run] will never exit.  */
3468       send_appdefined = YES;
3470       /* If called via ns_select, this is called once with expected=1,
3471          because we expect either the timeout or file descriptor activity.
3472          In this case the first event through will either be real input or
3473          one of these.  read_avail_input() then calls once more with expected=0
3474          and in that case we need to return quickly if there is nothing.
3475          If we're being called outside of that, it's also OK to return quickly
3476          after one iteration through the event loop, since other terms do
3477          this and emacs expects it. */
3478       if (!(inNsSelect && expected))
3479         {
3480           /* Post an application defined event on the event queue.  When this is
3481              received the [NXApp run] will return, thus having processed all
3482              events which are currently queued, if any.  */
3483           ns_send_appdefined (-1);
3484         }
3486       [NSApp run];
3487     }
3489   nevents = n_emacs_events_pending;
3490   n_emacs_events_pending = 0;
3491   emacs_event = q_event_ptr = NULL;
3492   UNBLOCK_INPUT;
3494   return nevents;
3499 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3500            fd_set *exceptfds, EMACS_TIME *timeout, sigset_t *sigmask)
3501 /* --------------------------------------------------------------------------
3502      Replacement for select, checking for events
3503    -------------------------------------------------------------------------- */
3505   int result;
3506   double time;
3507   NSEvent *ev;
3508   struct timespec select_timeout;
3510 /*  NSTRACE (ns_select); */
3512   if (NSApp == nil || inNsSelect == 1 /* || ([NSApp isActive] == NO &&
3513                       [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil
3514  inMode:NSDefaultRunLoopMode dequeue:NO] == nil) */)
3515     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3517   /* Save file descriptor set, which gets overwritten in calls to select ()
3518      Note, this is called from process.c, and only readfds is ever set */
3519   if (readfds)
3520     {
3521       memcpy (&select_readfds, readfds, sizeof (fd_set));
3522       select_nfds = nfds;
3523     }
3524   else
3525     select_nfds = 0;
3527     /* Try an initial select for pending data on input files */
3528   select_timeout.tv_sec = select_timeout.tv_nsec = 0;
3529   result = pselect (nfds, readfds, writefds, exceptfds,
3530                     &select_timeout, sigmask);
3531   if (result)
3532     return result;
3534   /* if (!timeout || timed_entry || fd_entry)
3535        fprintf (stderr, "assertion failed: timeout null or timed_entry/fd_entry non-null in ns_select\n"); */
3537     /* set a timeout and run the main AppKit event loop while continuing
3538        to monitor the files */
3539   time = EMACS_TIME_TO_DOUBLE (*timeout);
3540   timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3541                                            target: NSApp
3542                                          selector: @selector (timeout_handler:)
3543                                          userInfo: 0
3544                                           repeats: YES] /* for safe removal */
3545                                                          retain];
3547   /* set a periodic task to try the pselect () again */
3548   fd_entry = [[NSTimer scheduledTimerWithTimeInterval: 0.1
3549                                                target: NSApp
3550                                              selector: @selector (fd_handler:)
3551                                              userInfo: 0
3552                                               repeats: YES]
3553                retain];
3555   /* Let Application dispatch events until it receives an event of the type
3556      NX_APPDEFINED, which should only be sent by timeout_handler.
3557      We tell read_avail_input() that input is "expected" because we do expect
3558      either the timeout or fd handler to fire, and if they don't, the original
3559      call from process.c that got us here expects us to wait until some input
3560      comes. */
3561   inNsSelect = 1;
3562   gobble_input (1);
3563   ev = last_appdefined_event;
3564   inNsSelect = 0;
3566   if (ev)
3567     {
3568       int t;
3569       if ([ev type] != NSApplicationDefined)
3570         abort ();
3572       t = [ev data1];
3573       last_appdefined_event = 0;
3575       if (t == -2)
3576         {
3577           /* The NX_APPDEFINED event we received was a timeout. */
3578           return 0;
3579         }
3580       else if (t == -1)
3581         {
3582           /* The NX_APPDEFINED event we received was the result of
3583              at least one real input event arriving.  */
3584           errno = EINTR;
3585           return -1;
3586         }
3587       else
3588         {
3589           /* Received back from pselect () in fd_handler; copy the results */
3590           if (readfds)
3591             memcpy (readfds, &select_readfds, sizeof (fd_set));
3592           return t;
3593         }
3594     }
3595   /* never reached, shut compiler up */
3596   return 0;
3601 /* ==========================================================================
3603     Scrollbar handling
3605    ========================================================================== */
3608 static void
3609 ns_set_vertical_scroll_bar (struct window *window,
3610                            int portion, int whole, int position)
3611 /* --------------------------------------------------------------------------
3612       External (hook): Update or add scrollbar
3613    -------------------------------------------------------------------------- */
3615   Lisp_Object win;
3616   NSRect r, v;
3617   struct frame *f = XFRAME (WINDOW_FRAME (window));
3618   EmacsView *view = FRAME_NS_VIEW (f);
3619   int window_y, window_height;
3620   BOOL barOnVeryLeft, barOnVeryRight;
3621   int top, left, height, width, sb_width, sb_left;
3622   EmacsScroller *bar;
3624   /* optimization; display engine sends WAY too many of these.. */
3625   if (!NILP (window->vertical_scroll_bar))
3626     {
3627       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3628       if ([bar checkSamePosition: position portion: portion whole: whole])
3629         {
3630           if (view->scrollbarsNeedingUpdate == 0)
3631             {
3632               if (!windows_or_buffers_changed)
3633                   return;
3634             }
3635           else
3636             view->scrollbarsNeedingUpdate--;
3637         }
3638     }
3640   NSTRACE (ns_set_vertical_scroll_bar);
3642   /* Get dimensions.  */
3643   window_box (window, -1, 0, &window_y, 0, &window_height);
3644   top = window_y;
3645   height = window_height;
3646   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3647   left = WINDOW_SCROLL_BAR_AREA_X (window);
3649   if (top < 5) /* top scrollbar adjustment */
3650     {
3651       top -= FRAME_INTERNAL_BORDER_WIDTH (f);
3652       height += FRAME_INTERNAL_BORDER_WIDTH (f);
3653     }
3655   /* allow for displaying a skinnier scrollbar than char area allotted */
3656   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3657     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3659   barOnVeryLeft = left < 5;
3660   barOnVeryRight = FRAME_PIXEL_WIDTH (f) - left - width < 5;
3661   sb_left = left + FRAME_INTERNAL_BORDER_WIDTH (f)
3662       * (barOnVeryLeft ? -1 : (barOnVeryRight ? 1 : 0));
3664   r = NSMakeRect (sb_left, top, sb_width, height);
3665   /* the parent view is flipped, so we need to flip y value */
3666   v = [view frame];
3667   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3669   XSETWINDOW (win, window);
3670   BLOCK_INPUT;
3672   /* we want at least 5 lines to display a scrollbar */
3673   if (WINDOW_TOTAL_LINES (window) < 5)
3674     {
3675       if (!NILP (window->vertical_scroll_bar))
3676         {
3677           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3678           [bar removeFromSuperview];
3679           WSET (window, vertical_scroll_bar, Qnil);
3680         }
3681       ns_clear_frame_area (f, sb_left, top, width, height);
3682       UNBLOCK_INPUT;
3683       return;
3684     }
3686   if (NILP (window->vertical_scroll_bar))
3687     {
3688       ns_clear_frame_area (f, sb_left, top, width, height);
3689       bar = [[EmacsScroller alloc] initFrame: r window: win];
3690       WSET (window, vertical_scroll_bar, make_save_value (bar, 0));
3691     }
3692   else
3693     {
3694       NSRect oldRect;
3695       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3696       oldRect = [bar frame];
3697       r.size.width = oldRect.size.width;
3698       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3699         {
3700           if (oldRect.origin.x != r.origin.x)
3701               ns_clear_frame_area (f, sb_left, top, width, height);
3702           [bar setFrame: r];
3703         }
3704     }
3706   [bar setPosition: position portion: portion whole: whole];
3707   UNBLOCK_INPUT;
3711 static void
3712 ns_condemn_scroll_bars (struct frame *f)
3713 /* --------------------------------------------------------------------------
3714      External (hook): arrange for all frame's scrollbars to be removed
3715      at next call to judge_scroll_bars, except for those redeemed.
3716    -------------------------------------------------------------------------- */
3718   int i;
3719   id view;
3720   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3722   NSTRACE (ns_condemn_scroll_bars);
3724   for (i =[subviews count]-1; i >= 0; i--)
3725     {
3726       view = [subviews objectAtIndex: i];
3727       if ([view isKindOfClass: [EmacsScroller class]])
3728         [view condemn];
3729     }
3733 static void
3734 ns_redeem_scroll_bar (struct window *window)
3735 /* --------------------------------------------------------------------------
3736      External (hook): arrange to spare this window's scrollbar
3737      at next call to judge_scroll_bars.
3738    -------------------------------------------------------------------------- */
3740   id bar;
3741   NSTRACE (ns_redeem_scroll_bar);
3742   if (!NILP (window->vertical_scroll_bar))
3743     {
3744       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3745       [bar reprieve];
3746     }
3750 static void
3751 ns_judge_scroll_bars (struct frame *f)
3752 /* --------------------------------------------------------------------------
3753      External (hook): destroy all scrollbars on frame that weren't
3754      redeemed after call to condemn_scroll_bars.
3755    -------------------------------------------------------------------------- */
3757   int i;
3758   id view;
3759   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3760   NSTRACE (ns_judge_scroll_bars);
3761   for (i =[subviews count]-1; i >= 0; i--)
3762     {
3763       view = [subviews objectAtIndex: i];
3764       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3765       [view judge];
3766     }
3770 void
3771 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
3773   /* XXX irrelevant under NS */
3778 /* ==========================================================================
3780     Initialization
3782    ========================================================================== */
3785 x_display_pixel_height (struct ns_display_info *dpyinfo)
3787   NSScreen *screen = [NSScreen mainScreen];
3788   return [screen frame].size.height;
3792 x_display_pixel_width (struct ns_display_info *dpyinfo)
3794   NSScreen *screen = [NSScreen mainScreen];
3795   return [screen frame].size.width;
3799 static Lisp_Object ns_string_to_lispmod (const char *s)
3800 /* --------------------------------------------------------------------------
3801      Convert modifier name to lisp symbol
3802    -------------------------------------------------------------------------- */
3804   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
3805     return Qmeta;
3806   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
3807     return Qsuper;
3808   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3809     return Qcontrol;
3810   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
3811     return Qalt;
3812   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
3813     return Qhyper;
3814   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
3815     return Qnone;
3816   else
3817     return Qnil;
3821 static void
3822 ns_default (const char *parameter, Lisp_Object *result,
3823            Lisp_Object yesval, Lisp_Object noval,
3824            BOOL is_float, BOOL is_modstring)
3825 /* --------------------------------------------------------------------------
3826       Check a parameter value in user's preferences
3827    -------------------------------------------------------------------------- */
3829   const char *value = ns_get_defaults_value (parameter);
3831   if (value)
3832     {
3833       double f;
3834       char *pos;
3835       if (c_strcasecmp (value, "YES") == 0)
3836         *result = yesval;
3837       else if (c_strcasecmp (value, "NO") == 0)
3838         *result = noval;
3839       else if (is_float && (f = strtod (value, &pos), pos != value))
3840         *result = make_float (f);
3841       else if (is_modstring && value)
3842         *result = ns_string_to_lispmod (value);
3843       else fprintf (stderr,
3844                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3845     }
3849 static void
3850 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3851 /* --------------------------------------------------------------------------
3852       Initialize global info and storage for display.
3853    -------------------------------------------------------------------------- */
3855     NSScreen *screen = [NSScreen mainScreen];
3856     NSWindowDepth depth = [screen depth];
3857     Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
3859     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3860     dpyinfo->resy = 72.27;
3861     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3862                                                   NSColorSpaceFromDepth (depth)]
3863                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3864                                                  NSColorSpaceFromDepth (depth)];
3865     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3866     dpyinfo->image_cache = make_image_cache ();
3867     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
3868     dpyinfo->color_table->colors = NULL;
3869     dpyinfo->root_window = 42; /* a placeholder.. */
3871     hlinfo->mouse_face_mouse_frame = NULL;
3872     hlinfo->mouse_face_deferred_gc = 0;
3873     hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
3874     hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
3875     hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
3876     hlinfo->mouse_face_window = hlinfo->mouse_face_overlay = Qnil;
3877     hlinfo->mouse_face_hidden = 0;
3879     hlinfo->mouse_face_mouse_x = hlinfo->mouse_face_mouse_y = 0;
3880     hlinfo->mouse_face_defer = 0;
3882     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3884     dpyinfo->n_fonts = 0;
3885     dpyinfo->smallest_font_height = 1;
3886     dpyinfo->smallest_char_width = 1;
3890 /* This and next define (many of the) public functions in this file. */
3891 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3892          with using despite presence in the "system dependent" redisplay
3893          interface.  In addition, many of the ns_ methods have code that is
3894          shared with all terms, indicating need for further refactoring. */
3895 extern frame_parm_handler ns_frame_parm_handlers[];
3896 static struct redisplay_interface ns_redisplay_interface =
3898   ns_frame_parm_handlers,
3899   x_produce_glyphs,
3900   x_write_glyphs,
3901   x_insert_glyphs,
3902   x_clear_end_of_line,
3903   ns_scroll_run,
3904   ns_after_update_window_line,
3905   ns_update_window_begin,
3906   ns_update_window_end,
3907   x_cursor_to,
3908   ns_flush,
3909   0, /* flush_display_optional */
3910   x_clear_window_mouse_face,
3911   x_get_glyph_overhangs,
3912   x_fix_overlapping_area,
3913   ns_draw_fringe_bitmap,
3914   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3915   0, /* destroy_fringe_bitmap */
3916   ns_compute_glyph_string_overhangs,
3917   ns_draw_glyph_string, /* interface to nsfont.m */
3918   ns_define_frame_cursor,
3919   ns_clear_frame_area,
3920   ns_draw_window_cursor,
3921   ns_draw_vertical_window_border,
3922   ns_shift_glyphs_for_insert
3926 static void
3927 ns_delete_display (struct ns_display_info *dpyinfo)
3929   /* TODO... */
3933 /* This function is called when the last frame on a display is deleted. */
3934 static void
3935 ns_delete_terminal (struct terminal *terminal)
3937   struct ns_display_info *dpyinfo = terminal->display_info.ns;
3939   /* Protect against recursive calls.  delete_frame in
3940      delete_terminal calls us back when it deletes our last frame.  */
3941   if (!terminal->name)
3942     return;
3944   BLOCK_INPUT;
3946   x_destroy_all_bitmaps (dpyinfo);
3947   ns_delete_display (dpyinfo);
3948   UNBLOCK_INPUT;
3952 static struct terminal *
3953 ns_create_terminal (struct ns_display_info *dpyinfo)
3954 /* --------------------------------------------------------------------------
3955       Set up use of NS before we make the first connection.
3956    -------------------------------------------------------------------------- */
3958   struct terminal *terminal;
3960   NSTRACE (ns_create_terminal);
3962   terminal = create_terminal ();
3964   terminal->type = output_ns;
3965   terminal->display_info.ns = dpyinfo;
3966   dpyinfo->terminal = terminal;
3968   terminal->rif = &ns_redisplay_interface;
3970   terminal->clear_frame_hook = ns_clear_frame;
3971   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
3972   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
3973   terminal->ring_bell_hook = ns_ring_bell;
3974   terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
3975   terminal->set_terminal_modes_hook = ns_set_terminal_modes;
3976   terminal->update_begin_hook = ns_update_begin;
3977   terminal->update_end_hook = ns_update_end;
3978   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
3979   terminal->read_socket_hook = ns_read_socket;
3980   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
3981   terminal->mouse_position_hook = ns_mouse_position;
3982   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
3983   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
3985   terminal->fullscreen_hook = 0; /* see XTfullscreen_hook */
3987   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
3988   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
3989   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
3990   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
3992   terminal->delete_frame_hook = x_destroy_window;
3993   terminal->delete_terminal_hook = ns_delete_terminal;
3995   terminal->scroll_region_ok = 1;
3996   terminal->char_ins_del_ok = 1;
3997   terminal->line_ins_del_ok = 1;
3998   terminal->fast_clear_end_of_line = 1;
3999   terminal->memory_below_frame = 0;
4001   return terminal;
4005 struct ns_display_info *
4006 ns_term_init (Lisp_Object display_name)
4007 /* --------------------------------------------------------------------------
4008      Start the Application and get things rolling.
4009    -------------------------------------------------------------------------- */
4011   struct terminal *terminal;
4012   struct ns_display_info *dpyinfo;
4013   static int ns_initialized = 0;
4014   Lisp_Object tmp;
4016   NSTRACE (ns_term_init);
4018   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4019   /*GSDebugAllocationActive (YES); */
4020   BLOCK_INPUT;
4021   handling_signal = 0;
4023   if (!ns_initialized)
4024     {
4025       baud_rate = 38400;
4026       Fset_input_interrupt_mode (Qnil);
4027       ns_initialized = 1;
4028     }
4030   ns_pending_files = [[NSMutableArray alloc] init];
4031   ns_pending_service_names = [[NSMutableArray alloc] init];
4032   ns_pending_service_args = [[NSMutableArray alloc] init];
4034 /* Start app and create the main menu, window, view.
4035      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4036      The view will then ask the NSApp to stop and return to Emacs. */
4037   [EmacsApp sharedApplication];
4038   if (NSApp == nil)
4039     return NULL;
4040   [NSApp setDelegate: NSApp];
4042   /* debugging: log all notifications */
4043   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4044                                          selector: @selector (logNotification:)
4045                                              name: nil object: nil]; */
4047   dpyinfo = xzalloc (sizeof *dpyinfo);
4049   ns_initialize_display_info (dpyinfo);
4050   terminal = ns_create_terminal (dpyinfo);
4052   terminal->kboard = xmalloc (sizeof *terminal->kboard);
4053   init_kboard (terminal->kboard);
4054   KVAR (terminal->kboard, Vwindow_system) = Qns;
4055   terminal->kboard->next_kboard = all_kboards;
4056   all_kboards = terminal->kboard;
4057   /* Don't let the initial kboard remain current longer than necessary.
4058      That would cause problems if a file loaded on startup tries to
4059      prompt in the mini-buffer.  */
4060   if (current_kboard == initial_kboard)
4061     current_kboard = terminal->kboard;
4062   terminal->kboard->reference_count++;
4064   dpyinfo->next = x_display_list;
4065   x_display_list = dpyinfo;
4067   /* Put it on ns_display_name_list */
4068   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
4069                                 ns_display_name_list);
4070   dpyinfo->name_list_element = XCAR (ns_display_name_list);
4072   terminal->name = xstrdup (SSDATA (display_name));
4074   UNBLOCK_INPUT;
4076   if (!inhibit_x_resources)
4077     {
4078       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4079                  Qt, Qnil, NO, NO);
4080       tmp = Qnil;
4081       /* this is a standard variable */
4082       ns_default ("AppleAntiAliasingThreshold", &tmp,
4083                  make_float (10.0), make_float (6.0), YES, NO);
4084       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4085     }
4087   ns_selection_color = [[NSUserDefaults standardUserDefaults]
4088                          stringForKey: @"AppleHighlightColor"];
4089   if (ns_selection_color == nil)
4090     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
4092   {
4093     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4095     if ( cl == nil )
4096       {
4097         Lisp_Object color_file, color_map, color;
4098         unsigned long c;
4099         char *name;
4101         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4102                          Fsymbol_value (intern ("data-directory")));
4103         if (NILP (Ffile_readable_p (color_file)))
4104           fatal ("Could not find %s.\n", SDATA (color_file));
4106         color_map = Fx_load_color_file (color_file);
4107         if (NILP (color_map))
4108           fatal ("Could not read %s.\n", SDATA (color_file));
4110         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4111         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4112           {
4113             color = XCAR (color_map);
4114             name = SSDATA (XCAR (color));
4115             c = XINT (XCDR (color));
4116             [cl setColor:
4117                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4118                                             green: GREEN_FROM_ULONG (c) / 255.0
4119                                              blue: BLUE_FROM_ULONG (c) / 255.0
4120                                             alpha: 1.0]
4121                   forKey: [NSString stringWithUTF8String: name]];
4122           }
4123         [cl writeToFile: nil];
4124       }
4125   }
4127   {
4128 #ifdef NS_IMPL_GNUSTEP
4129     Vwindow_system_version = build_string (gnustep_base_version);
4130 #else
4131     /*PSnextrelease (128, c); */
4132     char c[DBL_BUFSIZE_BOUND];
4133     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4134     Vwindow_system_version = make_unibyte_string (c, len);
4135 #endif
4136   }
4138   delete_keyboard_wait_descriptor (0);
4140   ns_app_name = [[NSProcessInfo processInfo] processName];
4142 /* Set up OS X app menu */
4143 #ifdef NS_IMPL_COCOA
4144   {
4145     NSMenu *appMenu;
4146     NSMenuItem *item;
4147     /* set up the application menu */
4148     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4149     [svcsMenu setAutoenablesItems: NO];
4150     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4151     [appMenu setAutoenablesItems: NO];
4152     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4153     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4155     [appMenu insertItemWithTitle: @"About Emacs"
4156                           action: @selector (orderFrontStandardAboutPanel:)
4157                    keyEquivalent: @""
4158                          atIndex: 0];
4159     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4160     [appMenu insertItemWithTitle: @"Preferences..."
4161                           action: @selector (showPreferencesWindow:)
4162                    keyEquivalent: @","
4163                          atIndex: 2];
4164     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4165     item = [appMenu insertItemWithTitle: @"Services"
4166                                  action: @selector (menuDown:)
4167                           keyEquivalent: @""
4168                                 atIndex: 4];
4169     [appMenu setSubmenu: svcsMenu forItem: item];
4170     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4171     [appMenu insertItemWithTitle: @"Hide Emacs"
4172                           action: @selector (hide:)
4173                    keyEquivalent: @"h"
4174                          atIndex: 6];
4175     item =  [appMenu insertItemWithTitle: @"Hide Others"
4176                           action: @selector (hideOtherApplications:)
4177                    keyEquivalent: @"h"
4178                          atIndex: 7];
4179     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4180     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4181     [appMenu insertItemWithTitle: @"Quit Emacs"
4182                           action: @selector (terminate:)
4183                    keyEquivalent: @"q"
4184                          atIndex: 9];
4186     item = [mainMenu insertItemWithTitle: ns_app_name
4187                                   action: @selector (menuDown:)
4188                            keyEquivalent: @""
4189                                  atIndex: 0];
4190     [mainMenu setSubmenu: appMenu forItem: item];
4191     [dockMenu insertItemWithTitle: @"New Frame"
4192                            action: @selector (newFrame:)
4193                     keyEquivalent: @""
4194                           atIndex: 0];
4196     [NSApp setMainMenu: mainMenu];
4197     [NSApp setAppleMenu: appMenu];
4198     [NSApp setServicesMenu: svcsMenu];
4199     /* Needed at least on Cocoa, to get dock menu to show windows */
4200     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4202     [[NSNotificationCenter defaultCenter]
4203       addObserver: mainMenu
4204          selector: @selector (trackingNotification:)
4205              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4206     [[NSNotificationCenter defaultCenter]
4207       addObserver: mainMenu
4208          selector: @selector (trackingNotification:)
4209              name: NSMenuDidEndTrackingNotification object: mainMenu];
4210   }
4211 #endif /* MAC OS X menu setup */
4213   [NSApp run];
4214   ns_do_open_file = YES;
4215   return dpyinfo;
4219 void
4220 ns_term_shutdown (int sig)
4222   [[NSUserDefaults standardUserDefaults] synchronize];
4224   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4225   if (STRINGP (Vauto_save_list_file_name))
4226     unlink (SSDATA (Vauto_save_list_file_name));
4228   if (sig == 0 || sig == SIGTERM)
4229     {
4230       [NSApp terminate: NSApp];
4231     }
4232   else // force a stack trace to happen
4233     {
4234       abort();
4235     }
4239 /* ==========================================================================
4241     EmacsApp implementation
4243    ========================================================================== */
4246 @implementation EmacsApp
4248 - (void)logNotification: (NSNotification *)notification
4250   const char *name = [[notification name] UTF8String];
4251   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4252       && !strstr (name, "WindowNumber"))
4253     NSLog (@"notification: '%@'", [notification name]);
4257 - (void)sendEvent: (NSEvent *)theEvent
4258 /* --------------------------------------------------------------------------
4259      Called when NSApp is running for each event received.  Used to stop
4260      the loop when we choose, since there's no way to just run one iteration.
4261    -------------------------------------------------------------------------- */
4263   int type = [theEvent type];
4264   NSWindow *window = [theEvent window];
4265 /*  NSTRACE (sendEvent); */
4266 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4268 #ifdef NS_IMPL_COCOA
4269   if (type == NSApplicationDefined
4270       && [theEvent data2] == NSAPP_DATA2_RUNASSCRIPT)
4271     {
4272       ns_run_ascript ();
4273       [self stop: self];
4274       return;
4275     }
4276 #endif
4278   if (type == NSCursorUpdate && window == nil)
4279     {
4280       fprintf (stderr, "Dropping external cursor update event.\n");
4281       return;
4282     }
4284 #ifdef NS_IMPL_COCOA
4285   /* pass mouse down in resize handle and subsequent drags directly to
4286      EmacsWindow so we can generate continuous redisplays */
4287   if (ns_in_resize)
4288     {
4289       if (type == NSLeftMouseDragged)
4290         {
4291           [window mouseDragged: theEvent];
4292           return;
4293         }
4294       else if (type == NSLeftMouseUp)
4295         {
4296           [window mouseUp: theEvent];
4297           return;
4298         }
4299     }
4300   else if (type == NSLeftMouseDown)
4301     {
4302       NSRect r = ns_resize_handle_rect (window);
4303       if (NSPointInRect ([theEvent locationInWindow], r))
4304         {
4305           ns_in_resize = YES;
4306           [window mouseDown: theEvent];
4307           return;
4308         }
4309     }
4310 #endif
4312   if (type == NSApplicationDefined)
4313     {
4314       /* Events posted by ns_send_appdefined interrupt the run loop here.
4315          But, if a modal window is up, an appdefined can still come through,
4316          (e.g., from a makeKeyWindow event) but stopping self also stops the
4317          modal loop. Just defer it until later. */
4318       if ([NSApp modalWindow] == nil)
4319         {
4320           last_appdefined_event = theEvent;
4321           [self stop: self];
4322         }
4323       else
4324         {
4325           send_appdefined = YES;
4326         }
4327     }
4329   [super sendEvent: theEvent];
4333 - (void)showPreferencesWindow: (id)sender
4335   struct frame *emacsframe = SELECTED_FRAME ();
4336   NSEvent *theEvent = [NSApp currentEvent];
4338   if (!emacs_event)
4339     return;
4340   emacs_event->kind = NS_NONKEY_EVENT;
4341   emacs_event->code = KEY_NS_SHOW_PREFS;
4342   emacs_event->modifiers = 0;
4343   EV_TRAILER (theEvent);
4347 - (void)newFrame: (id)sender
4349   struct frame *emacsframe = SELECTED_FRAME ();
4350   NSEvent *theEvent = [NSApp currentEvent];
4352   if (!emacs_event)
4353     return;
4354   emacs_event->kind = NS_NONKEY_EVENT;
4355   emacs_event->code = KEY_NS_NEW_FRAME;
4356   emacs_event->modifiers = 0;
4357   EV_TRAILER (theEvent);
4361 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4362 - (BOOL) openFile: (NSString *)fileName
4364   struct frame *emacsframe = SELECTED_FRAME ();
4365   NSEvent *theEvent = [NSApp currentEvent];
4367   if (!emacs_event)
4368     return NO;
4370   emacs_event->kind = NS_NONKEY_EVENT;
4371   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4372   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4373   ns_input_line = Qnil; /* can be start or cons start,end */
4374   emacs_event->modifiers =0;
4375   EV_TRAILER (theEvent);
4377   return YES;
4381 /* **************************************************************************
4383       EmacsApp delegate implementation
4385    ************************************************************************** */
4387 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4388 /* --------------------------------------------------------------------------
4389      When application is loaded, terminate event loop in ns_term_init
4390    -------------------------------------------------------------------------- */
4392   NSTRACE (applicationDidFinishLaunching);
4393   [NSApp setServicesProvider: NSApp];
4394   ns_send_appdefined (-2);
4398 /* Termination sequences:
4399     C-x C-c:
4400     Cmd-Q:
4401     MenuBar | File | Exit:
4402     Select Quit from App menubar:
4403         -terminate
4404         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4405         ns_term_shutdown()
4407     Select Quit from Dock menu:
4408     Logout attempt:
4409         -appShouldTerminate
4410           Cancel -> Nothing else
4411           Accept ->
4413           -terminate
4414           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4415           ns_term_shutdown()
4419 - (void) terminate: (id)sender
4421   struct frame *emacsframe = SELECTED_FRAME ();
4423   if (!emacs_event)
4424     return;
4426   emacs_event->kind = NS_NONKEY_EVENT;
4427   emacs_event->code = KEY_NS_POWER_OFF;
4428   emacs_event->arg = Qt; /* mark as non-key event */
4429   EV_TRAILER ((id)nil);
4433 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4435   int ret;
4437   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4438     return NSTerminateNow;
4440     ret = NSRunAlertPanel(ns_app_name,
4441                           @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
4442                           @"Save Buffers and Exit", @"Cancel", nil);
4444     if (ret == NSAlertDefaultReturn)
4445         return NSTerminateNow;
4446     else if (ret == NSAlertAlternateReturn)
4447         return NSTerminateCancel;
4448     return NSTerminateNow;  /* just in case */
4452 /*   Notification from the Workspace to open a file */
4453 - (BOOL)application: sender openFile: (NSString *)file
4455   if (ns_do_open_file)
4456     [ns_pending_files addObject: file];
4457   return YES;
4461 /*   Open a file as a temporary file */
4462 - (BOOL)application: sender openTempFile: (NSString *)file
4464   if (ns_do_open_file)
4465     [ns_pending_files addObject: file];
4466   return YES;
4470 /*   Notification from the Workspace to open a file noninteractively (?) */
4471 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4473   if (ns_do_open_file)
4474     [ns_pending_files addObject: file];
4475   return YES;
4479 /*   Notification from the Workspace to open multiple files */
4480 - (void)application: sender openFiles: (NSArray *)fileList
4482   /* Don't open files from the command line, Cocoa parses the command line
4483      wrong anyway, --option value tries to open value if --option is the last
4484      option.  */
4485   if (ns_do_open_file)
4486     {
4487       NSEnumerator *files = [fileList objectEnumerator];
4488       NSString *file;
4489       while ((file = [files nextObject]) != nil)
4490         [ns_pending_files addObject: file];
4491     }
4492   
4493   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4498 /* Handle dock menu requests.  */
4499 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4501   return dockMenu;
4505 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4506 - (void)applicationWillBecomeActive: (NSNotification *)notification
4508   //ns_app_active=YES;
4510 - (void)applicationDidBecomeActive: (NSNotification *)notification
4512   NSTRACE (applicationDidBecomeActive);
4514   //ns_app_active=YES;
4516   ns_update_auto_hide_menu_bar ();
4517   // No constraining takes place when the application is not active.
4518   ns_constrain_all_frames ();
4520 - (void)applicationDidResignActive: (NSNotification *)notification
4522   //ns_app_active=NO;
4523   ns_send_appdefined (-1);
4528 /* ==========================================================================
4530     EmacsApp aux handlers for managing event loop
4532    ========================================================================== */
4535 - (void)timeout_handler: (NSTimer *)timedEntry
4536 /* --------------------------------------------------------------------------
4537      The timeout specified to ns_select has passed.
4538    -------------------------------------------------------------------------- */
4540   /*NSTRACE (timeout_handler); */
4541   ns_send_appdefined (-2);
4544 - (void)fd_handler: (NSTimer *) fdEntry
4545 /* --------------------------------------------------------------------------
4546      Check data waiting on file descriptors and terminate if so
4547    -------------------------------------------------------------------------- */
4549   int result;
4550   struct timespec select_timeout;
4551   /* NSTRACE (fd_handler); */
4553   if (select_nfds == 0)
4554     return;
4556   memcpy (&t_readfds, &select_readfds, sizeof (fd_set));
4558   select_timeout.tv_sec = select_timeout.tv_nsec = 0;
4559   result = pselect (select_nfds, &t_readfds, NULL, NULL, &select_timeout, NULL);
4560   if (result)
4561     {
4562       memcpy (&select_readfds, &t_readfds, sizeof (fd_set));
4563       ns_send_appdefined (result);
4564     }
4569 /* ==========================================================================
4571     Service provision
4573    ========================================================================== */
4575 /* called from system: queue for next pass through event loop */
4576 - (void)requestService: (NSPasteboard *)pboard
4577               userData: (NSString *)userData
4578                  error: (NSString **)error
4580   [ns_pending_service_names addObject: userData];
4581   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4582       SSDATA (ns_string_from_pasteboard (pboard))]];
4586 /* called from ns_read_socket to clear queue */
4587 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4589   struct frame *emacsframe = SELECTED_FRAME ();
4590   NSEvent *theEvent = [NSApp currentEvent];
4592   if (!emacs_event)
4593     return NO;
4595   emacs_event->kind = NS_NONKEY_EVENT;
4596   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4597   ns_input_spi_name = build_string ([name UTF8String]);
4598   ns_input_spi_arg = build_string ([arg UTF8String]);
4599   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4600   EV_TRAILER (theEvent);
4602   return YES;
4606 @end  /* EmacsApp */
4610 /* ==========================================================================
4612     EmacsView implementation
4614    ========================================================================== */
4617 @implementation EmacsView
4619 /* needed to inform when window closed from LISP */
4620 - (void) setWindowClosing: (BOOL)closing
4622   windowClosing = closing;
4626 - (void)dealloc
4628   NSTRACE (EmacsView_dealloc);
4629   [toolbar release];
4630   [super dealloc];
4634 /* called on font panel selection */
4635 - (void)changeFont: (id)sender
4637   NSEvent *e =[[self window] currentEvent];
4638   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4639   id newFont;
4640   float size;
4642   NSTRACE (changeFont);
4643   if (!emacs_event)
4644     return;
4646   if ((newFont = [sender convertFont:
4647                            ((struct nsfont_info *)face->font)->nsfont]))
4648     {
4649       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4651       emacs_event->kind = NS_NONKEY_EVENT;
4652       emacs_event->modifiers = 0;
4653       emacs_event->code = KEY_NS_CHANGE_FONT;
4655       size = [newFont pointSize];
4656       ns_input_fontsize = make_number (lrint (size));
4657       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4658       EV_TRAILER (e);
4659     }
4663 - (BOOL)acceptsFirstResponder
4665   NSTRACE (acceptsFirstResponder);
4666   return YES;
4670 - (void)resetCursorRects
4672   NSRect visible = [self visibleRect];
4673   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4674   NSTRACE (resetCursorRects);
4676   if (currentCursor == nil)
4677     currentCursor = [NSCursor arrowCursor];
4679   if (!NSIsEmptyRect (visible))
4680     [self addCursorRect: visible cursor: currentCursor];
4681   [currentCursor setOnMouseEntered: YES];
4686 /*****************************************************************************/
4687 /* Keyboard handling. */
4688 #define NS_KEYLOG 0
4690 - (void)keyDown: (NSEvent *)theEvent
4692   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4693   int code;
4694   unsigned fnKeysym = 0;
4695   int flags;
4696   static NSMutableArray *nsEvArray;
4697 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4698   static BOOL firstTime = YES;
4699 #endif
4700   int left_is_none;
4702   NSTRACE (keyDown);
4704   /* Rhapsody and OS X give up and down events for the arrow keys */
4705   if (ns_fake_keydown == YES)
4706     ns_fake_keydown = NO;
4707   else if ([theEvent type] != NSKeyDown)
4708     return;
4710   if (!emacs_event)
4711     return;
4713  if (![[self window] isKeyWindow]
4714      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4715      /* we must avoid an infinite loop here. */
4716      && (EmacsView *)[[theEvent window] delegate] != self)
4717    {
4718      /* XXX: There is an occasional condition in which, when Emacs display
4719          updates a different frame from the current one, and temporarily
4720          selects it, then processes some interrupt-driven input
4721          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4722          for some reason that window has its first responder set to the NSView
4723          most recently updated (I guess), which is not the correct one. */
4724      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4725      return;
4726    }
4728   if (nsEvArray == nil)
4729     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4731   [NSCursor setHiddenUntilMouseMoves: YES];
4733   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4734     {
4735       clear_mouse_face (hlinfo);
4736       hlinfo->mouse_face_hidden = 1;
4737     }
4739   if (!processingCompose)
4740     {
4741       /* When using screen sharing, no left or right information is sent,
4742          so use Left key in those cases.  */
4743       int is_left_key, is_right_key;
4745       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4746         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4748       /* (Carbon way: [theEvent keyCode]) */
4750       /* is it a "function key"? */
4751       fnKeysym = ns_convert_key (code);
4752       if (fnKeysym)
4753         {
4754           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4755              because Emacs treats Delete and KP-Delete same (in simple.el). */
4756           if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4757             code = 0xFF08; /* backspace */
4758           else
4759             code = fnKeysym;
4760         }
4762       /* are there modifiers? */
4763       emacs_event->modifiers = 0;
4764       flags = [theEvent modifierFlags];
4766       if (flags & NSHelpKeyMask)
4767           emacs_event->modifiers |= hyper_modifier;
4769       if (flags & NSShiftKeyMask)
4770         emacs_event->modifiers |= shift_modifier;
4772       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
4773       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
4774         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
4775       
4776       if (is_right_key)
4777         emacs_event->modifiers |= parse_solitary_modifier
4778           (EQ (ns_right_command_modifier, Qleft)
4779            ? ns_command_modifier
4780            : ns_right_command_modifier);
4782       if (is_left_key)
4783         {
4784           emacs_event->modifiers |= parse_solitary_modifier
4785             (ns_command_modifier);
4787           /* if super (default), take input manager's word so things like
4788              dvorak / qwerty layout work */
4789           if (EQ (ns_command_modifier, Qsuper)
4790               && !fnKeysym
4791               && [[theEvent characters] length] != 0)
4792             {
4793               /* XXX: the code we get will be unshifted, so if we have
4794                  a shift modifier, must convert ourselves */
4795               if (!(flags & NSShiftKeyMask))
4796                 code = [[theEvent characters] characterAtIndex: 0];
4797 #if 0
4798               /* this is ugly and also requires linking w/Carbon framework
4799                  (for LMGetKbdType) so for now leave this rare (?) case
4800                  undealt with.. in future look into CGEvent methods */
4801               else
4802                 {
4803                   long smv = GetScriptManagerVariable (smKeyScript);
4804                   Handle uchrHandle = GetResource
4805                     ('uchr', GetScriptVariable (smv, smScriptKeys));
4806                   UInt32 dummy = 0;
4807                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
4808                                  [[theEvent characters] characterAtIndex: 0],
4809                                  kUCKeyActionDisplay,
4810                                  (flags & ~NSCommandKeyMask) >> 8,
4811                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
4812                                  &dummy, 1, &dummy, &code);
4813                   code &= 0xFF;
4814                 }
4815 #endif
4816             }
4817         }
4819       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
4820       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
4821         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
4823       if (is_right_key)
4824           emacs_event->modifiers |= parse_solitary_modifier
4825               (EQ (ns_right_control_modifier, Qleft)
4826                ? ns_control_modifier
4827                : ns_right_control_modifier);
4829       if (is_left_key)
4830         emacs_event->modifiers |= parse_solitary_modifier
4831           (ns_control_modifier);
4833       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
4834           emacs_event->modifiers |=
4835             parse_solitary_modifier (ns_function_modifier);
4837       left_is_none = NILP (ns_alternate_modifier)
4838         || EQ (ns_alternate_modifier, Qnone);
4840       is_right_key = (flags & NSRightAlternateKeyMask)
4841         == NSRightAlternateKeyMask;
4842       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
4843         || (! is_right_key
4844             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
4846       if (is_right_key)
4847         {
4848           if ((NILP (ns_right_alternate_modifier)
4849                || EQ (ns_right_alternate_modifier, Qnone)
4850                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
4851               && !fnKeysym)
4852             {   /* accept pre-interp alt comb */
4853               if ([[theEvent characters] length] > 0)
4854                 code = [[theEvent characters] characterAtIndex: 0];
4855               /*HACK: clear lone shift modifier to stop next if from firing */
4856               if (emacs_event->modifiers == shift_modifier)
4857                 emacs_event->modifiers = 0;
4858             }
4859           else
4860             emacs_event->modifiers |= parse_solitary_modifier
4861               (EQ (ns_right_alternate_modifier, Qleft)
4862                ? ns_alternate_modifier
4863                : ns_right_alternate_modifier);
4864         }
4866       if (is_left_key) /* default = meta */
4867         {
4868           if (left_is_none && !fnKeysym)
4869             {   /* accept pre-interp alt comb */
4870               if ([[theEvent characters] length] > 0)
4871                 code = [[theEvent characters] characterAtIndex: 0];
4872               /*HACK: clear lone shift modifier to stop next if from firing */
4873               if (emacs_event->modifiers == shift_modifier)
4874                 emacs_event->modifiers = 0;
4875             }
4876           else
4877               emacs_event->modifiers |=
4878                 parse_solitary_modifier (ns_alternate_modifier);
4879         }
4881   if (NS_KEYLOG)
4882     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
4883              code, fnKeysym, flags, emacs_event->modifiers);
4885       /* if it was a function key or had modifiers, pass it directly to emacs */
4886       if (fnKeysym || (emacs_event->modifiers
4887                        && (emacs_event->modifiers != shift_modifier)
4888                        && [[theEvent charactersIgnoringModifiers] length] > 0))
4889 /*[[theEvent characters] length] */
4890         {
4891           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4892           if (code < 0x20)
4893             code |= (1<<28)|(3<<16);
4894           else if (code == 0x7f)
4895             code |= (1<<28)|(3<<16);
4896           else if (!fnKeysym)
4897             emacs_event->kind = code > 0xFF
4898               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4900           emacs_event->code = code;
4901           EV_TRAILER (theEvent);
4902           return;
4903         }
4904     }
4907 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4908   /* if we get here we should send the key for input manager processing */
4909   if (firstTime && [[NSInputManager currentInputManager]
4910                      wantsToDelayTextChangeNotifications] == NO)
4911     fprintf (stderr,
4912           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
4913   firstTime = NO;
4914 #endif
4915   if (NS_KEYLOG && !processingCompose)
4916     fprintf (stderr, "keyDown: Begin compose sequence.\n");
4918   processingCompose = YES;
4919   [nsEvArray addObject: theEvent];
4920   [self interpretKeyEvents: nsEvArray];
4921   [nsEvArray removeObject: theEvent];
4925 #ifdef NS_IMPL_COCOA
4926 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
4927    decided not to send key-down for.
4928    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
4929    This only applies on Tiger and earlier.
4930    If it matches one of these, send it on to keyDown. */
4931 -(void)keyUp: (NSEvent *)theEvent
4933   int flags = [theEvent modifierFlags];
4934   int code = [theEvent keyCode];
4935   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
4936       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
4937     {
4938       if (NS_KEYLOG)
4939         fprintf (stderr, "keyUp: passed test");
4940       ns_fake_keydown = YES;
4941       [self keyDown: theEvent];
4942     }
4944 #endif
4947 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
4950 /* <NSTextInput>: called when done composing;
4951    NOTE: also called when we delete over working text, followed immed.
4952          by doCommandBySelector: deleteBackward: */
4953 - (void)insertText: (id)aString
4955   int code;
4956   int len = [(NSString *)aString length];
4957   int i;
4959   if (NS_KEYLOG)
4960     NSLog (@"insertText '%@'\tlen = %d", aString, len);
4961   processingCompose = NO;
4963   if (!emacs_event)
4964     return;
4966   /* first, clear any working text */
4967   if (workingText != nil)
4968     [self deleteWorkingText];
4970   /* now insert the string as keystrokes */
4971   for (i =0; i<len; i++)
4972     {
4973       code = [aString characterAtIndex: i];
4974       /* TODO: still need this? */
4975       if (code == 0x2DC)
4976         code = '~'; /* 0x7E */
4977       emacs_event->modifiers = 0;
4978       emacs_event->kind
4979         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4980       emacs_event->code = code;
4981       EV_TRAILER ((id)nil);
4982     }
4986 /* <NSTextInput>: inserts display of composing characters */
4987 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
4989   NSString *str = [aString respondsToSelector: @selector (string)] ?
4990     [aString string] : aString;
4991   if (NS_KEYLOG)
4992     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
4993            selRange.length, selRange.location);
4995   if (workingText != nil)
4996     [self deleteWorkingText];
4997   if ([str length] == 0)
4998     return;
5000   if (!emacs_event)
5001     return;
5003   processingCompose = YES;
5004   workingText = [str copy];
5005   ns_working_text = build_string ([workingText UTF8String]);
5007   emacs_event->kind = NS_TEXT_EVENT;
5008   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5009   EV_TRAILER ((id)nil);
5013 /* delete display of composing characters [not in <NSTextInput>] */
5014 - (void)deleteWorkingText
5016   if (workingText == nil)
5017     return;
5018   if (NS_KEYLOG)
5019     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
5020   [workingText release];
5021   workingText = nil;
5022   processingCompose = NO;
5024   if (!emacs_event)
5025     return;
5027   emacs_event->kind = NS_TEXT_EVENT;
5028   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5029   EV_TRAILER ((id)nil);
5033 - (BOOL)hasMarkedText
5035   return workingText != nil;
5039 - (NSRange)markedRange
5041   NSRange rng = workingText != nil
5042     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5043   if (NS_KEYLOG)
5044     NSLog (@"markedRange request");
5045   return rng;
5049 - (void)unmarkText
5051   if (NS_KEYLOG)
5052     NSLog (@"unmark (accept) text");
5053   [self deleteWorkingText];
5054   processingCompose = NO;
5058 /* used to position char selection windows, etc. */
5059 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5061   NSRect rect;
5062   NSPoint pt;
5063   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5064   if (NS_KEYLOG)
5065     NSLog (@"firstRectForCharRange request");
5067   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5068   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5069   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5070   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5071                                        +FRAME_LINE_HEIGHT (emacsframe));
5073   pt = [self convertPoint: pt toView: nil];
5074   pt = [[self window] convertBaseToScreen: pt];
5075   rect.origin = pt;
5076   return rect;
5080 - (NSInteger)conversationIdentifier
5082   return (NSInteger)self;
5086 - (void)doCommandBySelector: (SEL)aSelector
5088   if (NS_KEYLOG)
5089     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5091   if (aSelector == @selector (deleteBackward:))
5092     {
5093       /* happens when user backspaces over an ongoing composition:
5094          throw a 'delete' into the event queue */
5095       if (!emacs_event)
5096         return;
5097       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5098       emacs_event->code = 0xFF08;
5099       EV_TRAILER ((id)nil);
5100     }
5103 - (NSArray *)validAttributesForMarkedText
5105   static NSArray *arr = nil;
5106   if (arr == nil) arr = [NSArray new];
5107  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5108   return arr;
5111 - (NSRange)selectedRange
5113   if (NS_KEYLOG)
5114     NSLog (@"selectedRange request");
5115   return NSMakeRange (NSNotFound, 0);
5118 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5120   if (NS_KEYLOG)
5121     NSLog (@"characterIndexForPoint request");
5122   return 0;
5125 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5127   static NSAttributedString *str = nil;
5128   if (str == nil) str = [NSAttributedString new];
5129   if (NS_KEYLOG)
5130     NSLog (@"attributedSubstringFromRange request");
5131   return str;
5134 /* End <NSTextInput> impl. */
5135 /*****************************************************************************/
5138 /* This is what happens when the user presses a mouse button.  */
5139 - (void)mouseDown: (NSEvent *)theEvent
5141   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5143   NSTRACE (mouseDown);
5145   [self deleteWorkingText];
5147   if (!emacs_event)
5148     return;
5150   last_mouse_frame = emacsframe;
5151   /* appears to be needed to prevent spurious movement events generated on
5152      button clicks */
5153   last_mouse_frame->mouse_moved = 0;
5155   if ([theEvent type] == NSScrollWheel)
5156     {
5157       float delta = [theEvent deltaY];
5158       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5159       if (delta == 0)
5160         return;
5161       emacs_event->kind = WHEEL_EVENT;
5162       emacs_event->code = 0;
5163       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5164         ((delta > 0) ? up_modifier : down_modifier);
5165     }
5166   else
5167     {
5168       emacs_event->kind = MOUSE_CLICK_EVENT;
5169       emacs_event->code = EV_BUTTON (theEvent);
5170       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5171                              | EV_UDMODIFIERS (theEvent);
5172     }
5173   XSETINT (emacs_event->x, lrint (p.x));
5174   XSETINT (emacs_event->y, lrint (p.y));
5175   EV_TRAILER (theEvent);
5179 - (void)rightMouseDown: (NSEvent *)theEvent
5181   NSTRACE (rightMouseDown);
5182   [self mouseDown: theEvent];
5186 - (void)otherMouseDown: (NSEvent *)theEvent
5188   NSTRACE (otherMouseDown);
5189   [self mouseDown: theEvent];
5193 - (void)mouseUp: (NSEvent *)theEvent
5195   NSTRACE (mouseUp);
5196   [self mouseDown: theEvent];
5200 - (void)rightMouseUp: (NSEvent *)theEvent
5202   NSTRACE (rightMouseUp);
5203   [self mouseDown: theEvent];
5207 - (void)otherMouseUp: (NSEvent *)theEvent
5209   NSTRACE (otherMouseUp);
5210   [self mouseDown: theEvent];
5214 - (void) scrollWheel: (NSEvent *)theEvent
5216   NSTRACE (scrollWheel);
5217   [self mouseDown: theEvent];
5221 /* Tell emacs the mouse has moved. */
5222 - (void)mouseMoved: (NSEvent *)e
5224   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5225   Lisp_Object frame;
5227 //  NSTRACE (mouseMoved);
5229   last_mouse_movement_time = EV_TIMESTAMP (e);
5230   last_mouse_motion_position
5231     = [self convertPoint: [e locationInWindow] fromView: nil];
5233   /* update any mouse face */
5234   if (hlinfo->mouse_face_hidden)
5235     {
5236       hlinfo->mouse_face_hidden = 0;
5237       clear_mouse_face (hlinfo);
5238     }
5240   /* tooltip handling */
5241   previous_help_echo_string = help_echo_string;
5242   help_echo_string = Qnil;
5244   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
5245                             last_mouse_motion_position.y))
5246     help_echo_string = previous_help_echo_string;
5248   XSETFRAME (frame, emacsframe);
5249   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5250     {
5251       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5252          (note_mouse_highlight), which is called through the
5253          note_mouse_movement () call above */
5254       gen_help_event (help_echo_string, frame, help_echo_window,
5255                       help_echo_object, help_echo_pos);
5256     }
5257   else
5258     {
5259       help_echo_string = Qnil;
5260       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5261     }
5263   if (emacsframe->mouse_moved && send_appdefined)
5264     ns_send_appdefined (-1);
5268 - (void)mouseDragged: (NSEvent *)e
5270   NSTRACE (mouseDragged);
5271   [self mouseMoved: e];
5275 - (void)rightMouseDragged: (NSEvent *)e
5277   NSTRACE (rightMouseDragged);
5278   [self mouseMoved: e];
5282 - (void)otherMouseDragged: (NSEvent *)e
5284   NSTRACE (otherMouseDragged);
5285   [self mouseMoved: e];
5289 - (BOOL)windowShouldClose: (id)sender
5291   NSEvent *e =[[self window] currentEvent];
5293   NSTRACE (windowShouldClose);
5294   windowClosing = YES;
5295   if (!emacs_event)
5296     return NO;
5297   emacs_event->kind = DELETE_WINDOW_EVENT;
5298   emacs_event->modifiers = 0;
5299   emacs_event->code = 0;
5300   EV_TRAILER (e);
5301   /* Don't close this window, let this be done from lisp code.  */
5302   return NO;
5306 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5307 /* normalize frame to gridded text size */
5309   NSTRACE (windowWillResize);
5310 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5312   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5313 #ifdef NS_IMPL_GNUSTEP
5314                                         frameSize.width + 3);
5315 #else
5316                                         frameSize.width);
5317 #endif
5318   if (cols < MINWIDTH)
5319     cols = MINWIDTH;
5321   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, frameSize.height
5322 #ifdef NS_IMPL_GNUSTEP
5323       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + 3
5324         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5325 #else
5326       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5327         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5328 #endif
5329   if (rows < MINHEIGHT)
5330     rows = MINHEIGHT;
5331 #ifdef NS_IMPL_COCOA
5332   {
5333     /* this sets window title to have size in it; the wm does this under GS */
5334     NSRect r = [[self window] frame];
5335     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5336       {
5337         if (old_title != 0)
5338           {
5339             xfree (old_title);
5340             old_title = 0;
5341           }
5342       }
5343     else
5344       {
5345         char *size_title;
5346         NSWindow *window = [self window];
5347         if (old_title == 0)
5348           {
5349             const char *t = [[[self window] title] UTF8String];
5350             char *pos = strstr (t, "  â€”  ");
5351             if (pos)
5352               *pos = '\0';
5353             old_title = xstrdup (t);
5354           }
5355         size_title = xmalloc (strlen (old_title) + 40);
5356         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5357         [window setTitle: [NSString stringWithUTF8String: size_title]];
5358         [window display];
5359         xfree (size_title);
5360       }
5361   }
5362 #endif /* NS_IMPL_COCOA */
5363 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5365   return frameSize;
5369 - (void)windowDidResize: (NSNotification *)notification
5371 #ifdef NS_IMPL_GNUSTEP
5372   NSWindow *theWindow = [notification object];
5374    /* in GNUstep, at least currently, it's possible to get a didResize
5375       without getting a willResize.. therefore we need to act as if we got
5376       the willResize now */
5377   NSSize sz = [theWindow frame].size;
5378   sz = [self windowWillResize: theWindow toSize: sz];
5379 #endif /* NS_IMPL_GNUSTEP */
5381   NSTRACE (windowDidResize);
5382 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5384 #ifdef NS_IMPL_COCOA
5385   if (old_title != 0)
5386     {
5387       xfree (old_title);
5388       old_title = 0;
5389     }
5390 #endif /* NS_IMPL_COCOA */
5392   /* Avoid loop under GNUstep due to call at beginning of this function.
5393      (x_set_window_size causes a resize which causes
5394      a "windowDidResize" which calls x_set_window_size).  */
5395 #ifndef NS_IMPL_GNUSTEP
5396   if (cols > 0 && rows > 0)
5397     {
5398       if (ns_in_resize)
5399         x_set_window_size (emacsframe, 0, cols, rows);
5400       else
5401         {
5402           NSWindow *window = [self window];
5403           NSRect wr = [window frame];
5404           FRAME_PIXEL_WIDTH (emacsframe) = (int)wr.size.width
5405             - emacsframe->border_width;
5406           FRAME_PIXEL_HEIGHT (emacsframe) = (int)wr.size.height
5407             - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5408             - FRAME_TOOLBAR_HEIGHT (emacsframe);
5409           change_frame_size (emacsframe, rows, cols, 0, 0, 1);
5410           SET_FRAME_GARBAGED (emacsframe);
5411           cancel_mouse_face (emacsframe);
5412         }
5413     }
5414 #endif
5416   ns_send_appdefined (-1);
5420 - (void)windowDidBecomeKey: (NSNotification *)notification
5421 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5423   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5424   struct frame *old_focus = dpyinfo->x_focus_frame;
5426   NSTRACE (windowDidBecomeKey);
5428   if (emacsframe != old_focus)
5429     dpyinfo->x_focus_frame = emacsframe;
5431   ns_frame_rehighlight (emacsframe);
5433   if (emacs_event)
5434     {
5435       emacs_event->kind = FOCUS_IN_EVENT;
5436       EV_TRAILER ((id)nil);
5437     }
5441 - (void)windowDidResignKey: (NSNotification *)notification
5442 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5444   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5445   NSTRACE (windowDidResignKey);
5447   if (dpyinfo->x_focus_frame == emacsframe)
5448     dpyinfo->x_focus_frame = 0;
5450   ns_frame_rehighlight (emacsframe);
5452   /* FIXME: for some reason needed on second and subsequent clicks away
5453             from sole-frame Emacs to get hollow box to show */
5454   if (!windowClosing && [[self window] isVisible] == YES)
5455     {
5456       x_update_cursor (emacsframe, 1);
5457       x_set_frame_alpha (emacsframe);
5458     }
5460   if (emacs_event)
5461     {
5462       [self deleteWorkingText];
5463       emacs_event->kind = FOCUS_IN_EVENT;
5464       EV_TRAILER ((id)nil);
5465     }
5469 - (void)windowWillMiniaturize: sender
5471   NSTRACE (windowWillMiniaturize);
5475 - (BOOL)isFlipped
5477   return YES;
5481 - (BOOL)isOpaque
5483   return NO;
5487 - initFrameFromEmacs: (struct frame *)f
5489   NSRect r, wr;
5490   Lisp_Object tem;
5491   NSWindow *win;
5492   NSButton *toggleButton;
5493   NSSize sz;
5494   NSColor *col;
5495   NSString *name;
5497   NSTRACE (initFrameFromEmacs);
5499   windowClosing = NO;
5500   processingCompose = NO;
5501   scrollbarsNeedingUpdate = 0;
5503 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5505   ns_userRect = NSMakeRect (0, 0, 0, 0);
5506   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5507                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5508   [self initWithFrame: r];
5509   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5511   FRAME_NS_VIEW (f) = self;
5512   emacsframe = f;
5513   old_title = 0;
5515   win = [[EmacsWindow alloc]
5516             initWithContentRect: r
5517                       styleMask: (NSResizableWindowMask |
5518 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5519                                   NSTitledWindowMask |
5520 #endif
5521                                   NSMiniaturizableWindowMask |
5522                                   NSClosableWindowMask)
5523                         backing: NSBackingStoreBuffered
5524                           defer: YES];
5526   wr = [win frame];
5527   f->border_width = wr.size.width - r.size.width;
5528   FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5530   [win setAcceptsMouseMovedEvents: YES];
5531   [win setDelegate: self];
5532   [win useOptimizedDrawing: YES];
5534   sz.width = FRAME_COLUMN_WIDTH (f);
5535   sz.height = FRAME_LINE_HEIGHT (f);
5536   [win setResizeIncrements: sz];
5538   [[win contentView] addSubview: self];
5540   if (ns_drag_types)
5541     [self registerForDraggedTypes: ns_drag_types];
5543   tem = f->name;
5544   name = [NSString stringWithUTF8String:
5545                    NILP (tem) ? "Emacs" : SSDATA (tem)];
5546   [win setTitle: name];
5548   /* toolbar support */
5549   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5550                          [NSString stringWithFormat: @"Emacs Frame %d",
5551                                    ns_window_num]];
5552   [win setToolbar: toolbar];
5553   [toolbar setVisible: NO];
5554 #ifdef NS_IMPL_COCOA
5555   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5556   [toggleButton setTarget: self];
5557   [toggleButton setAction: @selector (toggleToolbar: )];
5558 #endif
5559   FRAME_TOOLBAR_HEIGHT (f) = 0;
5561   tem = f->icon_name;
5562   if (!NILP (tem))
5563     [win setMiniwindowTitle:
5564            [NSString stringWithUTF8String: SSDATA (tem)]];
5566   {
5567     NSScreen *screen = [win screen];
5569     if (screen != 0)
5570       [win setFrameTopLeftPoint: NSMakePoint
5571            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5572             IN_BOUND (-SCREENMAX,
5573                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5574   }
5576   [win makeFirstResponder: self];
5578   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5579                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5580   [win setBackgroundColor: col];
5581   if ([col alphaComponent] != 1.0)
5582     [win setOpaque: NO];
5584   [self allocateGState];
5586   [NSApp registerServicesMenuSendTypes: ns_send_types
5587                            returnTypes: nil];
5589   ns_window_num++;
5590   return self;
5594 - (void)windowDidMove: sender
5596   NSWindow *win = [self window];
5597   NSRect r = [win frame];
5598   NSArray *screens = [NSScreen screens];
5599   NSScreen *screen = [screens objectAtIndex: 0];
5601   NSTRACE (windowDidMove);
5603   if (!emacsframe->output_data.ns)
5604     return;
5605   if (screen != nil)
5606     {
5607       emacsframe->left_pos = r.origin.x;
5608       emacsframe->top_pos =
5609         [screen frame].size.height - (r.origin.y + r.size.height);
5610     }
5614 /* Called AFTER method below, but before our windowWillResize call there leads
5615    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5616    location so set_window_size moves the frame. */
5617 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5619   emacsframe->output_data.ns->zooming = 1;
5620   return YES;
5624 /* Override to do something slightly nonstandard, but nice.  First click on
5625    zoom button will zoom vertically.  Second will zoom completely.  Third
5626    returns to original. */
5627 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5628                         defaultFrame:(NSRect)defaultFrame
5630   NSRect result = [sender frame];
5632   NSTRACE (windowWillUseStandardFrame);
5634   if (abs (defaultFrame.size.height - result.size.height)
5635       > FRAME_LINE_HEIGHT (emacsframe))
5636     {
5637       /* first click */
5638       ns_userRect = result;
5639       result.size.height = defaultFrame.size.height;
5640       result.origin.y = defaultFrame.origin.y;
5641     }
5642   else
5643     {
5644       if (abs (defaultFrame.size.width - result.size.width)
5645           > FRAME_COLUMN_WIDTH (emacsframe))
5646         result = defaultFrame;  /* second click */
5647       else
5648         {
5649           /* restore */
5650           result = ns_userRect.size.height ? ns_userRect : result;
5651           ns_userRect = NSMakeRect (0, 0, 0, 0);
5652         }
5653     }
5655   [self windowWillResize: sender toSize: result.size];
5656   return result;
5660 - (void)windowDidDeminiaturize: sender
5662   NSTRACE (windowDidDeminiaturize);
5663   if (!emacsframe->output_data.ns)
5664     return;
5665   emacsframe->async_iconified = 0;
5666   emacsframe->async_visible   = 1;
5667   windows_or_buffers_changed++;
5669   if (emacs_event)
5670     {
5671       emacs_event->kind = ICONIFY_EVENT;
5672       EV_TRAILER ((id)nil);
5673     }
5677 - (void)windowDidExpose: sender
5679   NSTRACE (windowDidExpose);
5680   if (!emacsframe->output_data.ns)
5681     return;
5682   emacsframe->async_visible = 1;
5683   SET_FRAME_GARBAGED (emacsframe);
5685   if (send_appdefined)
5686     ns_send_appdefined (-1);
5690 - (void)windowDidMiniaturize: sender
5692   NSTRACE (windowDidMiniaturize);
5693   if (!emacsframe->output_data.ns)
5694     return;
5696   emacsframe->async_iconified = 1;
5697   emacsframe->async_visible = 0;
5699   if (emacs_event)
5700     {
5701       emacs_event->kind = ICONIFY_EVENT;
5702       EV_TRAILER ((id)nil);
5703     }
5707 - (void)mouseEntered: (NSEvent *)theEvent
5709   NSTRACE (mouseEntered);
5710   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5714 - (void)mouseExited: (NSEvent *)theEvent
5716   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
5718   NSTRACE (mouseExited);
5720   if (!hlinfo)
5721     return;
5723   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5725   if (emacsframe == hlinfo->mouse_face_mouse_frame)
5726     {
5727       clear_mouse_face (hlinfo);
5728       hlinfo->mouse_face_mouse_frame = 0;
5729     }
5733 - menuDown: sender
5735   NSTRACE (menuDown);
5736   if (context_menu_value == -1)
5737     context_menu_value = [sender tag];
5738   else 
5739     {
5740       NSInteger tag = [sender tag];
5741       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
5742                                     emacsframe->menu_bar_vector,
5743                                     (void *)tag);
5744     }
5746   ns_send_appdefined (-1);
5747   return self;
5751 - (EmacsToolbar *)toolbar
5753   return toolbar;
5757 /* this gets called on toolbar button click */
5758 - toolbarClicked: (id)item
5760   NSEvent *theEvent;
5761   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
5763   NSTRACE (toolbarClicked);
5765   if (!emacs_event)
5766     return self;
5768   /* send first event (for some reason two needed) */
5769   theEvent = [[self window] currentEvent];
5770   emacs_event->kind = TOOL_BAR_EVENT;
5771   XSETFRAME (emacs_event->arg, emacsframe);
5772   EV_TRAILER (theEvent);
5774   emacs_event->kind = TOOL_BAR_EVENT;
5775 /*   XSETINT (emacs_event->code, 0); */
5776   emacs_event->arg = AREF (emacsframe->tool_bar_items,
5777                            idx + TOOL_BAR_ITEM_KEY);
5778   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5779   EV_TRAILER (theEvent);
5780   return self;
5784 - toggleToolbar: (id)sender
5786   if (!emacs_event)
5787     return self;
5789   emacs_event->kind = NS_NONKEY_EVENT;
5790   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
5791   EV_TRAILER ((id)nil);
5792   return self;
5796 - (void)drawRect: (NSRect)rect
5798   int x = NSMinX (rect), y = NSMinY (rect);
5799   int width = NSWidth (rect), height = NSHeight (rect);
5801   NSTRACE (drawRect);
5803   if (!emacsframe || !emacsframe->output_data.ns || ns_in_resize)
5804     return;
5806   ns_clear_frame_area (emacsframe, x, y, width, height);
5807   expose_frame (emacsframe, x, y, width, height);
5809   /*
5810     drawRect: may be called (at least in OS X 10.5) for invisible
5811     views as well for some reason.  Thus, do not infer visibility
5812     here.
5814     emacsframe->async_visible = 1;
5815     emacsframe->async_iconified = 0;
5816   */
5820 /* NSDraggingDestination protocol methods.  Actually this is not really a
5821    protocol, but a category of Object.  O well...  */
5823 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
5825   NSTRACE (draggingEntered);
5826   return NSDragOperationGeneric;
5830 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
5832   return YES;
5836 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
5838   id pb;
5839   int x, y;
5840   NSString *type;
5841   NSEvent *theEvent = [[self window] currentEvent];
5842   NSPoint position;
5844   NSTRACE (performDragOperation);
5846   if (!emacs_event)
5847     return NO;
5849   position = [self convertPoint: [sender draggingLocation] fromView: nil];
5850   x = lrint (position.x);  y = lrint (position.y);
5852   pb = [sender draggingPasteboard];
5853   type = [pb availableTypeFromArray: ns_drag_types];
5854   if (type == 0)
5855     {
5856       return NO;
5857     }
5858   else if ([type isEqualToString: NSFilenamesPboardType])
5859     {
5860       NSArray *files;
5861       NSEnumerator *fenum;
5862       NSString *file;
5864       if (!(files = [pb propertyListForType: type]))
5865         return NO;
5867       fenum = [files objectEnumerator];
5868       while ( (file = [fenum nextObject]) )
5869         {
5870           emacs_event->kind = NS_NONKEY_EVENT;
5871           emacs_event->code = KEY_NS_DRAG_FILE;
5872           XSETINT (emacs_event->x, x);
5873           XSETINT (emacs_event->y, y);
5874           ns_input_file = append2 (ns_input_file,
5875                                    build_string ([file UTF8String]));
5876           emacs_event->modifiers = EV_MODIFIERS (theEvent);
5877           EV_TRAILER (theEvent);
5878         }
5879       return YES;
5880     }
5881   else if ([type isEqualToString: NSURLPboardType])
5882     {
5883       NSString *file;
5884       NSURL *fileURL;
5886       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
5887           [fileURL isFileURL] == NO)
5888         return NO;
5890       file = [fileURL path];
5891       emacs_event->kind = NS_NONKEY_EVENT;
5892       emacs_event->code = KEY_NS_DRAG_FILE;
5893       XSETINT (emacs_event->x, x);
5894       XSETINT (emacs_event->y, y);
5895       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
5896       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5897       EV_TRAILER (theEvent);
5898       return YES;
5899     }
5900   else if ([type isEqualToString: NSStringPboardType]
5901            || [type isEqualToString: NSTabularTextPboardType])
5902     {
5903       NSString *data;
5905       if (! (data = [pb stringForType: type]))
5906         return NO;
5908       emacs_event->kind = NS_NONKEY_EVENT;
5909       emacs_event->code = KEY_NS_DRAG_TEXT;
5910       XSETINT (emacs_event->x, x);
5911       XSETINT (emacs_event->y, y);
5912       ns_input_text = build_string ([data UTF8String]);
5913       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5914       EV_TRAILER (theEvent);
5915       return YES;
5916     }
5917   else if ([type isEqualToString: NSColorPboardType])
5918     {
5919       NSColor *c = [NSColor colorFromPasteboard: pb];
5920       emacs_event->kind = NS_NONKEY_EVENT;
5921       emacs_event->code = KEY_NS_DRAG_COLOR;
5922       XSETINT (emacs_event->x, x);
5923       XSETINT (emacs_event->y, y);
5924       ns_input_color = ns_color_to_lisp (c);
5925       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5926       EV_TRAILER (theEvent);
5927       return YES;
5928     }
5929   else if ([type isEqualToString: NSFontPboardType])
5930     {
5931       /* impl based on GNUstep NSTextView.m */
5932       NSData *data = [pb dataForType: NSFontPboardType];
5933       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
5934       NSFont *font = [dict objectForKey: NSFontAttributeName];
5935       char fontSize[10];
5937       if (font == nil)
5938         return NO;
5940       emacs_event->kind = NS_NONKEY_EVENT;
5941       emacs_event->code = KEY_NS_CHANGE_FONT;
5942       XSETINT (emacs_event->x, x);
5943       XSETINT (emacs_event->y, y);
5944       ns_input_font = build_string ([[font fontName] UTF8String]);
5945       snprintf (fontSize, 10, "%f", [font pointSize]);
5946       ns_input_fontsize = build_string (fontSize);
5947       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5948       EV_TRAILER (theEvent);
5949       return YES;
5950     }
5951   else
5952     {
5953       error ("Invalid data type in dragging pasteboard.");
5954       return NO;
5955     }
5959 - (id) validRequestorForSendType: (NSString *)typeSent
5960                       returnType: (NSString *)typeReturned
5962   NSTRACE (validRequestorForSendType);
5963   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
5964       && typeReturned == nil)
5965     {
5966       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
5967         return self;
5968     }
5970   return [super validRequestorForSendType: typeSent
5971                                returnType: typeReturned];
5975 /* The next two methods are part of NSServicesRequests informal protocol,
5976    supposedly called when a services menu item is chosen from this app.
5977    But this should not happen because we override the services menu with our
5978    own entries which call ns-perform-service.
5979    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
5980    So let's at least stub them out until further investigation can be done. */
5982 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
5984   /* we could call ns_string_from_pasteboard(pboard) here but then it should
5985      be written into the buffer in place of the existing selection..
5986      ordinary service calls go through functions defined in ns-win.el */
5987   return NO;
5990 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
5992   NSArray *typesDeclared;
5993   Lisp_Object val;
5995   /* We only support NSStringPboardType */
5996   if ([types containsObject:NSStringPboardType] == NO) {
5997     return NO;
5998   }
6000   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6001   if (CONSP (val) && SYMBOLP (XCAR (val)))
6002     {
6003       val = XCDR (val);
6004       if (CONSP (val) && NILP (XCDR (val)))
6005         val = XCAR (val);
6006     }
6007   if (! STRINGP (val))
6008     return NO;
6010   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6011   [pb declareTypes:typesDeclared owner:nil];
6012   ns_string_to_pasteboard (pb, val);
6013   return YES;
6017 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6018    (gives a miniaturized version of the window); currently we use the latter for
6019    frames whose active buffer doesn't correspond to any file
6020    (e.g., '*scratch*') */
6021 - setMiniwindowImage: (BOOL) setMini
6023   id image = [[self window] miniwindowImage];
6024   NSTRACE (setMiniwindowImage);
6026   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6027      about "AppleDockIconEnabled" notwithstanding, however the set message
6028      below has its effect nonetheless. */
6029   if (image != emacsframe->output_data.ns->miniimage)
6030     {
6031       if (image && [image isKindOfClass: [EmacsImage class]])
6032         [image release];
6033       [[self window] setMiniwindowImage:
6034                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6035     }
6037   return self;
6041 - (void) setRows: (int) r andColumns: (int) c
6043   rows = r;
6044   cols = c;
6047 @end  /* EmacsView */
6051 /* ==========================================================================
6053     EmacsWindow implementation
6055    ========================================================================== */
6057 @implementation EmacsWindow
6059 #ifdef NS_IMPL_COCOA
6060 - (id)accessibilityAttributeValue:(NSString *)attribute
6062   Lisp_Object str = Qnil;
6063   struct frame *f = SELECTED_FRAME ();
6064   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->buffer);
6066   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6067     return NSAccessibilityTextFieldRole;
6069   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6070       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6071     {
6072       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6073     }
6074   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
6075     {
6076       if (! NILP (BVAR (curbuf, mark_active)))
6077           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6078       
6079       if (NILP (str))
6080         {
6081           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
6082           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
6083           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
6084           
6085           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
6086             str = make_uninit_multibyte_string (range, byte_range);
6087           else
6088             str = make_uninit_string (range);
6089           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
6090              Is this a problem?  */
6091           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
6092         }
6093     }
6094   
6095   
6096   if (! NILP (str)) 
6097     {
6098       if (CONSP (str) && SYMBOLP (XCAR (str)))
6099         {
6100           str = XCDR (str);
6101           if (CONSP (str) && NILP (XCDR (str)))
6102             str = XCAR (str);
6103         }
6104       if (STRINGP (str))
6105         {
6106           const char *utfStr = SSDATA (str);
6107           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
6108           return nsStr;
6109         }
6110     }
6111   
6112   return [super accessibilityAttributeValue:attribute];
6114 #endif /* NS_IMPL_COCOA */
6116 /* If we have multiple monitors, one above the other, we don't want to
6117    restrict the height to just one monitor.  So we override this.  */
6118 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6120   /* When making the frame visible for the first time or if there is just
6121      one screen, we want to constrain.  Other times not.  */
6122   NSUInteger nr_screens = [[NSScreen screens] count];
6123   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6124   NSTRACE (constrainFrameRect);
6126   if (nr_screens == 1)
6127     return [super constrainFrameRect:frameRect toScreen:screen];
6129   if (f->output_data.ns->dont_constrain
6130       || ns_menu_bar_should_be_hidden ())
6131     return frameRect;
6133   f->output_data.ns->dont_constrain = 1;
6134   return [super constrainFrameRect:frameRect toScreen:screen];
6138 /* called only on resize clicks by special case in EmacsApp-sendEvent */
6139 - (void)mouseDown: (NSEvent *)theEvent
6141   if (ns_in_resize)
6142     {
6143       NSSize size = [[theEvent window] frame].size;
6144       grabOffset = [theEvent locationInWindow];
6145       grabOffset.x = size.width - grabOffset.x;
6146     }
6147   else
6148     [super mouseDown: theEvent];
6152 /* stop resizing */
6153 - (void)mouseUp: (NSEvent *)theEvent
6155   if (ns_in_resize)
6156     {
6157       struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6158       ns_in_resize = NO;
6159       ns_set_name_as_filename (f);
6160       [self display];
6161       ns_send_appdefined (-1);
6162     }
6163   else
6164     [super mouseUp: theEvent];
6168 /* send resize events */
6169 - (void)mouseDragged: (NSEvent *)theEvent
6171   if (ns_in_resize)
6172     {
6173       NSPoint p = [theEvent locationInWindow];
6174       NSSize size, vettedSize, origSize = [self frame].size;
6176       size.width = p.x + grabOffset.x;
6177       size.height = origSize.height - p.y + grabOffset.y;
6179       if (size.width == origSize.width && size.height == origSize.height)
6180         return;
6182       vettedSize = [[self delegate] windowWillResize: self toSize: size];
6183       [[NSNotificationCenter defaultCenter]
6184             postNotificationName: NSWindowDidResizeNotification
6185                           object: self];
6186     }
6187   else
6188     [super mouseDragged: theEvent];
6191 @end /* EmacsWindow */
6194 /* ==========================================================================
6196     EmacsScroller implementation
6198    ========================================================================== */
6201 @implementation EmacsScroller
6203 /* for repeat button push */
6204 #define SCROLL_BAR_FIRST_DELAY 0.5
6205 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6207 + (CGFloat) scrollerWidth
6209   /* TODO: if we want to allow variable widths, this is the place to do it,
6210            however neither GNUstep nor Cocoa support it very well */
6211   return [NSScroller scrollerWidth];
6215 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6217   NSTRACE (EmacsScroller_initFrame);
6219   r.size.width = [EmacsScroller scrollerWidth];
6220   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6221   [self setContinuous: YES];
6222   [self setEnabled: YES];
6224   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6225      locked against the top and bottom edges, and right edge on OS X, where
6226      scrollers are on right. */
6227 #ifdef NS_IMPL_GNUSTEP
6228   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6229 #else
6230   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6231 #endif
6233   win = nwin;
6234   condemned = NO;
6235   pixel_height = NSHeight (r);
6236   if (pixel_height == 0) pixel_height = 1;
6237   min_portion = 20 / pixel_height;
6239   frame = XFRAME (XWINDOW (win)->frame);
6240   if (FRAME_LIVE_P (frame))
6241     {
6242       int i;
6243       EmacsView *view = FRAME_NS_VIEW (frame);
6244       NSView *sview = [[view window] contentView];
6245       NSArray *subs = [sview subviews];
6247       /* disable optimization stopping redraw of other scrollbars */
6248       view->scrollbarsNeedingUpdate = 0;
6249       for (i =[subs count]-1; i >= 0; i--)
6250         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6251           view->scrollbarsNeedingUpdate++;
6252       [sview addSubview: self];
6253     }
6255 /*  [self setFrame: r]; */
6257   return self;
6261 - (void)setFrame: (NSRect)newRect
6263   NSTRACE (EmacsScroller_setFrame);
6264 /*  BLOCK_INPUT; */
6265   pixel_height = NSHeight (newRect);
6266   if (pixel_height == 0) pixel_height = 1;
6267   min_portion = 20 / pixel_height;
6268   [super setFrame: newRect];
6269   [self display];
6270 /*  UNBLOCK_INPUT; */
6274 - (void)dealloc
6276   NSTRACE (EmacsScroller_dealloc);
6277   if (!NILP (win))
6278     WSET (XWINDOW (win), vertical_scroll_bar, Qnil);
6279   [super dealloc];
6283 - condemn
6285   NSTRACE (condemn);
6286   condemned =YES;
6287   return self;
6291 - reprieve
6293   NSTRACE (reprieve);
6294   condemned =NO;
6295   return self;
6299 - judge
6301   NSTRACE (judge);
6302   if (condemned)
6303     {
6304       EmacsView *view;
6305       BLOCK_INPUT;
6306       /* ensure other scrollbar updates after deletion */
6307       view = (EmacsView *)FRAME_NS_VIEW (frame);
6308       if (view != nil)
6309         view->scrollbarsNeedingUpdate++;
6310       [self removeFromSuperview];
6311       [self release];
6312       UNBLOCK_INPUT;
6313     }
6314   return self;
6318 - (void)resetCursorRects
6320   NSRect visible = [self visibleRect];
6321   NSTRACE (resetCursorRects);
6323   if (!NSIsEmptyRect (visible))
6324     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6325   [[NSCursor arrowCursor] setOnMouseEntered: YES];
6329 - (int) checkSamePosition: (int) position portion: (int) portion
6330                     whole: (int) whole
6332   return em_position ==position && em_portion ==portion && em_whole ==whole
6333     && portion != whole; /* needed for resize empty buf */
6337 - setPosition: (int)position portion: (int)portion whole: (int)whole
6339   NSTRACE (setPosition);
6341   em_position = position;
6342   em_portion = portion;
6343   em_whole = whole;
6345   if (portion >= whole)
6346     {
6347 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6348       [self setKnobProportion: 1.0];
6349       [self setDoubleValue: 1.0];
6350 #else
6351       [self setFloatValue: 0.0 knobProportion: 1.0];
6352 #endif
6353     }
6354   else
6355     {
6356       float pos, por;
6357       portion = max ((float)whole*min_portion/pixel_height, portion);
6358       pos = (float)position / (whole - portion);
6359       por = (float)portion/whole;
6360 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6361       [self setKnobProportion: por];
6362       [self setDoubleValue: pos];
6363 #else
6364       [self setFloatValue: pos knobProportion: por];
6365 #endif
6366     }
6367   return self;
6370 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6371      drag events will go directly to the EmacsScroller.  Leaving in for now. */
6372 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6373                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
6375   *part = last_hit_part;
6376   *window = win;
6377   XSETINT (*y, pixel_height);
6378   if ([self floatValue] > 0.999)
6379     XSETINT (*x, pixel_height);
6380   else
6381     XSETINT (*x, pixel_height * [self floatValue]);
6385 /* set up emacs_event */
6386 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6388   if (!emacs_event)
6389     return;
6391   emacs_event->part = last_hit_part;
6392   emacs_event->code = 0;
6393   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
6394   emacs_event->frame_or_window = win;
6395   emacs_event->timestamp = EV_TIMESTAMP (e);
6396   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
6397   emacs_event->arg = Qnil;
6398   XSETINT (emacs_event->x, loc * pixel_height);
6399   XSETINT (emacs_event->y, pixel_height-20);
6401   n_emacs_events_pending++;
6402   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
6403   EVENT_INIT (*emacs_event);
6404   ns_send_appdefined (-1);
6408 /* called manually thru timer to implement repeated button action w/hold-down */
6409 - repeatScroll: (NSTimer *)scrollEntry
6411   NSEvent *e = [[self window] currentEvent];
6412   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
6413   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
6415   /* clear timer if need be */
6416   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
6417     {
6418         [scroll_repeat_entry invalidate];
6419         [scroll_repeat_entry release];
6420         scroll_repeat_entry = nil;
6422         if (inKnob)
6423           return self;
6425         scroll_repeat_entry
6426           = [[NSTimer scheduledTimerWithTimeInterval:
6427                         SCROLL_BAR_CONTINUOUS_DELAY
6428                                             target: self
6429                                           selector: @selector (repeatScroll:)
6430                                           userInfo: 0
6431                                            repeats: YES]
6432               retain];
6433     }
6435   [self sendScrollEventAtLoc: 0 fromEvent: e];
6436   return self;
6440 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
6441    mouseDragged events without going into a modal loop. */
6442 - (void)mouseDown: (NSEvent *)e
6444   NSRect sr, kr;
6445   /* hitPart is only updated AFTER event is passed on */
6446   NSScrollerPart part = [self testPart: [e locationInWindow]];
6447   double inc = 0.0, loc, kloc, pos;
6448   int edge = 0;
6450   NSTRACE (EmacsScroller_mouseDown);
6452   switch (part)
6453     {
6454     case NSScrollerDecrementPage:
6455         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
6456     case NSScrollerIncrementPage:
6457         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
6458     case NSScrollerDecrementLine:
6459       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
6460     case NSScrollerIncrementLine:
6461       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
6462     case NSScrollerKnob:
6463       last_hit_part = scroll_bar_handle; break;
6464     case NSScrollerKnobSlot:  /* GNUstep-only */
6465       last_hit_part = scroll_bar_move_ratio; break;
6466     default:  /* NSScrollerNoPart? */
6467       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
6468                (long) part);
6469       return;
6470     }
6472   if (inc != 0.0)
6473     {
6474       pos = 0;      /* ignored */
6476       /* set a timer to repeat, as we can't let superclass do this modally */
6477       scroll_repeat_entry
6478         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
6479                                             target: self
6480                                           selector: @selector (repeatScroll:)
6481                                           userInfo: 0
6482                                            repeats: YES]
6483             retain];
6484     }
6485   else
6486     {
6487       /* handle, or on GNUstep possibly slot */
6488       NSEvent *fake_event;
6490       /* compute float loc in slot and mouse offset on knob */
6491       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6492                       toView: nil];
6493       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6494       if (loc <= 0.0)
6495         {
6496           loc = 0.0;
6497           edge = -1;
6498         }
6499       else if (loc >= NSHeight (sr))
6500         {
6501           loc = NSHeight (sr);
6502           edge = 1;
6503         }
6505       if (edge)
6506         kloc = 0.5 * edge;
6507       else
6508         {
6509           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
6510                           toView: nil];
6511           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
6512         }
6513       last_mouse_offset = kloc;
6515       /* if knob, tell emacs a location offset by knob pos
6516          (to indicate top of handle) */
6517       if (part == NSScrollerKnob)
6518           pos = (loc - last_mouse_offset) / NSHeight (sr);
6519       else
6520         /* else this is a slot click on GNUstep: go straight there */
6521         pos = loc / NSHeight (sr);
6523       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
6524       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
6525                                       location: [e locationInWindow]
6526                                  modifierFlags: [e modifierFlags]
6527                                      timestamp: [e timestamp]
6528                                   windowNumber: [e windowNumber]
6529                                        context: [e context]
6530                                    eventNumber: [e eventNumber]
6531                                     clickCount: [e clickCount]
6532                                       pressure: [e pressure]];
6533       [super mouseUp: fake_event];
6534     }
6536   if (part != NSScrollerKnob)
6537     [self sendScrollEventAtLoc: pos fromEvent: e];
6541 /* Called as we manually track scroller drags, rather than superclass. */
6542 - (void)mouseDragged: (NSEvent *)e
6544     NSRect sr;
6545     double loc, pos;
6546     int edge = 0;
6548     NSTRACE (EmacsScroller_mouseDragged);
6550       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6551                       toView: nil];
6552       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6554       if (loc <= 0.0)
6555         {
6556           loc = 0.0;
6557           edge = -1;
6558         }
6559       else if (loc >= NSHeight (sr) + last_mouse_offset)
6560         {
6561           loc = NSHeight (sr) + last_mouse_offset;
6562           edge = 1;
6563         }
6565       pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
6566       [self sendScrollEventAtLoc: pos fromEvent: e];
6570 - (void)mouseUp: (NSEvent *)e
6572   if (scroll_repeat_entry)
6573     {
6574       [scroll_repeat_entry invalidate];
6575       [scroll_repeat_entry release];
6576       scroll_repeat_entry = nil;
6577     }
6578   last_hit_part = 0;
6582 /* treat scrollwheel events in the bar as though they were in the main window */
6583 - (void) scrollWheel: (NSEvent *)theEvent
6585   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
6586   [view mouseDown: theEvent];
6589 @end  /* EmacsScroller */
6594 /* ==========================================================================
6596    Font-related functions; these used to be in nsfaces.m
6598    ========================================================================== */
6601 Lisp_Object
6602 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
6604   struct font *font = XFONT_OBJECT (font_object);
6606   if (fontset < 0)
6607     fontset = fontset_from_font (font_object);
6608   FRAME_FONTSET (f) = fontset;
6610   if (FRAME_FONT (f) == font)
6611     /* This font is already set in frame F.  There's nothing more to
6612        do.  */
6613     return font_object;
6615   FRAME_FONT (f) = font;
6617   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
6618   FRAME_COLUMN_WIDTH (f) = font->average_width;
6619   FRAME_SPACE_WIDTH (f) = font->space_width;
6620   FRAME_LINE_HEIGHT (f) = font->height;
6622   compute_fringe_widths (f, 1);
6624   /* Compute the scroll bar width in character columns.  */
6625   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6626     {
6627       int wid = FRAME_COLUMN_WIDTH (f);
6628       FRAME_CONFIG_SCROLL_BAR_COLS (f)
6629         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
6630     }
6631   else
6632     {
6633       int wid = FRAME_COLUMN_WIDTH (f);
6634       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6635     }
6637   /* Now make the frame display the given font.  */
6638   if (FRAME_NS_WINDOW (f) != 0)
6639         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6641   return font_object;
6645 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
6646 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
6647          in 1.43. */
6649 const char *
6650 ns_xlfd_to_fontname (const char *xlfd)
6651 /* --------------------------------------------------------------------------
6652     Convert an X font name (XLFD) to an NS font name.
6653     Only family is used.
6654     The string returned is temporarily allocated.
6655    -------------------------------------------------------------------------- */
6657   char *name = xmalloc (180);
6658   int i, len;
6659   const char *ret;
6661   if (!strncmp (xlfd, "--", 2))
6662     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
6663   else
6664     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
6666   /* stopgap for malformed XLFD input */
6667   if (strlen (name) == 0)
6668     strcpy (name, "Monaco");
6670   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
6671      also uppercase after '-' or ' ' */
6672   name[0] = toupper (name[0]);
6673   for (len =strlen (name), i =0; i<len; i++)
6674     {
6675       if (name[i] == '$')
6676         {
6677           name[i] = '-';
6678           if (i+1<len)
6679             name[i+1] = toupper (name[i+1]);
6680         }
6681       else if (name[i] == '_')
6682         {
6683           name[i] = ' ';
6684           if (i+1<len)
6685             name[i+1] = toupper (name[i+1]);
6686         }
6687     }
6688 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
6689   ret = [[NSString stringWithUTF8String: name] UTF8String];
6690   xfree (name);
6691   return ret;
6695 void
6696 syms_of_nsterm (void)
6698   NSTRACE (syms_of_nsterm);
6700   ns_antialias_threshold = 10.0;
6702   /* from 23+ we need to tell emacs what modifiers there are.. */
6703   DEFSYM (Qmodifier_value, "modifier-value");
6704   DEFSYM (Qalt, "alt");
6705   DEFSYM (Qhyper, "hyper");
6706   DEFSYM (Qmeta, "meta");
6707   DEFSYM (Qsuper, "super");
6708   DEFSYM (Qcontrol, "control");
6709   DEFSYM (QUTF8_STRING, "UTF8_STRING");
6711   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
6712   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
6713   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
6714   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
6715   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
6717   DEFVAR_LISP ("ns-input-file", ns_input_file,
6718               "The file specified in the last NS event.");
6719   ns_input_file =Qnil;
6721   DEFVAR_LISP ("ns-input-text", ns_input_text,
6722               "The data received in the last NS text drag event.");
6723   ns_input_text =Qnil;
6725   DEFVAR_LISP ("ns-working-text", ns_working_text,
6726               "String for visualizing working composition sequence.");
6727   ns_working_text =Qnil;
6729   DEFVAR_LISP ("ns-input-font", ns_input_font,
6730               "The font specified in the last NS event.");
6731   ns_input_font =Qnil;
6733   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
6734               "The fontsize specified in the last NS event.");
6735   ns_input_fontsize =Qnil;
6737   DEFVAR_LISP ("ns-input-line", ns_input_line,
6738                "The line specified in the last NS event.");
6739   ns_input_line =Qnil;
6741   DEFVAR_LISP ("ns-input-color", ns_input_color,
6742                "The color specified in the last NS event.");
6743   ns_input_color =Qnil;
6745   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
6746                "The service name specified in the last NS event.");
6747   ns_input_spi_name =Qnil;
6749   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
6750                "The service argument specified in the last NS event.");
6751   ns_input_spi_arg =Qnil;
6753   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
6754                "This variable describes the behavior of the alternate or option key.\n\
6755 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6756 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6757 at all, allowing it to be used at a lower level for accented character entry.");
6758   ns_alternate_modifier = Qmeta;
6760   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
6761                "This variable describes the behavior of the right alternate or option key.\n\
6762 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6763 Set to left means be the same key as `ns-alternate-modifier'.\n\
6764 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6765 at all, allowing it to be used at a lower level for accented character entry.");
6766   ns_right_alternate_modifier = Qleft;
6768   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
6769                "This variable describes the behavior of the command key.\n\
6770 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6771   ns_command_modifier = Qsuper;
6773   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
6774                "This variable describes the behavior of the right command key.\n\
6775 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6776 Set to left means be the same key as `ns-command-modifier'.\n\
6777 Set to none means that the command / option key is not interpreted by Emacs\n\
6778 at all, allowing it to be used at a lower level for accented character entry.");
6779   ns_right_command_modifier = Qleft;
6781   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
6782                "This variable describes the behavior of the control key.\n\
6783 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6784   ns_control_modifier = Qcontrol;
6786   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
6787                "This variable describes the behavior of the right control key.\n\
6788 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6789 Set to left means be the same key as `ns-control-modifier'.\n\
6790 Set to none means that the control / option key is not interpreted by Emacs\n\
6791 at all, allowing it to be used at a lower level for accented character entry.");
6792   ns_right_control_modifier = Qleft;
6794   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
6795                "This variable describes the behavior of the function key (on laptops).\n\
6796 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6797 Set to none means that the function key is not interpreted by Emacs at all,\n\
6798 allowing it to be used at a lower level for accented character entry.");
6799   ns_function_modifier = Qnone;
6801   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
6802                "Non-nil (the default) means to render text antialiased. Only has an effect on OS X Panther and above.");
6803   ns_antialias_text = Qt;
6805   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
6806                "Whether to confirm application quit using dialog.");
6807   ns_confirm_quit = Qnil;
6809   staticpro (&ns_display_name_list);
6810   ns_display_name_list = Qnil;
6812   staticpro (&last_mouse_motion_frame);
6813   last_mouse_motion_frame = Qnil;
6815   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
6816                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
6817 Only works on OSX 10.6 or later.  */);
6818   ns_auto_hide_menu_bar = Qnil;
6820   /* TODO: move to common code */
6821   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
6822                doc: /* Which toolkit scroll bars Emacs uses, if any.
6823 A value of nil means Emacs doesn't use toolkit scroll bars.
6824 With the X Window system, the value is a symbol describing the
6825 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
6826 With MS Windows or Nextstep, the value is t.  */);
6827   Vx_toolkit_scroll_bars = Qt;
6829   DEFVAR_BOOL ("x-use-underline-position-properties",
6830                x_use_underline_position_properties,
6831      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
6832 A value of nil means ignore them.  If you encounter fonts with bogus
6833 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
6834 to 4.1, set this to nil. */);
6835   x_use_underline_position_properties = 0;
6837   DEFVAR_BOOL ("x-underline-at-descent-line",
6838                x_underline_at_descent_line,
6839      doc: /* Non-nil means to draw the underline at the same place as the descent line.
6840 A value of nil means to draw the underline according to the value of the
6841 variable `x-use-underline-position-properties', which is usually at the
6842 baseline level.  The default value is nil.  */);
6843   x_underline_at_descent_line = 0;
6845   /* Tell emacs about this window system. */
6846   Fprovide (intern ("ns"), Qnil);