* maintaining.texi (Registering, Tag Syntax): Tweak line and page breaks.
[emacs.git] / src / nsterm.m
blob7cbaf9913111c40d77da7ec43b771ea14414e36f
1 /* NeXT/Open/GNUstep / MacOSX communication module.
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2012
4   Free Software Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
22 Originally by Carl Edman
23 Updated by Christian Limpach (chris@nice.ch)
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25 MacOSX/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
26 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
29 /* This should be the first include, as it may set up #defines affecting
30    interpretation of even the system includes. */
31 #include <config.h>
33 #include <math.h>
34 #include <sys/types.h>
35 #include <time.h>
36 #include <signal.h>
37 #include <unistd.h>
38 #include <setjmp.h>
40 #include "lisp.h"
41 #include "blockinput.h"
42 #include "sysselect.h"
43 #include "nsterm.h"
44 #include "systime.h"
45 #include "character.h"
46 #include "fontset.h"
47 #include "composite.h"
48 #include "ccl.h"
50 #include "termhooks.h"
51 #include "termopts.h"
52 #include "termchar.h"
54 #include "window.h"
55 #include "keyboard.h"
57 #include "font.h"
59 /* call tracing */
60 #if 0
61 int term_trace_num = 0;
62 #define NSTRACE(x)        fprintf (stderr, "%s:%d: [%d] " #x "\n",         \
63                                 __FILE__, __LINE__, ++term_trace_num)
64 #else
65 #define NSTRACE(x)
66 #endif
68 extern NSString *NSMenuDidBeginTrackingNotification;
70 /* ==========================================================================
72     Local declarations
74    ========================================================================== */
76 /* Convert a symbol indexed with an NSxxx value to a value as defined
77    in keyboard.c (lispy_function_key). I hope this is a correct way
78    of doing things... */
79 static unsigned convert_ns_to_X_keysym[] =
81   NSHomeFunctionKey,            0x50,
82   NSLeftArrowFunctionKey,       0x51,
83   NSUpArrowFunctionKey,         0x52,
84   NSRightArrowFunctionKey,      0x53,
85   NSDownArrowFunctionKey,       0x54,
86   NSPageUpFunctionKey,          0x55,
87   NSPageDownFunctionKey,        0x56,
88   NSEndFunctionKey,             0x57,
89   NSBeginFunctionKey,           0x58,
90   NSSelectFunctionKey,          0x60,
91   NSPrintFunctionKey,           0x61,
92   NSExecuteFunctionKey,         0x62,
93   NSInsertFunctionKey,          0x63,
94   NSUndoFunctionKey,            0x65,
95   NSRedoFunctionKey,            0x66,
96   NSMenuFunctionKey,            0x67,
97   NSFindFunctionKey,            0x68,
98   NSHelpFunctionKey,            0x6A,
99   NSBreakFunctionKey,           0x6B,
101   NSF1FunctionKey,              0xBE,
102   NSF2FunctionKey,              0xBF,
103   NSF3FunctionKey,              0xC0,
104   NSF4FunctionKey,              0xC1,
105   NSF5FunctionKey,              0xC2,
106   NSF6FunctionKey,              0xC3,
107   NSF7FunctionKey,              0xC4,
108   NSF8FunctionKey,              0xC5,
109   NSF9FunctionKey,              0xC6,
110   NSF10FunctionKey,             0xC7,
111   NSF11FunctionKey,             0xC8,
112   NSF12FunctionKey,             0xC9,
113   NSF13FunctionKey,             0xCA,
114   NSF14FunctionKey,             0xCB,
115   NSF15FunctionKey,             0xCC,
116   NSF16FunctionKey,             0xCD,
117   NSF17FunctionKey,             0xCE,
118   NSF18FunctionKey,             0xCF,
119   NSF19FunctionKey,             0xD0,
120   NSF20FunctionKey,             0xD1,
121   NSF21FunctionKey,             0xD2,
122   NSF22FunctionKey,             0xD3,
123   NSF23FunctionKey,             0xD4,
124   NSF24FunctionKey,             0xD5,
126   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
127   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
128   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
130   NSTabCharacter,               0x09,
131   0x19,                         0x09,  /* left tab->regular since pass shift */
132   NSCarriageReturnCharacter,    0x0D,
133   NSNewlineCharacter,           0x0D,
134   NSEnterCharacter,             0x8D,
136   0x1B,                         0x1B   /* escape */
139 static Lisp_Object Qmodifier_value;
140 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper, Qnone;
141 extern Lisp_Object Qcursor_color, Qcursor_type, Qns, Qleft;
143 static Lisp_Object QUTF8_STRING;
145 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
146    the maximum font size to NOT antialias.  On GNUstep there is currently
147    no way to control this behavior. */
148 float ns_antialias_threshold;
150 /* Used to pick up AppleHighlightColor on OS X */
151 NSString *ns_selection_color;
153 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
154 NSString *ns_app_name = @"Emacs";  /* default changed later */
156 /* Display variables */
157 struct ns_display_info *x_display_list; /* Chain of existing displays */
158 Lisp_Object ns_display_name_list;
159 long context_menu_value = 0;
161 /* display update */
162 NSPoint last_mouse_motion_position;
163 static NSRect last_mouse_glyph;
164 static Time last_mouse_movement_time = 0;
165 static Lisp_Object last_mouse_motion_frame;
166 static EmacsScroller *last_mouse_scroll_bar = nil;
167 static struct frame *ns_updating_frame;
168 static NSView *focus_view = NULL;
169 static int ns_window_num = 0;
170 static NSRect uRect;
171 static BOOL gsaved = NO;
172 BOOL ns_in_resize = NO;
173 static BOOL ns_fake_keydown = NO;
174 int ns_tmp_flags; /* FIXME */
175 struct nsfont_info *ns_tmp_font; /* FIXME */
176 static BOOL ns_menu_bar_is_hidden = NO;
177 /*static int debug_lock = 0; */
179 /* event loop */
180 static BOOL send_appdefined = YES;
181 static NSEvent *last_appdefined_event = 0;
182 static NSTimer *timed_entry = 0;
183 static NSTimer *fd_entry = nil;
184 static NSTimer *scroll_repeat_entry = nil;
185 static fd_set select_readfds, t_readfds;
186 static struct timeval select_timeout;
187 static int select_nfds;
188 static NSAutoreleasePool *outerpool;
189 static struct input_event *emacs_event = NULL;
190 static struct input_event *q_event_ptr = NULL;
191 static int n_emacs_events_pending = 0;
192 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
193   *ns_pending_service_args;
194 static BOOL inNsSelect = 0;
196 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
197 #define NS_FUNCTION_KEY_MASK 0x800000
198 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
199 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
200 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
201 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
202 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
203 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
204 #define EV_MODIFIERS(e)                               \
205     ((([e modifierFlags] & NSHelpKeyMask) ?           \
206            hyper_modifier : 0)                        \
207      | (!EQ (ns_right_alternate_modifier, Qleft) && \
208         (([e modifierFlags] & NSRightAlternateKeyMask) \
209          == NSRightAlternateKeyMask) ? \
210            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
211      | (([e modifierFlags] & NSAlternateKeyMask) ?                 \
212            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
213      | (([e modifierFlags] & NSShiftKeyMask) ?     \
214            shift_modifier : 0)                        \
215      | (!EQ (ns_right_control_modifier, Qleft) && \
216         (([e modifierFlags] & NSRightControlKeyMask) \
217          == NSRightControlKeyMask) ? \
218            parse_solitary_modifier (ns_right_control_modifier) : 0) \
219      | (([e modifierFlags] & NSControlKeyMask) ?      \
220            parse_solitary_modifier (ns_control_modifier) : 0)     \
221      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
222            parse_solitary_modifier (ns_function_modifier) : 0)    \
223      | (!EQ (ns_right_command_modifier, Qleft) && \
224         (([e modifierFlags] & NSRightCommandKeyMask) \
225          == NSRightCommandKeyMask) ? \
226            parse_solitary_modifier (ns_right_command_modifier) : 0) \
227      | (([e modifierFlags] & NSCommandKeyMask) ?      \
228            parse_solitary_modifier (ns_command_modifier):0))
230 #define EV_UDMODIFIERS(e)                                      \
231     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
232      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
233      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
234      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
235      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
236      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
237      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
238      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
239      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
241 #define EV_BUTTON(e)                                                         \
242     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
243       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
244      [e buttonNumber] - 1)
246 /* Convert the time field to a timestamp in milliseconds. */
247 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
249 /* This is a piece of code which is common to all the event handling
250    methods.  Maybe it should even be a function.  */
251 #define EV_TRAILER(e)                                         \
252   {                                                           \
253   XSETFRAME (emacs_event->frame_or_window, emacsframe);       \
254   if (e) emacs_event->timestamp = EV_TIMESTAMP (e);           \
255   n_emacs_events_pending++;                                   \
256   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);     \
257   EVENT_INIT (*emacs_event);                                  \
258   ns_send_appdefined (-1);                                    \
259   }
261 void x_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
263 /* TODO: get rid of need for these forward declarations */
264 static void ns_condemn_scroll_bars (struct frame *f);
265 static void ns_judge_scroll_bars (struct frame *f);
266 void x_set_frame_alpha (struct frame *f);
269 /* ==========================================================================
271     Utilities
273    ========================================================================== */
276 static Lisp_Object
277 append2 (Lisp_Object list, Lisp_Object item)
278 /* --------------------------------------------------------------------------
279    Utility to append to a list
280    -------------------------------------------------------------------------- */
282   Lisp_Object array[2];
283   array[0] = list;
284   array[1] = Fcons (item, Qnil);
285   return Fnconc (2, &array[0]);
289 void
290 ns_init_paths (void)
291 /* --------------------------------------------------------------------------
292    Used to allow emacs to find its resources under Emacs.app
293    Called from emacs.c at startup.
294    -------------------------------------------------------------------------- */
296   NSBundle *bundle = [NSBundle mainBundle];
297   NSString *binDir = [bundle bundlePath], *resourceDir = [bundle resourcePath];
298   NSString *resourcePath, *resourcePaths;
299   NSRange range;
300   BOOL onWindows = NO; /* how do I determine this? */
301   NSString *pathSeparator = onWindows ? @";" : @":";
302   NSFileManager *fileManager = [NSFileManager defaultManager];
303   BOOL isDir;
304 /*NSLog (@"ns_init_paths: '%@'\n%@\n", [[NSBundle mainBundle] bundlePath], [[NSBundle mainBundle] resourcePath]); */
306   /* get bindir from base */
307   range = [resourceDir rangeOfString: @"Contents"];
308   if (range.location != NSNotFound)
309     {
310       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
311 #ifdef NS_IMPL_COCOA
312       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
313 #endif
314     }
316   /* the following based on Andrew Choi's init_mac_osx_environment () */
317   if (!getenv ("EMACSLOADPATH"))
318     {
319       NSArray *paths = [resourceDir stringsByAppendingPaths:
320                                   [NSArray arrayWithObjects:
321                                          @"site-lisp", @"lisp", @"leim", nil]];
322       NSEnumerator *pathEnum = [paths objectEnumerator];
323       resourcePaths = @"";
324       while (resourcePath = [pathEnum nextObject])
325         {
326           if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
327             if (isDir)
328               {
329                 if ([resourcePaths length] > 0)
330                   resourcePaths
331                     = [resourcePaths stringByAppendingString: pathSeparator];
332                 resourcePaths
333                   = [resourcePaths stringByAppendingString: resourcePath];
334               }
335         }
336       if ([resourcePaths length] > 0)
337         setenv ("EMACSLOADPATH", [resourcePaths UTF8String], 1);
338 /*NSLog (@"loadPath: '%@'\n", resourcePaths); */
339     }
341   if (!getenv ("EMACSPATH"))
342     {
343       NSArray *paths = [binDir stringsByAppendingPaths:
344                                   [NSArray arrayWithObjects: @"bin",
345                                                              @"lib-exec", nil]];
346       NSEnumerator *pathEnum = [paths objectEnumerator];
347       resourcePaths = @"";
348       while (resourcePath = [pathEnum nextObject])
349         {
350           if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
351             if (isDir)
352               {
353                 if ([resourcePaths length] > 0)
354                   resourcePaths
355                     = [resourcePaths stringByAppendingString: pathSeparator];
356                 resourcePaths
357                   = [resourcePaths stringByAppendingString: resourcePath];
358               }
359         }
360       if ([resourcePaths length] > 0)
361         setenv ("EMACSPATH", [resourcePaths UTF8String], 1);
362     }
364   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
365   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
366     {
367       if (isDir)
368         {
369           if (!getenv ("EMACSDATA"))
370             setenv ("EMACSDATA", [resourcePath UTF8String], 1);
371           if (!getenv ("EMACSDOC"))
372             setenv ("EMACSDOC", [resourcePath UTF8String], 1);
373         }
374     }
376   if (!getenv ("INFOPATH"))
377     {
378       resourcePath = [resourceDir stringByAppendingPathComponent: @"info"];
379       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
380         if (isDir)
381           setenv ("INFOPATH", [[resourcePath stringByAppendingString: @":"]
382                                              UTF8String], 1);
383       /* Note, extra colon needed to cause merge w/later user additions. */
384     }
388 static int
389 timeval_subtract (struct timeval *result, struct timeval x, struct timeval y)
390 /* --------------------------------------------------------------------------
391    Subtract the `struct timeval' values X and Y, storing the result in RESULT.
392    Return 1 if the difference is negative, otherwise 0.
393    -------------------------------------------------------------------------- */
395   /* Perform the carry for the later subtraction by updating y.
396      This is safer because on some systems
397      the tv_sec member is unsigned.  */
398   if (x.tv_usec < y.tv_usec)
399     {
400       int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
401       y.tv_usec -= 1000000 * nsec;
402       y.tv_sec += nsec;
403     }
404   if (x.tv_usec - y.tv_usec > 1000000)
405     {
406       int nsec = (y.tv_usec - x.tv_usec) / 1000000;
407       y.tv_usec += 1000000 * nsec;
408       y.tv_sec -= nsec;
409     }
411   /* Compute the time remaining to wait.  tv_usec is certainly positive.  */
412   result->tv_sec = x.tv_sec - y.tv_sec;
413   result->tv_usec = x.tv_usec - y.tv_usec;
415   /* Return indication of whether the result should be considered negative.  */
416   return x.tv_sec < y.tv_sec;
419 static void
420 ns_timeout (int usecs)
421 /* --------------------------------------------------------------------------
422      Blocking timer utility used by ns_ring_bell
423    -------------------------------------------------------------------------- */
425   struct timeval wakeup;
427   EMACS_GET_TIME (wakeup);
429   /* Compute time to wait until, propagating carry from usecs.  */
430   wakeup.tv_usec += usecs;
431   wakeup.tv_sec += (wakeup.tv_usec / 1000000);
432   wakeup.tv_usec %= 1000000;
434   /* Keep waiting until past the time wakeup.  */
435   while (1)
436     {
437       struct timeval timeout;
439       EMACS_GET_TIME (timeout);
441       /* In effect, timeout = wakeup - timeout.
442          Break if result would be negative.  */
443       if (timeval_subtract (&timeout, wakeup, timeout))
444         break;
446       /* Try to wait that long--but we might wake up sooner.  */
447       select (0, NULL, NULL, NULL, &timeout);
448     }
452 void
453 ns_release_object (void *obj)
454 /* --------------------------------------------------------------------------
455     Release an object (callable from C)
456    -------------------------------------------------------------------------- */
458     [(id)obj release];
462 void
463 ns_retain_object (void *obj)
464 /* --------------------------------------------------------------------------
465     Retain an object (callable from C)
466    -------------------------------------------------------------------------- */
468     [(id)obj retain];
472 void *
473 ns_alloc_autorelease_pool (void)
474 /* --------------------------------------------------------------------------
475      Allocate a pool for temporary objects (callable from C)
476    -------------------------------------------------------------------------- */
478   return [[NSAutoreleasePool alloc] init];
482 void
483 ns_release_autorelease_pool (void *pool)
484 /* --------------------------------------------------------------------------
485      Free a pool and temporary objects it refers to (callable from C)
486    -------------------------------------------------------------------------- */
488   ns_release_object (pool);
493 /* ==========================================================================
495     Focus (clipping) and screen update
497    ========================================================================== */
499 static NSRect
500 ns_resize_handle_rect (NSWindow *window)
502   NSRect r = [window frame];
503   r.origin.x = r.size.width - RESIZE_HANDLE_SIZE;
504   r.origin.y = 0;
505   r.size.width = r.size.height = RESIZE_HANDLE_SIZE;
506   return r;
511 // Window constraining
512 // -------------------
514 // To ensure that the windows are not placed under the menu bar, they
515 // are typically moved by the call-back constrainFrameRect. However,
516 // by overriding it, it's possible to inhibit this, leaving the window
517 // in it's original position.
519 // It's possible to hide the menu bar. However, technically, it's only
520 // possible to hide it when the application is active. To ensure that
521 // this work properly, the menu bar and window constraining are
522 // deferred until the application becomes active.
524 // Even though it's not possible to manually move a window above the
525 // top of the screen, it is allowed if it's done programmatically,
526 // when the menu is hidden. This allows the editable area to cover the
527 // full screen height.
529 // Test cases
530 // ----------
532 // Use the following extra files:
534 //    init.el:
535 //       ;; Hide menu and place frame slightly above the top of the screen.
536 //       (setq ns-auto-hide-menu-bar t)
537 //       (set-frame-position (selected-frame) 0 -20)
539 // Test 1:
541 //    emacs -Q -l init.el
543 //    Result: No menu bar, and the title bar should be above the screen.
545 // Test 2:
547 //    emacs -Q
549 //    Result: Menu bar visible, frame placed immediately below the menu.
552 static void
553 ns_constrain_all_frames (void)
555   Lisp_Object tail, frame;
557   FOR_EACH_FRAME (tail, frame)
558     {
559       struct frame *f = XFRAME (frame);
560       if (FRAME_NS_P (f))
561         {
562           NSView *view = FRAME_NS_VIEW (f);
563           /* This no-op will trigger the default window placing
564            * constraint system. */
565           f->output_data.ns->dont_constrain = 0;
566           [[view window] setFrameOrigin:[[view window] frame].origin];
567         }
568     }
572 /* True, if the menu bar should be hidden.  */
574 static BOOL
575 ns_menu_bar_should_be_hidden (void)
577   return !NILP (ns_auto_hide_menu_bar)
578     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
582 /* Show or hide the menu bar, based on user setting.  */
584 static void
585 ns_update_auto_hide_menu_bar (void)
587 #ifndef MAC_OS_X_VERSION_10_6
588 #define MAC_OS_X_VERSION_10_6 1060
589 #endif
590 #ifdef NS_IMPL_COCOA
591 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
592   BLOCK_INPUT;
594   NSTRACE (ns_update_auto_hide_menu_bar);
596   if (NSApp != nil
597       && [NSApp isActive]
598       && [NSApp respondsToSelector:@selector(setPresentationOptions:)])
599     {
600       // Note, "setPresentationOptions" triggers an error unless the
601       // application is active.
602       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
604       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
605         {
606           NSApplicationPresentationOptions options
607             = NSApplicationPresentationAutoHideDock;
609           if (menu_bar_should_be_hidden)
610             options |= NSApplicationPresentationAutoHideMenuBar;
612           [NSApp setPresentationOptions: options];
614           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
616           if (!ns_menu_bar_is_hidden)
617             {
618               ns_constrain_all_frames ();
619             }
620         }
621     }
623   UNBLOCK_INPUT;
624 #endif
625 #endif
629 static void
630 ns_update_begin (struct frame *f)
631 /* --------------------------------------------------------------------------
632    Prepare for a grouped sequence of drawing calls
633    external (RIF) call; whole frame, called before update_window_begin
634    -------------------------------------------------------------------------- */
636   NSView *view = FRAME_NS_VIEW (f);
637   NSTRACE (ns_update_begin);
639   ns_update_auto_hide_menu_bar ();
641   ns_updating_frame = f;
642   [view lockFocus];
644 #ifdef NS_IMPL_GNUSTEP
645   uRect = NSMakeRect (0, 0, 0, 0);
646 #endif
650 static void
651 ns_update_window_begin (struct window *w)
652 /* --------------------------------------------------------------------------
653    Prepare for a grouped sequence of drawing calls
654    external (RIF) call; for one window, called after update_begin
655    -------------------------------------------------------------------------- */
657   struct frame *f = XFRAME (WINDOW_FRAME (w));
658  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
659   NSTRACE (ns_update_window_begin);
661   updated_window = w;
662   set_output_cursor (&w->cursor);
664   BLOCK_INPUT;
666   if (f == hlinfo->mouse_face_mouse_frame)
667     {
668       /* Don't do highlighting for mouse motion during the update.  */
669       hlinfo->mouse_face_defer = 1;
671         /* If the frame needs to be redrawn,
672            simply forget about any prior mouse highlighting.  */
673       if (FRAME_GARBAGED_P (f))
674         hlinfo->mouse_face_window = Qnil;
676       /* (further code for mouse faces ifdef'd out in other terms elided) */
677     }
679   UNBLOCK_INPUT;
683 static void
684 ns_update_window_end (struct window *w, int cursor_on_p,
685                       int mouse_face_overwritten_p)
686 /* --------------------------------------------------------------------------
687    Finished a grouped sequence of drawing calls
688    external (RIF) call; for one window called before update_end
689    -------------------------------------------------------------------------- */
691   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
693   /* note: this fn is nearly identical in all terms */
694   if (!w->pseudo_window_p)
695     {
696       BLOCK_INPUT;
698       if (cursor_on_p)
699         display_and_set_cursor (w, 1,
700                                 output_cursor.hpos, output_cursor.vpos,
701                                 output_cursor.x, output_cursor.y);
703       if (draw_window_fringes (w, 1))
704         x_draw_vertical_border (w);
706       UNBLOCK_INPUT;
707     }
709   /* If a row with mouse-face was overwritten, arrange for
710      frame_up_to_date to redisplay the mouse highlight.  */
711   if (mouse_face_overwritten_p)
712     {
713       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
714       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
715       hlinfo->mouse_face_window = Qnil;
716     }
718   updated_window = NULL;
719   NSTRACE (update_window_end);
723 static void
724 ns_update_end (struct frame *f)
725 /* --------------------------------------------------------------------------
726    Finished a grouped sequence of drawing calls
727    external (RIF) call; for whole frame, called after update_window_end
728    -------------------------------------------------------------------------- */
730   NSView *view = FRAME_NS_VIEW (f);
732 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
733     MOUSE_HL_INFO (f)->mouse_face_defer = 0;
735   BLOCK_INPUT;
737 #ifdef NS_IMPL_GNUSTEP
738   /* trigger flush only in the rectangle we tracked as being drawn */
739   [view unlockFocusNeedsFlush: NO];
740 /*fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", uRect.origin.x, uRect.origin.y, uRect.size.width, uRect.size.height); */
741   [view lockFocusInRect: uRect];
742 #endif
744   [view unlockFocus];
745   [[view window] flushWindow];
747   UNBLOCK_INPUT;
748   ns_updating_frame = NULL;
749   NSTRACE (ns_update_end);
753 static void
754 ns_flush (struct frame *f)
755 /* --------------------------------------------------------------------------
756    external (RIF) call
757    NS impl is no-op since currently we flush in ns_update_end and elsewhere
758    -------------------------------------------------------------------------- */
760     NSTRACE (ns_flush);
764 static void
765 ns_focus (struct frame *f, NSRect *r, int n)
766 /* --------------------------------------------------------------------------
767    Internal: Focus on given frame.  During small local updates this is used to
768      draw, however during large updates, ns_update_begin and ns_update_end are
769      called to wrap the whole thing, in which case these calls are stubbed out.
770      Except, on GNUstep, we accumulate the rectangle being drawn into, because
771      the back end won't do this automatically, and will just end up flushing
772      the entire window.
773    -------------------------------------------------------------------------- */
775 //  NSTRACE (ns_focus);
776 #ifdef NS_IMPL_GNUSTEP
777   NSRect u;
778     if (n == 2)
779       u = NSUnionRect (r[0], r[1]);
780     else if (r)
781       u = *r;
782 #endif
783 /* static int c =0;
784    fprintf (stderr, "focus: %d", c++);
785    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
786    fprintf (stderr, "\n"); */
788   if (f != ns_updating_frame)
789     {
790       NSView *view = FRAME_NS_VIEW (f);
791       if (view != focus_view)
792         {
793           if (focus_view != NULL)
794             {
795               [focus_view unlockFocus];
796               [[focus_view window] flushWindow];
797 /*debug_lock--; */
798             }
800           if (view)
801 #ifdef NS_IMPL_GNUSTEP
802             r ? [view lockFocusInRect: u] : [view lockFocus];
803 #else
804             [view lockFocus];
805 #endif
806           focus_view = view;
807 /*if (view) debug_lock++; */
808         }
809 #ifdef NS_IMPL_GNUSTEP
810       else
811         {
812           /* more than one rect being drawn into */
813           if (view && r)
814             {
815               [view unlockFocus]; /* add prev rect to redraw list */
816               [view lockFocusInRect: u]; /* focus for draw in new rect */
817             }
818         }
819 #endif
820     }
821 #ifdef NS_IMPL_GNUSTEP
822   else
823     {
824       /* in batch mode, but in GNUstep must still track rectangles explicitly */
825       uRect = (r ? NSUnionRect (uRect, u) : [FRAME_NS_VIEW (f) visibleRect]);
826     }
827 #endif
829   /* clipping */
830   if (r)
831     {
832       [[NSGraphicsContext currentContext] saveGraphicsState];
833       if (n == 2)
834         NSRectClipList (r, 2);
835       else
836         NSRectClip (*r);
837       gsaved = YES;
838     }
842 static void
843 ns_unfocus (struct frame *f)
844 /* --------------------------------------------------------------------------
845      Internal: Remove focus on given frame
846    -------------------------------------------------------------------------- */
848 //  NSTRACE (ns_unfocus);
850   if (gsaved)
851     {
852       [[NSGraphicsContext currentContext] restoreGraphicsState];
853       gsaved = NO;
854     }
856   if (f != ns_updating_frame)
857     {
858       if (focus_view != NULL)
859         {
860           [focus_view unlockFocus];
861           [[focus_view window] flushWindow];
862           focus_view = NULL;
863 /*debug_lock--; */
864         }
865     }
869 static void
870 ns_clip_to_row (struct window *w, struct glyph_row *row, int area, BOOL gc)
871 /* --------------------------------------------------------------------------
872      Internal (but parallels other terms): Focus drawing on given row
873    -------------------------------------------------------------------------- */
875   struct frame *f = XFRAME (WINDOW_FRAME (w));
876   NSRect clip_rect;
877   int window_x, window_y, window_width;
879   window_box (w, area, &window_x, &window_y, &window_width, 0);
881   clip_rect.origin.x = window_x - FRAME_INTERNAL_BORDER_WIDTH (f);
882   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
883   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
884   clip_rect.size.width = window_width + 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
885   clip_rect.size.height = row->visible_height;
887   /* allow a full-height row at the top when requested
888      (used to draw fringe all the way through internal border area) */
889   if (gc && clip_rect.origin.y < 5)
890     {
891       clip_rect.origin.y -= FRAME_INTERNAL_BORDER_WIDTH (f);
892       clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
893     }
895   /* likewise at bottom */
896   if (gc &&
897       FRAME_PIXEL_HEIGHT (f) - (clip_rect.origin.y + clip_rect.size.height) < 5)
898     clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
900   ns_focus (f, &clip_rect, 1);
904 static void
905 ns_ring_bell (struct frame *f)
906 /* --------------------------------------------------------------------------
907      "Beep" routine
908    -------------------------------------------------------------------------- */
910   NSTRACE (ns_ring_bell);
911   if (visible_bell)
912     {
913       NSAutoreleasePool *pool;
914       struct frame *frame = SELECTED_FRAME ();
915       NSView *view;
917       BLOCK_INPUT;
918       pool = [[NSAutoreleasePool alloc] init];
920       view = FRAME_NS_VIEW (frame);
921       if (view != nil)
922         {
923           NSRect r, surr;
924           NSPoint dim = NSMakePoint (128, 128);
926           r = [view bounds];
927           r.origin.x += (r.size.width - dim.x) / 2;
928           r.origin.y += (r.size.height - dim.y) / 2;
929           r.size.width = dim.x;
930           r.size.height = dim.y;
931           surr = NSInsetRect (r, -2, -2);
932           ns_focus (frame, &surr, 1);
933           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
934           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
935                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
936           NSRectFill (r);
937           [[view window] flushWindow];
938           ns_timeout (150000);
939           [[view window] restoreCachedImage];
940           [[view window] flushWindow];
941           ns_unfocus (frame);
942         }
943       [pool release];
944       UNBLOCK_INPUT;
945     }
946   else
947     {
948       NSBeep ();
949     }
953 static void
954 ns_reset_terminal_modes (struct terminal *terminal)
955 /*  Externally called as hook */
957   NSTRACE (ns_reset_terminal_modes);
961 static void
962 ns_set_terminal_modes (struct terminal *terminal)
963 /*  Externally called as hook */
965   NSTRACE (ns_set_terminal_modes);
970 /* ==========================================================================
972     Frame / window manager related functions
974    ========================================================================== */
977 static void
978 ns_raise_frame (struct frame *f)
979 /* --------------------------------------------------------------------------
980      Bring window to foreground and make it active
981    -------------------------------------------------------------------------- */
983   NSView *view = FRAME_NS_VIEW (f);
984   check_ns ();
985   BLOCK_INPUT;
986   FRAME_SAMPLE_VISIBILITY (f);
987   if (FRAME_VISIBLE_P (f))
988     {
989       [[view window] makeKeyAndOrderFront: NSApp];
990     }
991   UNBLOCK_INPUT;
995 static void
996 ns_lower_frame (struct frame *f)
997 /* --------------------------------------------------------------------------
998      Send window to back
999    -------------------------------------------------------------------------- */
1001   NSView *view = FRAME_NS_VIEW (f);
1002   check_ns ();
1003   BLOCK_INPUT;
1004   [[view window] orderBack: NSApp];
1005   UNBLOCK_INPUT;
1009 static void
1010 ns_frame_raise_lower (struct frame *f, int raise)
1011 /* --------------------------------------------------------------------------
1012      External (hook)
1013    -------------------------------------------------------------------------- */
1015   NSTRACE (ns_frame_raise_lower);
1017   if (raise)
1018     ns_raise_frame (f);
1019   else
1020     ns_lower_frame (f);
1024 static void
1025 ns_frame_rehighlight (struct frame *frame)
1026 /* --------------------------------------------------------------------------
1027      External (hook): called on things like window switching within frame
1028    -------------------------------------------------------------------------- */
1030   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
1031   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1033   NSTRACE (ns_frame_rehighlight);
1034   if (dpyinfo->x_focus_frame)
1035     {
1036       dpyinfo->x_highlight_frame
1037         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1038            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1039            : dpyinfo->x_focus_frame);
1040       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1041         {
1042           FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
1043           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1044         }
1045     }
1046   else
1047       dpyinfo->x_highlight_frame = 0;
1049   if (dpyinfo->x_highlight_frame &&
1050          dpyinfo->x_highlight_frame != old_highlight)
1051     {
1052       if (old_highlight)
1053         {
1054           x_update_cursor (old_highlight, 1);
1055           x_set_frame_alpha (old_highlight);
1056         }
1057       if (dpyinfo->x_highlight_frame)
1058         {
1059           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1060           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1061         }
1062     }
1066 void
1067 x_make_frame_visible (struct frame *f)
1068 /* --------------------------------------------------------------------------
1069      External: Show the window (X11 semantics)
1070    -------------------------------------------------------------------------- */
1072   NSTRACE (x_make_frame_visible);
1073   /* XXX: at some points in past this was not needed, as the only place that
1074      called this (frame.c:Fraise_frame ()) also called raise_lower;
1075      if this ends up the case again, comment this out again. */
1076   if (!FRAME_VISIBLE_P (f))
1077     {
1078       f->async_visible = 1;
1079       ns_raise_frame (f);
1080     }
1084 void
1085 x_make_frame_invisible (struct frame *f)
1086 /* --------------------------------------------------------------------------
1087      External: Hide the window (X11 semantics)
1088    -------------------------------------------------------------------------- */
1090   NSView * view = FRAME_NS_VIEW (f);
1091   NSTRACE (x_make_frame_invisible);
1092   check_ns ();
1093   [[view window] orderOut: NSApp];
1094   f->async_visible = 0;
1095   f->async_iconified = 0;
1099 void
1100 x_iconify_frame (struct frame *f)
1101 /* --------------------------------------------------------------------------
1102      External: Iconify window
1103    -------------------------------------------------------------------------- */
1105   NSView * view = FRAME_NS_VIEW (f);
1106   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1107   NSTRACE (x_iconify_frame);
1108   check_ns ();
1110   if (dpyinfo->x_highlight_frame == f)
1111     dpyinfo->x_highlight_frame = 0;
1113   if ([[view window] windowNumber] <= 0)
1114     {
1115       /* the window is still deferred.  Make it very small, bring it
1116          on screen and order it out. */
1117       NSRect s = { { 100, 100}, {0, 0} };
1118       NSRect t;
1119       t = [[view window] frame];
1120       [[view window] setFrame: s display: NO];
1121       [[view window] orderBack: NSApp];
1122       [[view window] orderOut: NSApp];
1123       [[view window] setFrame: t display: NO];
1124     }
1125   [[view window] miniaturize: NSApp];
1128 /* Free X resources of frame F.  */
1130 void
1131 x_free_frame_resources (struct frame *f)
1133   NSView *view = FRAME_NS_VIEW (f);
1134   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1135   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1136   NSTRACE (x_destroy_window);
1137   check_ns ();
1139   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1141   BLOCK_INPUT;
1143   free_frame_menubar (f);
1145   if (FRAME_FACE_CACHE (f))
1146     free_frame_faces (f);
1148   if (f == dpyinfo->x_focus_frame)
1149     dpyinfo->x_focus_frame = 0;
1150   if (f == dpyinfo->x_highlight_frame)
1151     dpyinfo->x_highlight_frame = 0;
1152   if (f == hlinfo->mouse_face_mouse_frame)
1153     {
1154       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
1155       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
1156       hlinfo->mouse_face_window = Qnil;
1157       hlinfo->mouse_face_deferred_gc = 0;
1158       hlinfo->mouse_face_mouse_frame = 0;
1159     }
1161   xfree (f->output_data.ns);
1163   if (f->output_data.ns->miniimage != nil)
1164     [f->output_data.ns->miniimage release];
1166   [[view window] close];
1167   [view release];
1169   UNBLOCK_INPUT;
1172 void
1173 x_destroy_window (struct frame *f)
1174 /* --------------------------------------------------------------------------
1175      External: Delete the window
1176    -------------------------------------------------------------------------- */
1178   NSTRACE (x_destroy_window);
1179   check_ns ();
1180   x_free_frame_resources (f);
1181   ns_window_num--;
1185 void
1186 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1187 /* --------------------------------------------------------------------------
1188      External: Position the window
1189    -------------------------------------------------------------------------- */
1191   NSView *view = FRAME_NS_VIEW (f);
1192   NSArray *screens = [NSScreen screens];
1193   NSScreen *fscreen = [screens objectAtIndex: 0];
1194   NSScreen *screen = [[view window] screen];
1196   NSTRACE (x_set_offset);
1198   BLOCK_INPUT;
1200   f->left_pos = xoff;
1201   f->top_pos = yoff;
1203   if (view != nil && screen && fscreen)
1204     {
1205       f->left_pos = f->size_hint_flags & XNegative
1206         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1207         : f->left_pos;
1208       /* We use visibleFrame here to take menu bar into account.
1209          Ideally we should also adjust left/top with visibleFrame.origin.  */
1211       f->top_pos = f->size_hint_flags & YNegative
1212         ? ([screen visibleFrame].size.height + f->top_pos
1213            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1214            - FRAME_TOOLBAR_HEIGHT (f))
1215         : f->top_pos;
1216 #ifdef NS_IMPL_GNUSTEP
1217       if (f->left_pos < 100)
1218         f->left_pos = 100;  /* don't overlap menu */
1219 #endif
1220       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1221          menu bar.  */
1222       f->output_data.ns->dont_constrain = 0;
1223       [[view window] setFrameTopLeftPoint:
1224                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1225                                     SCREENMAXBOUND ([fscreen frame].size.height
1226                                                     - NS_TOP_POS (f)))];
1227       f->size_hint_flags &= ~(XNegative|YNegative);
1228     }
1230   UNBLOCK_INPUT;
1234 void
1235 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1236 /* --------------------------------------------------------------------------
1237      Adjust window pixel size based on given character grid size
1238      Impl is a bit more complex than other terms, need to do some
1239      internal clipping.
1240    -------------------------------------------------------------------------- */
1242   EmacsView *view = FRAME_NS_VIEW (f);
1243   EmacsToolbar *toolbar = [view toolbar];
1244   NSWindow *window = [view window];
1245   NSRect wr = [window frame];
1246   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1247   int pixelwidth, pixelheight;
1248   static int oldRows, oldCols, oldFontWidth, oldFontHeight;
1249   static int oldTB;
1250   static struct frame *oldF;
1252   NSTRACE (x_set_window_size);
1254   if (view == nil ||
1255       (f == oldF
1256        && rows == oldRows && cols == oldCols
1257        && oldFontWidth == FRAME_COLUMN_WIDTH (f)
1258        && oldFontHeight == FRAME_LINE_HEIGHT (f)
1259        && oldTB == tb))
1260     return;
1262 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1264   BLOCK_INPUT;
1266   check_frame_size (f, &rows, &cols);
1267   oldF = f;
1268   oldRows = rows;
1269   oldCols = cols;
1270   oldFontWidth = FRAME_COLUMN_WIDTH (f);
1271   oldFontHeight = FRAME_LINE_HEIGHT (f);
1272   oldTB = tb;
1274   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1275   compute_fringe_widths (f, 0);
1277   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1278   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1280   /* If we have a toolbar, take its height into account. */
1281   if (tb)
1282     /* NOTE: previously this would generate wrong result if toolbar not
1283              yet displayed and fixing toolbar_height=32 helped, but
1284              now (200903) seems no longer needed */
1285     FRAME_TOOLBAR_HEIGHT (f) =
1286       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1287         - FRAME_NS_TITLEBAR_HEIGHT (f);
1288   else
1289     FRAME_TOOLBAR_HEIGHT (f) = 0;
1291   wr.size.width = pixelwidth + f->border_width;
1292   wr.size.height = pixelheight + FRAME_NS_TITLEBAR_HEIGHT (f)
1293                   + FRAME_TOOLBAR_HEIGHT (f);
1295   /* Do not try to constrain to this screen.  We may have multiple
1296      screens, and want Emacs to span those.  Constraining to screen
1297      prevents that, and that is not nice to the user.  */
1298  if (f->output_data.ns->zooming)
1299    f->output_data.ns->zooming = 0;
1300  else
1301    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1303   [view setRows: rows andColumns: cols];
1304   [window setFrame: wr display: YES];
1306 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1308   /* This is a trick to compensate for Emacs' managing the scrollbar area
1309      as a fixed number of standard character columns.  Instead of leaving
1310      blank space for the extra, we chopped it off above.  Now for
1311      left-hand scrollbars, we shift all rendering to the left by the
1312      difference between the real width and Emacs' imagined one.  For
1313      right-hand bars, don't worry about it since the extra is never used.
1314      (Obviously doesn't work for vertically split windows tho..) */
1315   {
1316     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1317       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1318                      - NS_SCROLL_BAR_WIDTH (f), 0)
1319       : NSMakePoint (0, 0);
1320     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1321     [view setBoundsOrigin: origin];
1322   }
1324   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1325   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1326   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1327 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1329   mark_window_cursors_off (XWINDOW (f->root_window));
1330   cancel_mouse_face (f);
1332   UNBLOCK_INPUT;
1337 /* ==========================================================================
1339     Color management
1341    ========================================================================== */
1344 NSColor *
1345 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1347   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1348   if (idx < 1 || idx >= color_table->avail)
1349     return nil;
1350   return color_table->colors[idx];
1354 unsigned long
1355 ns_index_color (NSColor *color, struct frame *f)
1357   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1358   ptrdiff_t idx;
1359   ptrdiff_t i;
1361   if (!color_table->colors)
1362     {
1363       color_table->size = NS_COLOR_CAPACITY;
1364       color_table->avail = 1; /* skip idx=0 as marker */
1365       color_table->colors
1366         = (NSColor **)xmalloc (color_table->size * sizeof (NSColor *));
1367       color_table->colors[0] = nil;
1368       color_table->empty_indices = [[NSMutableSet alloc] init];
1369     }
1371   /* do we already have this color ? */
1372   for (i = 1; i < color_table->avail; i++)
1373     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1374       return i;
1376   if ([color_table->empty_indices count] > 0)
1377     {
1378       NSNumber *index = [color_table->empty_indices anyObject];
1379       [color_table->empty_indices removeObject: index];
1380       idx = [index unsignedLongValue];
1381     }
1382   else
1383     {
1384       if (color_table->avail == color_table->size)
1385         color_table->colors =
1386           xpalloc (color_table->colors, &color_table->size, 1,
1387                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1388       idx = color_table->avail++;
1389     }
1391   color_table->colors[idx] = color;
1392   [color retain];
1393 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1394   return idx;
1398 void
1399 ns_free_indexed_color (unsigned long idx, struct frame *f)
1401   struct ns_color_table *color_table;
1402   NSColor *color;
1403   NSNumber *index;
1405   if (!f)
1406     return;
1408   color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1410   if (idx <= 0 || idx >= color_table->size) {
1411     message1 ("ns_free_indexed_color: Color index out of range.\n");
1412     return;
1413   }
1415   index = [NSNumber numberWithUnsignedInt: idx];
1416   if ([color_table->empty_indices containsObject: index]) {
1417     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1418     return;
1419   }
1421   color = color_table->colors[idx];
1422   [color release];
1423   color_table->colors[idx] = nil;
1424   [color_table->empty_indices addObject: index];
1425 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1429 static int
1430 ns_get_color (const char *name, NSColor **col)
1431 /* --------------------------------------------------------------------------
1432      Parse a color name
1433    -------------------------------------------------------------------------- */
1434 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1435    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1436    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1438   NSColor *new = nil;
1439   static char hex[20];
1440   int scaling;
1441   float r = -1.0, g, b;
1442   NSString *nsname = [NSString stringWithUTF8String: name];
1444 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1445   BLOCK_INPUT;
1447   if ([nsname isEqualToString: @"ns_selection_color"])
1448     {
1449       nsname = ns_selection_color;
1450       name = [ns_selection_color UTF8String];
1451     }
1453   /* First, check for some sort of numeric specification. */
1454   hex[0] = '\0';
1456   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1457     {
1458       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1459       [scanner scanFloat: &r];
1460       [scanner scanFloat: &g];
1461       [scanner scanFloat: &b];
1462     }
1463   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1464     {
1465       strncpy (hex, name + 4, 19);
1466       hex[19] = '\0';
1467       scaling = (strlen(hex) - 2) / 3;
1468     }
1469   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1470     {
1471       int len = (strlen(name) - 1);
1472       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1473       int i;
1474       scaling = strlen(name+start) / 3;
1475       for (i=0; i<3; i++) {
1476         strncpy(hex + i * (scaling + 1), name + start + i * scaling, scaling);
1477         hex[(i+1) * (scaling + 1) - 1] = '/';
1478       }
1479       hex[3 * (scaling + 1) - 1] = '\0';
1480     }
1482   if (hex[0])
1483     {
1484       int rr, gg, bb;
1485       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1486       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1487         {
1488           r = rr / fscale;
1489           g = gg / fscale;
1490           b = bb / fscale;
1491         }
1492     }
1494   if (r >= 0.0)
1495     {
1496       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1497       UNBLOCK_INPUT;
1498       return 0;
1499     }
1501   /* Otherwise, color is expected to be from a list */
1502   {
1503     NSEnumerator *lenum, *cenum;
1504     NSString *name;
1505     NSColorList *clist;
1507 #ifdef NS_IMPL_GNUSTEP
1508     /* XXX: who is wrong, the requestor or the implementation? */
1509     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1510         == NSOrderedSame)
1511       nsname = @"highlightColor";
1512 #endif
1514     lenum = [[NSColorList availableColorLists] objectEnumerator];
1515     while ( (clist = [lenum nextObject]) && new == nil)
1516       {
1517         cenum = [[clist allKeys] objectEnumerator];
1518         while ( (name = [cenum nextObject]) && new == nil )
1519           {
1520             if ([name compare: nsname
1521                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1522               new = [clist colorWithKey: name];
1523           }
1524       }
1525   }
1527   if (new)
1528     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1529   UNBLOCK_INPUT;
1530   return new ? 0 : 1;
1534 static NSColor *
1535 ns_get_color_default (const char *name, NSColor *dflt)
1536 /* --------------------------------------------------------------------------
1537      Parse a color or use a default value
1538    -------------------------------------------------------------------------- */
1540   NSColor * col;
1542   if (ns_get_color (name, &col))
1543     return dflt;
1544   else
1545     return col;
1550 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1551 /* --------------------------------------------------------------------------
1552      Convert a Lisp string object to a NS color
1553    -------------------------------------------------------------------------- */
1555   NSTRACE (ns_lisp_to_color);
1556   if (STRINGP (color))
1557     return ns_get_color (SDATA (color), col);
1558   else if (SYMBOLP (color))
1559     return ns_get_color (SDATA (SYMBOL_NAME (color)), col);
1560   return 1;
1564 Lisp_Object
1565 ns_color_to_lisp (NSColor *col)
1566 /* --------------------------------------------------------------------------
1567      Convert a color to a lisp string with the RGB equivalent
1568    -------------------------------------------------------------------------- */
1570   CGFloat red, green, blue, alpha, gray;
1571   char buf[1024];
1572   const char *str;
1573   NSTRACE (ns_color_to_lisp);
1575   BLOCK_INPUT;
1576   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1578       if ((str =[[col colorNameComponent] UTF8String]))
1579         {
1580           UNBLOCK_INPUT;
1581           return build_string ((char *)str);
1582         }
1584     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1585         getRed: &red green: &green blue: &blue alpha: &alpha];
1586   if (red ==green && red ==blue)
1587     {
1588       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1589             getWhite: &gray alpha: &alpha];
1590       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1591                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1592       UNBLOCK_INPUT;
1593       return build_string (buf);
1594     }
1596   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1597             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1599   UNBLOCK_INPUT;
1600   return build_string (buf);
1604 void
1605 ns_query_color(void *col, XColor *color_def, int setPixel)
1606 /* --------------------------------------------------------------------------
1607          Get ARGB values out of NSColor col and put them into color_def.
1608          If setPixel, set the pixel to a concatenated version.
1609          and set color_def pixel to the resulting index.
1610    -------------------------------------------------------------------------- */
1612   CGFloat r, g, b, a;
1614   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1615   color_def->red   = r * 65535;
1616   color_def->green = g * 65535;
1617   color_def->blue  = b * 65535;
1619   if (setPixel == YES)
1620     color_def->pixel
1621       = ARGB_TO_ULONG((int)(a*255),
1622                       (int)(r*255), (int)(g*255), (int)(b*255));
1627 ns_defined_color (struct frame *f,
1628                   const char *name,
1629                   XColor *color_def,
1630                   int alloc,
1631                   char makeIndex)
1632 /* --------------------------------------------------------------------------
1633          Return 1 if named color found, and set color_def rgb accordingly.
1634          If makeIndex and alloc are nonzero put the color in the color_table,
1635          and set color_def pixel to the resulting index.
1636          If makeIndex is zero, set color_def pixel to ARGB.
1637          Return 0 if not found
1638    -------------------------------------------------------------------------- */
1640   NSColor *col;
1641   NSTRACE (ns_defined_color);
1643   BLOCK_INPUT;
1644   if (ns_get_color (name, &col) != 0) /* Color not found  */
1645     {
1646       UNBLOCK_INPUT;
1647       return 0;
1648     }
1649   if (makeIndex && alloc)
1650     color_def->pixel = ns_index_color (col, f);
1651   ns_query_color (col, color_def, !makeIndex);
1652   UNBLOCK_INPUT;
1653   return 1;
1657 unsigned long
1658 ns_get_rgb_color (struct frame *f, float r, float g, float b, float a)
1659 /* --------------------------------------------------------------------------
1660     return an autoreleased RGB color
1661    -------------------------------------------------------------------------- */
1663 /*static int c = 1; fprintf (stderr, "color request %d\n", c++); */
1664   if (r < 0.0) r = 0.0;
1665   else if (r > 1.0) r = 1.0;
1666   if (g < 0.0) g = 0.0;
1667   else if (g > 1.0) g = 1.0;
1668   if (b < 0.0) b = 0.0;
1669   else if (b > 1.0) b = 1.0;
1670   if (a < 0.0) a = 0.0;
1671   else if (a > 1.0) a = 1.0;
1672   return (unsigned long) ns_index_color(
1673     [NSColor colorWithCalibratedRed: r green: g blue: b alpha: a], f);
1677 void
1678 x_set_frame_alpha (struct frame *f)
1679 /* --------------------------------------------------------------------------
1680      change the entire-frame transparency
1681    -------------------------------------------------------------------------- */
1683   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1684   EmacsView *view = FRAME_NS_VIEW (f);
1685   double alpha = 1.0;
1686   double alpha_min = 1.0;
1688   if (dpyinfo->x_highlight_frame == f)
1689     alpha = f->alpha[0];
1690   else
1691     alpha = f->alpha[1];
1693   if (FLOATP (Vframe_alpha_lower_limit))
1694     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1695   else if (INTEGERP (Vframe_alpha_lower_limit))
1696     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1698   if (alpha < 0.0)
1699     return;
1700   else if (1.0 < alpha)
1701     alpha = 1.0;
1702   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1703     alpha = alpha_min;
1705 #ifdef NS_IMPL_COCOA
1706   [[view window] setAlphaValue: alpha];
1707 #endif
1711 /* ==========================================================================
1713     Mouse handling
1715    ========================================================================== */
1718 void
1719 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1720 /* --------------------------------------------------------------------------
1721      Programmatically reposition mouse pointer in pixel coordinates
1722    -------------------------------------------------------------------------- */
1724   NSTRACE (x_set_mouse_pixel_position);
1725   ns_raise_frame (f);
1726 #if 0
1727   /* FIXME: this does not work, and what about GNUstep? */
1728 #ifdef NS_IMPL_COCOA
1729   [FRAME_NS_VIEW (f) lockFocus];
1730   PSsetmouse ((float)pix_x, (float)pix_y);
1731   [FRAME_NS_VIEW (f) unlockFocus];
1732 #endif
1733 #endif
1737 void
1738 x_set_mouse_position (struct frame *f, int h, int v)
1739 /* --------------------------------------------------------------------------
1740      Programmatically reposition mouse pointer in character coordinates
1741    -------------------------------------------------------------------------- */
1743   int pix_x, pix_y;
1745   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1746   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1748   if (pix_x < 0) pix_x = 0;
1749   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1751   if (pix_y < 0) pix_y = 0;
1752   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1754   x_set_mouse_pixel_position (f, pix_x, pix_y);
1758 static int
1759 note_mouse_movement (struct frame *frame, float x, float y)
1760 /*   ------------------------------------------------------------------------
1761      Called by EmacsView on mouseMovement events.  Passes on
1762      to emacs mainstream code if we moved off of a rect of interest
1763      known as last_mouse_glyph.
1764      ------------------------------------------------------------------------ */
1766 //  NSTRACE (note_mouse_movement);
1768   XSETFRAME (last_mouse_motion_frame, frame);
1770   /* Note, this doesn't get called for enter/leave, since we don't have a
1771      position.  Those are taken care of in the corresponding NSView methods. */
1773   /* has movement gone beyond last rect we were tracking? */
1774   if (x < last_mouse_glyph.origin.x ||
1775       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1776       y < last_mouse_glyph.origin.y ||
1777       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1778     {
1779       ns_update_begin(frame);
1780       frame->mouse_moved = 1;
1781       note_mouse_highlight (frame, x, y);
1782       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1783       ns_update_end(frame);
1784       return 1;
1785     }
1787   return 0;
1791 static void
1792 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1793                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1794                    Time *time)
1795 /* --------------------------------------------------------------------------
1796     External (hook): inform emacs about mouse position and hit parts.
1797     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1798     x & y should be position in the scrollbar (the whole bar, not the handle)
1799     and length of scrollbar respectively
1800    -------------------------------------------------------------------------- */
1802   id view;
1803   NSPoint position;
1804   int xchar, ychar;
1805   Lisp_Object frame, tail;
1806   struct frame *f;
1807   struct ns_display_info *dpyinfo;
1809   NSTRACE (ns_mouse_position);
1811   if (*fp == NULL)
1812     {
1813       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1814       return;
1815     }
1817   dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1819   BLOCK_INPUT;
1821   if (last_mouse_scroll_bar != nil && insist == 0)
1822     {
1823       /* TODO: we do not use this path at the moment because drag events will
1824            go directly to the EmacsScroller.  Leaving code in for now. */
1825       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1826                                               x: x y: y];
1827       if (time) *time = last_mouse_movement_time;
1828       last_mouse_scroll_bar = nil;
1829     }
1830   else
1831     {
1832       /* Clear the mouse-moved flag for every frame on this display.  */
1833       FOR_EACH_FRAME (tail, frame)
1834         if (FRAME_NS_P (XFRAME (frame))
1835             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1836           XFRAME (frame)->mouse_moved = 0;
1838       last_mouse_scroll_bar = nil;
1839       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1840         f = last_mouse_frame;
1841       else
1842         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1843                                     : SELECTED_FRAME ();
1845       if (f && f->output_data.ns)  /* TODO: 2nd check no longer needed? */
1846         {
1847           view = FRAME_NS_VIEW (*fp);
1849           position = [[view window] mouseLocationOutsideOfEventStream];
1850           position = [view convertPoint: position fromView: nil];
1851           remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1852 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1854           if (bar_window) *bar_window = Qnil;
1855           if (part) *part = 0; /*scroll_bar_handle; */
1857           if (x) XSETINT (*x, lrint (position.x));
1858           if (y) XSETINT (*y, lrint (position.y));
1859           if (time) *time = last_mouse_movement_time;
1860           *fp = f;
1861         }
1862     }
1864   UNBLOCK_INPUT;
1868 static void
1869 ns_frame_up_to_date (struct frame *f)
1870 /* --------------------------------------------------------------------------
1871     External (hook): Fix up mouse highlighting right after a full update.
1872     Some highlighting was deferred if GC was happening during
1873     note_mouse_highlight (), while other highlighting was deferred for update.
1874    -------------------------------------------------------------------------- */
1876   NSTRACE (ns_frame_up_to_date);
1878   if (FRAME_NS_P (f))
1879     {
1880       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1881       if ((hlinfo->mouse_face_deferred_gc || f ==hlinfo->mouse_face_mouse_frame)
1882       /*&& hlinfo->mouse_face_mouse_frame*/)
1883         {
1884           BLOCK_INPUT;
1885           ns_update_begin(f);
1886           if (hlinfo->mouse_face_mouse_frame)
1887             note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1888                                   hlinfo->mouse_face_mouse_x,
1889                                   hlinfo->mouse_face_mouse_y);
1890           hlinfo->mouse_face_deferred_gc = 0;
1891           ns_update_end(f);
1892           UNBLOCK_INPUT;
1893         }
1894     }
1898 void
1899 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1900 /* --------------------------------------------------------------------------
1901     External (RIF): set frame mouse pointer type.
1902    -------------------------------------------------------------------------- */
1904   NSTRACE (ns_define_frame_cursor);
1905   if (FRAME_POINTER_TYPE (f) != cursor)
1906     {
1907       EmacsView *view = FRAME_NS_VIEW (f);
1908       FRAME_POINTER_TYPE (f) = cursor;
1909       [[view window] invalidateCursorRectsForView: view];
1910       /* Redisplay assumes this function also draws the changed frame
1911          cursor, but this function doesn't, so do it explicitly.  */
1912       x_update_cursor (f, 1);
1913     }
1918 /* ==========================================================================
1920     Keyboard handling
1922    ========================================================================== */
1925 static unsigned
1926 ns_convert_key (unsigned code)
1927 /* --------------------------------------------------------------------------
1928     Internal call used by NSView-keyDown.
1929    -------------------------------------------------------------------------- */
1931   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1932                                 / sizeof (convert_ns_to_X_keysym[0]));
1933   unsigned keysym;
1934   /* An array would be faster, but less easy to read. */
1935   for (keysym = 0; keysym < last_keysym; keysym += 2)
1936     if (code == convert_ns_to_X_keysym[keysym])
1937       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1938   return 0;
1939 /* if decide to use keyCode and Carbon table, use this line:
1940      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1944 char *
1945 x_get_keysym_name (int keysym)
1946 /* --------------------------------------------------------------------------
1947     Called by keyboard.c.  Not sure if the return val is important, except
1948     that it be unique.
1949    -------------------------------------------------------------------------- */
1951   static char value[16];
1952   NSTRACE (x_get_keysym_name);
1953   sprintf (value, "%d", keysym);
1954   return value;
1959 /* ==========================================================================
1961     Block drawing operations
1963    ========================================================================== */
1966 static void
1967 ns_redraw_scroll_bars (struct frame *f)
1969   int i;
1970   id view;
1971   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1972   NSTRACE (ns_judge_scroll_bars);
1973   for (i =[subviews count]-1; i >= 0; i--)
1974     {
1975       view = [subviews objectAtIndex: i];
1976       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1977       [view display];
1978     }
1982 void
1983 ns_clear_frame (struct frame *f)
1984 /* --------------------------------------------------------------------------
1985       External (hook): Erase the entire frame
1986    -------------------------------------------------------------------------- */
1988   NSView *view = FRAME_NS_VIEW (f);
1989   NSRect r;
1991   NSTRACE (ns_clear_frame);
1992   if (ns_in_resize)
1993     return;
1995  /* comes on initial frame because we have
1996     after-make-frame-functions = select-frame */
1997  if (!FRAME_DEFAULT_FACE (f))
1998    return;
2000   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2002   output_cursor.hpos = output_cursor.vpos = 0;
2003   output_cursor.x = -1;
2005   r = [view bounds];
2007   BLOCK_INPUT;
2008   ns_focus (f, &r, 1);
2009   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2010   NSRectFill (r);
2011   ns_unfocus (f);
2013 #ifdef NS_IMPL_COCOA
2014   [[view window] display];  /* redraw resize handle */
2015 #endif
2017   /* as of 2006/11 or so this is now needed */
2018   ns_redraw_scroll_bars (f);
2019   UNBLOCK_INPUT;
2023 void
2024 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2025 /* --------------------------------------------------------------------------
2026     External (RIF):  Clear section of frame
2027    -------------------------------------------------------------------------- */
2029   NSRect r = NSMakeRect (x, y, width, height);
2030   NSView *view = FRAME_NS_VIEW (f);
2031   struct face *face = FRAME_DEFAULT_FACE (f);
2033   if (!view || !face)
2034     return;
2036   NSTRACE (ns_clear_frame_area);
2038   r = NSIntersectionRect (r, [view frame]);
2039   ns_focus (f, &r, 1);
2040   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2042 #ifdef NS_IMPL_COCOA
2043   {
2044     /* clip out the resize handle */
2045     NSWindow *window = [FRAME_NS_VIEW (f) window];
2046     NSRect ir
2047       = [view convertRect: ns_resize_handle_rect (window) fromView: nil];
2049     ir = NSIntersectionRect (r, ir);
2050     if (NSIsEmptyRect (ir))
2051       {
2052 #endif
2054   NSRectFill (r);
2056 #ifdef NS_IMPL_COCOA
2057       }
2058     else
2059       {
2060         NSRect r1 = r, r2 = r; /* upper and lower non-intersecting */
2061         r1.size.height -= ir.size.height;
2062         r2.origin.y += r1.size.height;
2063         r2.size.width -= ir.size.width;
2064         r2.size.height = ir.size.height;
2065         NSRectFill (r1);
2066         NSRectFill (r2);
2067       }
2068   }
2069 #endif
2071   ns_unfocus (f);
2072   return;
2076 static void
2077 ns_scroll_run (struct window *w, struct run *run)
2078 /* --------------------------------------------------------------------------
2079     External (RIF):  Insert or delete n lines at line vpos
2080    -------------------------------------------------------------------------- */
2082   struct frame *f = XFRAME (w->frame);
2083   int x, y, width, height, from_y, to_y, bottom_y;
2085   NSTRACE (ns_scroll_run);
2087   /* begin copy from other terms */
2088   /* Get frame-relative bounding box of the text display area of W,
2089      without mode lines.  Include in this box the left and right
2090      fringe of W.  */
2091   window_box (w, -1, &x, &y, &width, &height);
2093   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2094   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2095   bottom_y = y + height;
2097   if (to_y < from_y)
2098     {
2099       /* Scrolling up.  Make sure we don't copy part of the mode
2100          line at the bottom.  */
2101       if (from_y + run->height > bottom_y)
2102         height = bottom_y - from_y;
2103       else
2104         height = run->height;
2105     }
2106   else
2107     {
2108       /* Scrolling down.  Make sure we don't copy over the mode line.
2109          at the bottom.  */
2110       if (to_y + run->height > bottom_y)
2111         height = bottom_y - to_y;
2112       else
2113         height = run->height;
2114     }
2115   /* end copy from other terms */
2117   if (height == 0)
2118       return;
2120   BLOCK_INPUT;
2122   updated_window = w;
2123   x_clear_cursor (w);
2125   {
2126     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2127     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2128     NSPoint dstOrigin = NSMakePoint (x, to_y);
2130     ns_focus (f, &dstRect, 1);
2131     NSCopyBits (0, srcRect , dstOrigin);
2132     ns_unfocus (f);
2133   }
2135   UNBLOCK_INPUT;
2139 static void
2140 ns_after_update_window_line (struct glyph_row *desired_row)
2141 /* --------------------------------------------------------------------------
2142     External (RIF): preparatory to fringe update after text was updated
2143    -------------------------------------------------------------------------- */
2145   struct window *w = updated_window;
2146   struct frame *f;
2147   int width, height;
2149   NSTRACE (ns_after_update_window_line);
2151   /* begin copy from other terms */
2152   xassert (w);
2154   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2155     desired_row->redraw_fringe_bitmaps_p = 1;
2157   /* When a window has disappeared, make sure that no rest of
2158      full-width rows stays visible in the internal border.
2159      Under NS this is drawn inside the fringes. */
2160   if (windows_or_buffers_changed
2161       && (f = XFRAME (w->frame),
2162           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2163           width != 0)
2164       && (height = desired_row->visible_height,
2165           height > 0))
2166     {
2167       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2169       /* Internal border is drawn below the tool bar.  */
2170       if (WINDOWP (f->tool_bar_window)
2171           && w == XWINDOW (f->tool_bar_window))
2172         y -= width;
2173       /* end copy from other terms */
2175       BLOCK_INPUT;
2176       if (!desired_row->full_width_p)
2177         {
2178           int x1 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2179             + WINDOW_LEFT_FRINGE_WIDTH (w);
2180           int x2 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2181             + FRAME_PIXEL_WIDTH (f) - NS_SCROLL_BAR_WIDTH (f)
2182             - WINDOW_RIGHT_FRINGE_WIDTH (w)
2183             - FRAME_INTERNAL_BORDER_WIDTH (f);
2184           ns_clear_frame_area (f, x1, y, width, height);
2185           ns_clear_frame_area (f, x2, y, width, height);
2186         }
2187       UNBLOCK_INPUT;
2188     }
2192 static void
2193 ns_shift_glyphs_for_insert (struct frame *f,
2194                            int x, int y, int width, int height,
2195                            int shift_by)
2196 /* --------------------------------------------------------------------------
2197     External (RIF): copy an area horizontally, don't worry about clearing src
2198    -------------------------------------------------------------------------- */
2200   NSRect srcRect = NSMakeRect (x, y, width, height);
2201   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2202   NSPoint dstOrigin = dstRect.origin;
2204   NSTRACE (ns_shift_glyphs_for_insert);
2206   ns_focus (f, &dstRect, 1);
2207   NSCopyBits (0, srcRect, dstOrigin);
2208   ns_unfocus (f);
2213 /* ==========================================================================
2215     Character encoding and metrics
2217    ========================================================================== */
2220 static inline void
2221 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2222 /* --------------------------------------------------------------------------
2223      External (RIF); compute left/right overhang of whole string and set in s
2224    -------------------------------------------------------------------------- */
2226   struct face *face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2227   struct font *font = s->font; /*face->font; */
2229   if (s->char2b)
2230     {
2231       struct font_metrics metrics;
2232       unsigned int codes[2];
2233       codes[0] = *(s->char2b);
2234       codes[1] = *(s->char2b + s->nchars - 1);
2236       font->driver->text_extents (font, codes, 2, &metrics);
2237       s->left_overhang = -metrics.lbearing;
2238       s->right_overhang
2239         = metrics.rbearing > metrics.width
2240         ? metrics.rbearing - metrics.width : 0;
2241     }
2242   else
2243     {
2244       s->left_overhang = 0;
2245       s->right_overhang = ((struct nsfont_info *)font)->ital ?
2246         FONT_HEIGHT (font) * 0.2 : 0;
2247     }
2252 /* ==========================================================================
2254     Fringe and cursor drawing
2256    ========================================================================== */
2259 extern int max_used_fringe_bitmap;
2260 static void
2261 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2262                       struct draw_fringe_bitmap_params *p)
2263 /* --------------------------------------------------------------------------
2264     External (RIF); fringe-related
2265    -------------------------------------------------------------------------- */
2267   struct frame *f = XFRAME (WINDOW_FRAME (w));
2268   struct face *face = p->face;
2269   int rowY;
2270   static EmacsImage **bimgs = NULL;
2271   static int nBimgs = 0;
2272   /* NS-specific: move internal border inside fringe */
2273   int x = p->bx < 0 ? p->x : p->bx;
2274   int wd = p->bx < 0 ? p->wd : p->nx;
2275   BOOL fringeOnVeryLeft
2276     = x - WINDOW_LEFT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w)
2277       - FRAME_INTERNAL_BORDER_WIDTH (f) < 10;
2278   BOOL fringeOnVeryRight
2279     = FRAME_PIXEL_WIDTH (f) - x - wd - FRAME_INTERNAL_BORDER_WIDTH (f)
2280       - WINDOW_RIGHT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w) < 10;
2281   int xAdjust = FRAME_INTERNAL_BORDER_WIDTH (f) *
2282     (fringeOnVeryLeft ? -1 : (fringeOnVeryRight ? 1 : 0));
2284   /* grow bimgs if needed */
2285   if (nBimgs < max_used_fringe_bitmap)
2286     {
2287       EmacsImage **newBimgs
2288         = xmalloc (max_used_fringe_bitmap * sizeof (EmacsImage *));
2289       memset (newBimgs, 0, max_used_fringe_bitmap * sizeof (EmacsImage *));
2291       if (nBimgs)
2292         {
2293           memcpy (newBimgs, bimgs, nBimgs * sizeof (EmacsImage *));
2294           xfree (bimgs);
2295         }
2297       bimgs = newBimgs;
2298       nBimgs = max_used_fringe_bitmap;
2299     }
2301   /* Must clip because of partially visible lines.  */
2302   rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2303   ns_clip_to_row (w, row, -1, YES);
2305   if (p->bx >= 0 && !p->overlay_p)
2306     {
2307       int yAdjust = rowY - FRAME_INTERNAL_BORDER_WIDTH (f) < 5 ?
2308         -FRAME_INTERNAL_BORDER_WIDTH (f) : 0;
2309       int yIncr = FRAME_PIXEL_HEIGHT (f) - (p->by+yAdjust + p->ny) < 5 ?
2310         FRAME_INTERNAL_BORDER_WIDTH (f) : 0
2311         + (yAdjust ? FRAME_INTERNAL_BORDER_WIDTH (f) : 0);
2312       NSRect r = NSMakeRect (p->bx+xAdjust, p->by+yAdjust, p->nx, p->ny+yIncr);
2313       NSRectClip (r);
2314       [ns_lookup_indexed_color(face->background, f) set];
2315       NSRectFill (r);
2316     }
2318   if (p->which)
2319     {
2320       NSRect r = NSMakeRect (p->x+xAdjust, p->y, p->wd, p->h);
2321       NSPoint pt = r.origin;
2322       EmacsImage *img = bimgs[p->which - 1];
2324       if (!img)
2325         {
2326           unsigned short *bits = p->bits + p->dh;
2327           int len = p->h;
2328           int i;
2329           unsigned char *cbits = xmalloc (len);
2331           for (i =0; i<len; i++)
2332             cbits[i] = ~(bits[i] & 0xff);
2333           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2334                                            flip: NO];
2335           bimgs[p->which - 1] = img;
2336           xfree (cbits);
2337         }
2339       NSRectClip (r);
2340       /* Since we composite the bitmap instead of just blitting it, we need
2341          to erase the whole background. */
2342       [ns_lookup_indexed_color(face->background, f) set];
2343       NSRectFill (r);
2344       pt.y += p->h;
2345       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2346       [img compositeToPoint: pt operation: NSCompositeSourceOver];
2347     }
2348   ns_unfocus (f);
2352 void
2353 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2354                        int x, int y, int cursor_type, int cursor_width,
2355                        int on_p, int active_p)
2356 /* --------------------------------------------------------------------------
2357      External call (RIF): draw cursor.
2358      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2359    -------------------------------------------------------------------------- */
2361   NSRect r, s;
2362   int fx, fy, h, cursor_height;
2363   struct frame *f = WINDOW_XFRAME (w);
2364   struct glyph *phys_cursor_glyph;
2365   int overspill;
2366   struct glyph *cursor_glyph;
2367   struct face *face;
2368   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2370   /* If cursor is out of bounds, don't draw garbage.  This can happen
2371      in mini-buffer windows when switching between echo area glyphs
2372      and mini-buffer.  */
2374   NSTRACE (dumpcursor);
2376   if (!on_p)
2377     return;
2379   w->phys_cursor_type = cursor_type;
2380   w->phys_cursor_on_p = on_p;
2382   if (cursor_type == NO_CURSOR)
2383     {
2384       w->phys_cursor_width = 0;
2385       return;
2386     }
2388   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2389     {
2390       if (glyph_row->exact_window_width_line_p
2391           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2392         {
2393           glyph_row->cursor_in_fringe_p = 1;
2394           draw_fringe_bitmap (w, glyph_row, 0);
2395         }
2396       return;
2397     }
2399   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2400      (other terminals do it the other way round).  We must set
2401      w->phys_cursor_width to the cursor width.  For bar cursors, that
2402      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2403   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2405   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2406      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2407   if (cursor_type == BAR_CURSOR)
2408     {
2409       if (cursor_width < 1)
2410         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2411       w->phys_cursor_width = cursor_width;
2412     }
2413   /* If we have an HBAR, "cursor_width" MAY specify height. */
2414   else if (cursor_type == HBAR_CURSOR)
2415     {
2416       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2417       fy += h - cursor_height;
2418       h = cursor_height;
2419     }
2421   r.origin.x = fx, r.origin.y = fy;
2422   r.size.height = h;
2423   r.size.width = w->phys_cursor_width;
2425   /* FIXME: if we overwrite the internal border area, it does not get erased;
2426      fix by truncating cursor, but better would be to erase properly */
2427   overspill = r.origin.x + r.size.width -
2428     WINDOW_TEXT_TO_FRAME_PIXEL_X (w, WINDOW_BOX_RIGHT_EDGE_X (w)
2429       - WINDOW_TOTAL_FRINGE_WIDTH (w) - FRAME_INTERNAL_BORDER_WIDTH (f));
2430   if (overspill > 0)
2431     r.size.width -= overspill;
2433   /* TODO: only needed in rare cases with last-resort font in HELLO..
2434      should we do this more efficiently? */
2435   ns_clip_to_row (w, glyph_row, -1, NO); /* do ns_focus(f, &r, 1); if remove */
2438   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2439   if (face && NS_FACE_BACKGROUND (face)
2440       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2441     {
2442       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2443       hollow_color = FRAME_CURSOR_COLOR (f);
2444     }
2445   else
2446     [FRAME_CURSOR_COLOR (f) set];
2448 #ifdef NS_IMPL_COCOA
2449   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2450            atomic.  Cleaner ways of doing this should be investigated.
2451            One way would be to set a global variable DRAWING_CURSOR
2452            when making the call to draw_phys..(), don't focus in that
2453            case, then move the ns_unfocus() here after that call. */
2454   NSDisableScreenUpdates ();
2455 #endif
2457   switch (cursor_type)
2458     {
2459     case NO_CURSOR:
2460       break;
2461     case FILLED_BOX_CURSOR:
2462       NSRectFill (r);
2463       break;
2464     case HOLLOW_BOX_CURSOR:
2465       NSRectFill (r);
2466       [hollow_color set];
2467       NSRectFill (NSInsetRect (r, 1, 1));
2468       [FRAME_CURSOR_COLOR (f) set];
2469       break;
2470     case HBAR_CURSOR:
2471       NSRectFill (r);
2472       break;
2473     case BAR_CURSOR:
2474       s = r;
2475       /* If the character under cursor is R2L, draw the bar cursor
2476          on the right of its glyph, rather than on the left.  */
2477       cursor_glyph = get_phys_cursor_glyph (w);
2478       if ((cursor_glyph->resolved_level & 1) != 0)
2479         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2481       NSRectFill (s);
2482       break;
2483     }
2484   ns_unfocus (f);
2486   /* draw the character under the cursor */
2487   if (cursor_type != NO_CURSOR)
2488     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2490 #ifdef NS_IMPL_COCOA
2491   NSEnableScreenUpdates ();
2492 #endif
2497 static void
2498 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2499 /* --------------------------------------------------------------------------
2500      External (RIF): Draw a vertical line.
2501    -------------------------------------------------------------------------- */
2503   struct frame *f = XFRAME (WINDOW_FRAME (w));
2504   struct face *face;
2505   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2507   NSTRACE (ns_draw_vertical_window_border);
2509   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2510   if (face)
2511       [ns_lookup_indexed_color(face->foreground, f) set];
2513   ns_focus (f, &r, 1);
2514   NSRectFill(r);
2515   ns_unfocus (f);
2519 void
2520 show_hourglass (struct atimer *timer)
2522   if (hourglass_shown_p)
2523     return;
2525   BLOCK_INPUT;
2527   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2529   hourglass_shown_p = 1;
2530   UNBLOCK_INPUT;
2534 void
2535 hide_hourglass (void)
2537   if (!hourglass_shown_p)
2538     return;
2540   BLOCK_INPUT;
2542   /* TODO: remove NSProgressIndicator from all frames */
2544   hourglass_shown_p = 0;
2545   UNBLOCK_INPUT;
2550 /* ==========================================================================
2552     Glyph drawing operations
2554    ========================================================================== */
2557 static inline NSRect
2558 ns_fix_rect_ibw (NSRect r, int fibw, int frame_pixel_width)
2559 /* --------------------------------------------------------------------------
2560     Under NS we draw internal borders inside fringes, and want full-width
2561     rendering to go all the way to edge.  This function makes that correction.
2562    -------------------------------------------------------------------------- */
2564   if (r.origin.y <= fibw+1)
2565     {
2566       r.size.height += r.origin.y;
2567       r.origin.y = 0;
2568     }
2569   if (r.origin.x <= fibw+1)
2570     {
2571       r.size.width += r.origin.x;
2572       r.origin.x = 0;
2573     }
2574   if (frame_pixel_width - (r.origin.x+r.size.width) <= fibw+1)
2575     r.size.width += fibw;
2577   return r;
2581 static int
2582 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2583 /* --------------------------------------------------------------------------
2584     Wrapper utility to account for internal border width on full-width lines,
2585     and allow top full-width rows to hit the frame top.  nr should be pointer
2586     to two successive NSRects.  Number of rects actually used is returned.
2587    -------------------------------------------------------------------------- */
2589   int n = get_glyph_string_clip_rects (s, nr, 2);
2590   if (s->row->full_width_p)
2591     {
2592       *nr = ns_fix_rect_ibw (*nr, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2593                             FRAME_PIXEL_WIDTH (s->f));
2594       if (n == 2)
2595         *nr = ns_fix_rect_ibw (*(nr+1), FRAME_INTERNAL_BORDER_WIDTH (s->f),
2596                               FRAME_PIXEL_WIDTH (s->f));
2597     }
2598   return n;
2601 void
2602 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2603                          NSColor *defaultCol, CGFloat width, CGFloat x)
2604 /* --------------------------------------------------------------------------
2605    Draw underline, overline, and strike-through on glyph string s.
2606    -------------------------------------------------------------------------- */
2608   if (s->for_overlaps)
2609     return;
2611   /* Do underline. */
2612   if (face->underline_p)
2613     {
2614       NSRect r;
2615       unsigned long thickness, position;
2617       /* If the prev was underlined, match its appearance. */
2618       if (s->prev && s->prev->face->underline_p
2619           && s->prev->underline_thickness > 0)
2620         {
2621           thickness = s->prev->underline_thickness;
2622           position = s->prev->underline_position;
2623         }
2624       else
2625         {
2626           struct font *font;
2627           unsigned long descent;
2629           font=s->font;
2630           descent = s->y + s->height - s->ybase;
2632           /* Use underline thickness of font, defaulting to 1. */
2633           thickness = (font && font->underline_thickness > 0)
2634             ? font->underline_thickness : 1;
2636           /* Determine the offset of underlining from the baseline. */
2637           if (x_underline_at_descent_line)
2638             position = descent - thickness;
2639           else if (x_use_underline_position_properties
2640                    && font && font->underline_position >= 0)
2641             position = font->underline_position;
2642           else if (font)
2643             position = lround (font->descent / 2);
2644           else
2645             position = underline_minimum_offset;
2647           position = max (position, underline_minimum_offset);
2649           /* Ensure underlining is not cropped. */
2650           if (descent <= position)
2651             {
2652               position = descent - 1;
2653               thickness = 1;
2654             }
2655           else if (descent < position + thickness)
2656             thickness = 1;
2657         }
2659       s->underline_thickness = thickness;
2660       s->underline_position = position;
2662       r = NSMakeRect (x, s->ybase + position, width, thickness);
2664       if (face->underline_defaulted_p)
2665         [defaultCol set];
2666       else
2667         [ns_lookup_indexed_color (face->underline_color, s->f) set];
2668       NSRectFill (r);
2669     }
2671   /* Do overline. We follow other terms in using a thickness of 1
2672      and ignoring overline_margin. */
2673   if (face->overline_p)
2674     {
2675       NSRect r;
2676       r = NSMakeRect (x, s->y, width, 1);
2678       if (face->overline_color_defaulted_p)
2679         [defaultCol set];
2680       else
2681         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2682       NSRectFill (r);
2683     }
2685   /* Do strike-through.  We follow other terms for thickness and
2686      vertical position.*/
2687   if (face->strike_through_p)
2688     {
2689       NSRect r;
2690       unsigned long dy;
2692       dy = lrint ((s->height - 1) / 2);
2693       r = NSMakeRect (x, s->y + dy, width, 1);
2695       if (face->strike_through_color_defaulted_p)
2696         [defaultCol set];
2697       else
2698         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2699       NSRectFill (r);
2700     }
2703 static void
2704 ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char right_p)
2705 /* --------------------------------------------------------------------------
2706     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2707     Note we can't just use an NSDrawRect command, because of the possibility
2708     of some sides not being drawn, and because the rect will be filled.
2709    -------------------------------------------------------------------------- */
2711   NSRect s = r;
2712   [col set];
2714   /* top, bottom */
2715   s.size.height = thickness;
2716   NSRectFill (s);
2717   s.origin.y += r.size.height - thickness;
2718   NSRectFill (s);
2720   s.size.height = r.size.height;
2721   s.origin.y = r.origin.y;
2723   /* left, right (optional) */
2724   s.size.width = thickness;
2725   if (left_p)
2726     NSRectFill (s);
2727   if (right_p)
2728     {
2729       s.origin.x += r.size.width - thickness;
2730       NSRectFill (s);
2731     }
2735 static void
2736 ns_draw_relief (NSRect r, int thickness, char raised_p,
2737                char top_p, char bottom_p, char left_p, char right_p,
2738                struct glyph_string *s)
2739 /* --------------------------------------------------------------------------
2740     Draw a relief rect inside r, optionally leaving some sides open.
2741     Note we can't just use an NSDrawBezel command, because of the possibility
2742     of some sides not being drawn, and because the rect will be filled.
2743    -------------------------------------------------------------------------- */
2745   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2746   NSColor *newBaseCol = nil;
2747   NSRect sr = r;
2749   NSTRACE (ns_draw_relief);
2751   /* set up colors */
2753   if (s->face->use_box_color_for_shadows_p)
2754     {
2755       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2756     }
2757 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2758            && s->img->pixmap
2759            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2760        {
2761          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2762        } */
2763   else
2764     {
2765       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2766     }
2768   if (newBaseCol == nil)
2769     newBaseCol = [NSColor grayColor];
2771   if (newBaseCol != baseCol)  /* TODO: better check */
2772     {
2773       [baseCol release];
2774       baseCol = [newBaseCol retain];
2775       [lightCol release];
2776       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2777       [darkCol release];
2778       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2779     }
2781   [(raised_p ? lightCol : darkCol) set];
2783   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2785   /* top */
2786   sr.size.height = thickness;
2787   if (top_p) NSRectFill (sr);
2789   /* left */
2790   sr.size.height = r.size.height;
2791   sr.size.width = thickness;
2792   if (left_p) NSRectFill (sr);
2794   [(raised_p ? darkCol : lightCol) set];
2796   /* bottom */
2797   sr.size.width = r.size.width;
2798   sr.size.height = thickness;
2799   sr.origin.y += r.size.height - thickness;
2800   if (bottom_p) NSRectFill (sr);
2802   /* right */
2803   sr.size.height = r.size.height;
2804   sr.origin.y = r.origin.y;
2805   sr.size.width = thickness;
2806   sr.origin.x += r.size.width - thickness;
2807   if (right_p) NSRectFill (sr);
2811 static void
2812 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2813 /* --------------------------------------------------------------------------
2814       Function modeled after x_draw_glyph_string_box ().
2815       Sets up parameters for drawing.
2816    -------------------------------------------------------------------------- */
2818   int right_x, last_x;
2819   char left_p, right_p;
2820   struct glyph *last_glyph;
2821   NSRect r;
2822   int thickness;
2823   struct face *face;
2825   if (s->hl == DRAW_MOUSE_FACE)
2826     {
2827       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2828       if (!face)
2829         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2830     }
2831   else
2832     face = s->face;
2834   thickness = face->box_line_width;
2836   NSTRACE (ns_dumpglyphs_box_or_relief);
2838   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2839             ? WINDOW_RIGHT_EDGE_X (s->w)
2840             : window_box_right (s->w, s->area));
2841   last_glyph = (s->cmp || s->img
2842                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2844   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2845               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2847   left_p = (s->first_glyph->left_box_line_p
2848             || (s->hl == DRAW_MOUSE_FACE
2849                 && (s->prev == NULL || s->prev->hl != s->hl)));
2850   right_p = (last_glyph->right_box_line_p
2851              || (s->hl == DRAW_MOUSE_FACE
2852                  && (s->next == NULL || s->next->hl != s->hl)));
2854   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2856   /* expand full-width row over internal borders */
2857   if (s->row->full_width_p)
2858     r = ns_fix_rect_ibw (r, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2859                         FRAME_PIXEL_WIDTH (s->f));
2861   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2862   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2863     {
2864       ns_draw_box (r, abs (thickness),
2865                    ns_lookup_indexed_color (face->box_color, s->f),
2866                   left_p, right_p);
2867     }
2868   else
2869     {
2870       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2871                      1, 1, left_p, right_p, s);
2872     }
2876 static void
2877 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2878 /* --------------------------------------------------------------------------
2879       Modeled after x_draw_glyph_string_background, which draws BG in
2880       certain cases.  Others are left to the text rendering routine.
2881    -------------------------------------------------------------------------- */
2883   NSTRACE (ns_maybe_dumpglyphs_background);
2885   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2886     {
2887       int box_line_width = max (s->face->box_line_width, 0);
2888       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2889           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2890         {
2891           struct face *face;
2892           if (s->hl == DRAW_MOUSE_FACE)
2893             {
2894               face = FACE_FROM_ID (s->f,
2895                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2896               if (!face)
2897                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2898             }
2899           else
2900             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2901           if (!face->stipple)
2902             [(NS_FACE_BACKGROUND (face) != 0
2903               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2904               : FRAME_BACKGROUND_COLOR (s->f)) set];
2905           else
2906             {
2907               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2908               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2909             }
2911           if (s->hl != DRAW_CURSOR)
2912             {
2913               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2914                                     s->background_width,
2915                                     s->height-2*box_line_width);
2917               /* expand full-width row over internal borders */
2918               if (s->row->full_width_p)
2919                 {
2920                   int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2921                   if (r.origin.y <= fibw+1 + box_line_width)
2922                     {
2923                       r.size.height += r.origin.y;
2924                       r.origin.y = 0;
2925                     }
2926                   if (r.origin.x <= fibw+1)
2927                     {
2928                       r.size.width += 2*r.origin.x;
2929                       r.origin.x = 0;
2930                     }
2931                   if (FRAME_PIXEL_WIDTH (s->f) - (r.origin.x + r.size.width)
2932                       <= fibw+1)
2933                     r.size.width += fibw;
2934                 }
2936               NSRectFill (r);
2937             }
2939           s->background_filled_p = 1;
2940         }
2941     }
2945 static void
2946 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2947 /* --------------------------------------------------------------------------
2948       Renders an image and associated borders.
2949    -------------------------------------------------------------------------- */
2951   EmacsImage *img = s->img->pixmap;
2952   int box_line_vwidth = max (s->face->box_line_width, 0);
2953   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2954   int bg_x, bg_y, bg_height;
2955   int th;
2956   char raised_p;
2957   NSRect br;
2958   struct face *face;
2959   NSColor *tdCol;
2961   NSTRACE (ns_dumpglyphs_image);
2963   if (s->face->box != FACE_NO_BOX
2964       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2965     x += abs (s->face->box_line_width);
2967   bg_x = x;
2968   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2969   bg_height = s->height;
2970   /* other terms have this, but was causing problems w/tabbar mode */
2971   /* - 2 * box_line_vwidth; */
2973   if (s->slice.x == 0) x += s->img->hmargin;
2974   if (s->slice.y == 0) y += s->img->vmargin;
2976   /* Draw BG: if we need larger area than image itself cleared, do that,
2977      otherwise, since we composite the image under NS (instead of mucking
2978      with its background color), we must clear just the image area. */
2979   if (s->hl == DRAW_MOUSE_FACE)
2980     {
2981       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2982       if (!face)
2983        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2984     }
2985   else
2986     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2988   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2990   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2991       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2992     {
2993       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
2994       s->background_filled_p = 1;
2995     }
2996   else
2997     {
2998       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
2999     }
3001   /* expand full-width row over internal borders */
3002   if (s->row->full_width_p)
3003     {
3004       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
3005       if (br.origin.y <= fibw+1 + box_line_vwidth)
3006         {
3007           br.size.height += br.origin.y;
3008           br.origin.y = 0;
3009         }
3010       if (br.origin.x <= fibw+1 + box_line_vwidth)
3011         {
3012           br.size.width += br.origin.x;
3013           br.origin.x = 0;
3014         }
3015       if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) <= fibw+1)
3016         br.size.width += fibw;
3017     }
3019   NSRectFill (br);
3021   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3022   if (img != nil)
3023     [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3024                 operation: NSCompositeSourceOver];
3026   if (s->hl == DRAW_CURSOR)
3027     {
3028     [FRAME_CURSOR_COLOR (s->f) set];
3029     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3030       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3031     else
3032       /* Currently on NS img->mask is always 0. Since
3033          get_window_cursor_type specifies a hollow box cursor when on
3034          a non-masked image we never reach this clause. But we put it
3035          in in anticipation of better support for image masks on
3036          NS. */
3037       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3038     }
3039   else
3040     {
3041       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3042     }
3044   /* Draw underline, overline, strike-through. */
3045   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3047   /* Draw relief, if requested */
3048   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3049     {
3050       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3051         {
3052           th = tool_bar_button_relief >= 0 ?
3053             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3054           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3055         }
3056       else
3057         {
3058           th = abs (s->img->relief);
3059           raised_p = (s->img->relief > 0);
3060         }
3062       r.origin.x = x - th;
3063       r.origin.y = y - th;
3064       r.size.width = s->slice.width + 2*th-1;
3065       r.size.height = s->slice.height + 2*th-1;
3066       ns_draw_relief (r, th, raised_p,
3067                       s->slice.y == 0,
3068                       s->slice.y + s->slice.height == s->img->height,
3069                       s->slice.x == 0,
3070                       s->slice.x + s->slice.width == s->img->width, s);
3071     }
3073   /* If there is no mask, the background won't be seen,
3074      so draw a rectangle on the image for the cursor.
3075      Do this for all images, getting transparency right is not reliable.  */
3076   if (s->hl == DRAW_CURSOR)
3077     {
3078       int thickness = abs (s->img->relief);
3079       if (thickness == 0) thickness = 1;
3080       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3081     }
3085 static void
3086 ns_dumpglyphs_stretch (struct glyph_string *s)
3088   NSRect r[2];
3089   int n, i;
3090   struct face *face;
3091   NSColor *fgCol, *bgCol;
3093   if (!s->background_filled_p)
3094     {
3095       n = ns_get_glyph_string_clip_rect (s, r);
3096       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3098       ns_focus (s->f, r, n);
3100       if (s->hl == DRAW_MOUSE_FACE)
3101        {
3102          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3103          if (!face)
3104            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3105        }
3106       else
3107        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3109       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3110       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3112       for (i=0; i<n; i++)
3113         {
3114           if (!s->row->full_width_p)
3115             {
3116               int overrun, leftoverrun;
3118               /* truncate to avoid overwriting fringe and/or scrollbar */
3119               overrun = max (0, (s->x + s->background_width)
3120                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3121                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3122               r[i].size.width -= overrun;
3124               /* truncate to avoid overwriting to left of the window box */
3125               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3126                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3128               if (leftoverrun > 0)
3129                 {
3130                   r[i].origin.x += leftoverrun;
3131                   r[i].size.width -= leftoverrun;
3132                 }
3134               /* XXX: Try to work between problem where a stretch glyph on
3135                  a partially-visible bottom row will clear part of the
3136                  modeline, and another where list-buffers headers and similar
3137                  rows erroneously have visible_height set to 0.  Not sure
3138                  where this is coming from as other terms seem not to show. */
3139               r[i].size.height = min (s->height, s->row->visible_height);
3140             }
3142           /* expand full-width rows over internal borders */
3143           else
3144             {
3145               r[i] = ns_fix_rect_ibw (r[i], FRAME_INTERNAL_BORDER_WIDTH (s->f),
3146                                       FRAME_PIXEL_WIDTH (s->f));
3147             }
3149           [bgCol set];
3151           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3152              overwriting cursor (usually when cursor on a tab) */
3153           if (s->hl == DRAW_CURSOR)
3154             {
3155               CGFloat x, width;
3157               x = r[i].origin.x;
3158               width = s->w->phys_cursor_width;
3159               r[i].size.width -= width;
3160               r[i].origin.x += width;
3162               NSRectFill (r[i]);
3164               /* Draw overlining, etc. on the cursor. */
3165               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3166                 ns_draw_text_decoration (s, face, bgCol, width, x);
3167               else
3168                 ns_draw_text_decoration (s, face, fgCol, width, x);
3169             }
3170           else
3171             {
3172               NSRectFill (r[i]);
3173             }
3175           /* Draw overlining, etc. on the stretch glyph (or the part
3176              of the stretch glyph after the cursor). */
3177           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3178                                    r[i].origin.x);
3179         }
3180       ns_unfocus (s->f);
3181       s->background_filled_p = 1;
3182     }
3186 static void
3187 ns_draw_glyph_string (struct glyph_string *s)
3188 /* --------------------------------------------------------------------------
3189       External (RIF): Main draw-text call.
3190    -------------------------------------------------------------------------- */
3192   /* TODO (optimize): focus for box and contents draw */
3193   NSRect r[2];
3194   int n;
3195   char box_drawn_p = 0;
3197   NSTRACE (ns_draw_glyph_string);
3199   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3200     {
3201       int width;
3202       struct glyph_string *next;
3204       for (width = 0, next = s->next;
3205            next && width < s->right_overhang;
3206            width += next->width, next = next->next)
3207         if (next->first_glyph->type != IMAGE_GLYPH)
3208           {
3209             if (next->first_glyph->type != STRETCH_GLYPH)
3210               {
3211                 n = ns_get_glyph_string_clip_rect (s->next, r);
3212                 ns_focus (s->f, r, n);
3213                 ns_maybe_dumpglyphs_background (s->next, 1);
3214                 ns_unfocus (s->f);
3215               }
3216             else
3217               {
3218                 ns_dumpglyphs_stretch (s->next);
3219               }
3220             next->num_clips = 0;
3221           }
3222     }
3224   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3225         && (s->first_glyph->type == CHAR_GLYPH
3226             || s->first_glyph->type == COMPOSITE_GLYPH))
3227     {
3228       n = ns_get_glyph_string_clip_rect (s, r);
3229       ns_focus (s->f, r, n);
3230       ns_maybe_dumpglyphs_background (s, 1);
3231       ns_dumpglyphs_box_or_relief (s);
3232       ns_unfocus (s->f);
3233       box_drawn_p = 1;
3234     }
3236   switch (s->first_glyph->type)
3237     {
3239     case IMAGE_GLYPH:
3240       n = ns_get_glyph_string_clip_rect (s, r);
3241       ns_focus (s->f, r, n);
3242       ns_dumpglyphs_image (s, r[0]);
3243       ns_unfocus (s->f);
3244       break;
3246     case STRETCH_GLYPH:
3247       ns_dumpglyphs_stretch (s);
3248       break;
3250     case CHAR_GLYPH:
3251     case COMPOSITE_GLYPH:
3252       n = ns_get_glyph_string_clip_rect (s, r);
3253       ns_focus (s->f, r, n);
3255       if (s->for_overlaps || (s->cmp_from > 0
3256                               && ! s->first_glyph->u.cmp.automatic))
3257         s->background_filled_p = 1;
3258       else
3259         ns_maybe_dumpglyphs_background
3260           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3262       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3263                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3264                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3265                       NS_DUMPGLYPH_NORMAL));
3266       ns_tmp_font = (struct nsfont_info *)s->face->font;
3267       if (ns_tmp_font == NULL)
3268           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
3270       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3271         {
3272           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3273           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3274           NS_FACE_FOREGROUND (s->face) = tmp;
3275         }
3277       ns_tmp_font->font.driver->draw
3278         (s, 0, s->nchars, s->x, s->y,
3279          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3280          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
3282       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3283         {
3284           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3285           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3286           NS_FACE_FOREGROUND (s->face) = tmp;
3287         }
3289       ns_unfocus (s->f);
3290       break;
3292     case GLYPHLESS_GLYPH:
3293       n = ns_get_glyph_string_clip_rect (s, r);
3294       ns_focus (s->f, r, n);
3296       if (s->for_overlaps || (s->cmp_from > 0
3297                               && ! s->first_glyph->u.cmp.automatic))
3298         s->background_filled_p = 1;
3299       else
3300         ns_maybe_dumpglyphs_background
3301           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3302       /* ... */
3303       /* Not yet implemented.  */
3304       /* ... */
3305       ns_unfocus (s->f);
3306       break;
3308     default:
3309       abort ();
3310     }
3312   /* Draw box if not done already. */
3313   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3314     {
3315       n = ns_get_glyph_string_clip_rect (s, r);
3316       ns_focus (s->f, r, n);
3317       ns_dumpglyphs_box_or_relief (s);
3318       ns_unfocus (s->f);
3319     }
3321   s->num_clips = 0;
3326 /* ==========================================================================
3328     Event loop
3330    ========================================================================== */
3333 static void
3334 ns_send_appdefined (int value)
3335 /* --------------------------------------------------------------------------
3336     Internal: post an appdefined event which EmacsApp-sendEvent will
3337               recognize and take as a command to halt the event loop.
3338    -------------------------------------------------------------------------- */
3340   /*NSTRACE (ns_send_appdefined); */
3342   /* Only post this event if we haven't already posted one.  This will end
3343        the [NXApp run] main loop after having processed all events queued at
3344        this moment.  */
3345   if (send_appdefined)
3346     {
3347       NSEvent *nxev;
3349       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3350       send_appdefined = NO;
3352       /* Don't need wakeup timer any more */
3353       if (timed_entry)
3354         {
3355           [timed_entry invalidate];
3356           [timed_entry release];
3357           timed_entry = nil;
3358         }
3360       /* Ditto for file descriptor poller */
3361       if (fd_entry)
3362         {
3363           [fd_entry invalidate];
3364           [fd_entry release];
3365           fd_entry = nil;
3366         }
3368       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3369                                 location: NSMakePoint (0, 0)
3370                            modifierFlags: 0
3371                                timestamp: 0
3372                             windowNumber: [[NSApp mainWindow] windowNumber]
3373                                  context: [NSApp context]
3374                                  subtype: 0
3375                                    data1: value
3376                                    data2: 0];
3378       /* Post an application defined event on the event queue.  When this is
3379          received the [NXApp run] will return, thus having processed all
3380          events which are currently queued.  */
3381       [NSApp postEvent: nxev atStart: NO];
3382     }
3386 static int
3387 ns_read_socket (struct terminal *terminal, int expected,
3388                 struct input_event *hold_quit)
3389 /* --------------------------------------------------------------------------
3390      External (hook): Post an event to ourself and keep reading events until
3391      we read it back again.  In effect process all events which were waiting.
3392      From 21+ we have to manage the event buffer ourselves.
3393    -------------------------------------------------------------------------- */
3395   struct input_event ev;
3396   int nevents;
3398 /* NSTRACE (ns_read_socket); */
3400   if (interrupt_input_blocked)
3401     {
3402       interrupt_input_pending = 1;
3403 #ifdef SYNC_INPUT
3404       pending_signals = 1;
3405 #endif
3406       return -1;
3407     }
3409   interrupt_input_pending = 0;
3410 #ifdef SYNC_INPUT
3411   pending_signals = pending_atimers;
3412 #endif
3414   BLOCK_INPUT;
3415   n_emacs_events_pending = 0;
3416   EVENT_INIT (ev);
3417   emacs_event = &ev;
3418   q_event_ptr = hold_quit;
3420   /* we manage autorelease pools by allocate/reallocate each time around
3421      the loop; strict nesting is occasionally violated but seems not to
3422      matter.. earlier methods using full nesting caused major memory leaks */
3423   [outerpool release];
3424   outerpool = [[NSAutoreleasePool alloc] init];
3426   /* If have pending open-file requests, attend to the next one of those. */
3427   if (ns_pending_files && [ns_pending_files count] != 0
3428       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3429     {
3430       [ns_pending_files removeObjectAtIndex: 0];
3431     }
3432   /* Deal with pending service requests. */
3433   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3434     && [(EmacsApp *)
3435          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3436                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3437     {
3438       [ns_pending_service_names removeObjectAtIndex: 0];
3439       [ns_pending_service_args removeObjectAtIndex: 0];
3440     }
3441   else
3442     {
3443       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3444          to ourself, otherwise [NXApp run] will never exit.  */
3445       send_appdefined = YES;
3447       /* If called via ns_select, this is called once with expected=1,
3448          because we expect either the timeout or file descriptor activity.
3449          In this case the first event through will either be real input or
3450          one of these.  read_avail_input() then calls once more with expected=0
3451          and in that case we need to return quickly if there is nothing.
3452          If we're being called outside of that, it's also OK to return quickly
3453          after one iteration through the event loop, since other terms do
3454          this and emacs expects it. */
3455       if (!(inNsSelect && expected))
3456         {
3457           /* Post an application defined event on the event queue.  When this is
3458              received the [NXApp run] will return, thus having processed all
3459              events which are currently queued, if any.  */
3460           ns_send_appdefined (-1);
3461         }
3463       [NSApp run];
3464     }
3466   nevents = n_emacs_events_pending;
3467   n_emacs_events_pending = 0;
3468   emacs_event = q_event_ptr = NULL;
3469   UNBLOCK_INPUT;
3471   return nevents;
3476 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3477            fd_set *exceptfds, struct timeval *timeout)
3478 /* --------------------------------------------------------------------------
3479      Replacement for select, checking for events
3480    -------------------------------------------------------------------------- */
3482   int result;
3483   double time;
3484   NSEvent *ev;
3485 /*  NSTRACE (ns_select); */
3487   if (NSApp == nil || inNsSelect == 1 /* || ([NSApp isActive] == NO &&
3488                       [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil
3489  inMode:NSDefaultRunLoopMode dequeue:NO] == nil) */)
3490     return select (nfds, readfds, writefds, exceptfds, timeout);
3492   /* Save file descriptor set, which gets overwritten in calls to select ()
3493      Note, this is called from process.c, and only readfds is ever set */
3494   if (readfds)
3495     {
3496       memcpy (&select_readfds, readfds, sizeof (fd_set));
3497       select_nfds = nfds;
3498     }
3499   else
3500     select_nfds = 0;
3502     /* Try an initial select for pending data on input files */
3503   select_timeout.tv_sec = select_timeout.tv_usec = 0;
3504   result = select (nfds, readfds, writefds, exceptfds, &select_timeout);
3505   if (result)
3506     return result;
3508   /* if (!timeout || timed_entry || fd_entry)
3509        fprintf (stderr, "assertion failed: timeout null or timed_entry/fd_entry non-null in ns_select\n"); */
3511     /* set a timeout and run the main AppKit event loop while continuing
3512        to monitor the files */
3513   time = ((double) timeout->tv_sec) + ((double) timeout->tv_usec)/1000000.0;
3514   timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3515                                            target: NSApp
3516                                          selector: @selector (timeout_handler:)
3517                                          userInfo: 0
3518                                           repeats: YES] /* for safe removal */
3519                                                          retain];
3521   /* set a periodic task to try the select () again */
3522   fd_entry = [[NSTimer scheduledTimerWithTimeInterval: 0.1
3523                                                target: NSApp
3524                                              selector: @selector (fd_handler:)
3525                                              userInfo: 0
3526                                               repeats: YES]
3527                retain];
3529   /* Let Application dispatch events until it receives an event of the type
3530      NX_APPDEFINED, which should only be sent by timeout_handler.
3531      We tell read_avail_input() that input is "expected" because we do expect
3532      either the timeout or fd handler to fire, and if they don't, the original
3533      call from process.c that got us here expects us to wait until some input
3534      comes. */
3535   inNsSelect = 1;
3536   gobble_input (1);
3537   ev = last_appdefined_event;
3538   inNsSelect = 0;
3540   if (ev)
3541     {
3542       int t;
3543       if ([ev type] != NSApplicationDefined)
3544         abort ();
3546       t = [ev data1];
3547       last_appdefined_event = 0;
3549       if (t == -2)
3550         {
3551           /* The NX_APPDEFINED event we received was a timeout. */
3552           return 0;
3553         }
3554       else if (t == -1)
3555         {
3556           /* The NX_APPDEFINED event we received was the result of
3557              at least one real input event arriving.  */
3558           errno = EINTR;
3559           return -1;
3560         }
3561       else
3562         {
3563           /* Received back from select () in fd_handler; copy the results */
3564           if (readfds)
3565             memcpy (readfds, &select_readfds, sizeof (fd_set));
3566           return t;
3567         }
3568     }
3569   /* never reached, shut compiler up */
3570   return 0;
3575 /* ==========================================================================
3577     Scrollbar handling
3579    ========================================================================== */
3582 static void
3583 ns_set_vertical_scroll_bar (struct window *window,
3584                            int portion, int whole, int position)
3585 /* --------------------------------------------------------------------------
3586       External (hook): Update or add scrollbar
3587    -------------------------------------------------------------------------- */
3589   Lisp_Object win;
3590   NSRect r, v;
3591   struct frame *f = XFRAME (WINDOW_FRAME (window));
3592   EmacsView *view = FRAME_NS_VIEW (f);
3593   int window_y, window_height;
3594   BOOL barOnVeryLeft, barOnVeryRight;
3595   int top, left, height, width, sb_width, sb_left;
3596   EmacsScroller *bar;
3597 static int count = 0;
3599   /* optimization; display engine sends WAY too many of these.. */
3600   if (!NILP (window->vertical_scroll_bar))
3601     {
3602       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3603       if ([bar checkSamePosition: position portion: portion whole: whole])
3604         {
3605           if (view->scrollbarsNeedingUpdate == 0)
3606             {
3607               if (!windows_or_buffers_changed)
3608                   return;
3609             }
3610           else
3611             view->scrollbarsNeedingUpdate--;
3612         }
3613     }
3615   NSTRACE (ns_set_vertical_scroll_bar);
3617   /* Get dimensions.  */
3618   window_box (window, -1, 0, &window_y, 0, &window_height);
3619   top = window_y;
3620   height = window_height;
3621   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3622   left = WINDOW_SCROLL_BAR_AREA_X (window);
3624   if (top < 5) /* top scrollbar adjustment */
3625     {
3626       top -= FRAME_INTERNAL_BORDER_WIDTH (f);
3627       height += FRAME_INTERNAL_BORDER_WIDTH (f);
3628     }
3630   /* allow for displaying a skinnier scrollbar than char area allotted */
3631   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3632     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3634   barOnVeryLeft = left < 5;
3635   barOnVeryRight = FRAME_PIXEL_WIDTH (f) - left - width < 5;
3636   sb_left = left + FRAME_INTERNAL_BORDER_WIDTH (f)
3637       * (barOnVeryLeft ? -1 : (barOnVeryRight ? 1 : 0));
3639   r = NSMakeRect (sb_left, top, sb_width, height);
3640   /* the parent view is flipped, so we need to flip y value */
3641   v = [view frame];
3642   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3644   XSETWINDOW (win, window);
3645   BLOCK_INPUT;
3647   /* we want at least 5 lines to display a scrollbar */
3648   if (WINDOW_TOTAL_LINES (window) < 5)
3649     {
3650       if (!NILP (window->vertical_scroll_bar))
3651         {
3652           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3653           [bar removeFromSuperview];
3654           window->vertical_scroll_bar = Qnil;
3655         }
3656       ns_clear_frame_area (f, sb_left, top, width, height);
3657       UNBLOCK_INPUT;
3658       return;
3659     }
3661   if (NILP (window->vertical_scroll_bar))
3662     {
3663       ns_clear_frame_area (f, sb_left, top, width, height);
3664       bar = [[EmacsScroller alloc] initFrame: r window: win];
3665       window->vertical_scroll_bar = make_save_value (bar, 0);
3666     }
3667   else
3668     {
3669       NSRect oldRect;
3670       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3671       oldRect = [bar frame];
3672       r.size.width = oldRect.size.width;
3673       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3674         {
3675           if (oldRect.origin.x != r.origin.x)
3676               ns_clear_frame_area (f, sb_left, top, width, height);
3677           [bar setFrame: r];
3678         }
3679     }
3681   [bar setPosition: position portion: portion whole: whole];
3682   UNBLOCK_INPUT;
3686 static void
3687 ns_condemn_scroll_bars (struct frame *f)
3688 /* --------------------------------------------------------------------------
3689      External (hook): arrange for all frame's scrollbars to be removed
3690      at next call to judge_scroll_bars, except for those redeemed.
3691    -------------------------------------------------------------------------- */
3693   int i;
3694   id view;
3695   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3697   NSTRACE (ns_condemn_scroll_bars);
3699   for (i =[subviews count]-1; i >= 0; i--)
3700     {
3701       view = [subviews objectAtIndex: i];
3702       if ([view isKindOfClass: [EmacsScroller class]])
3703         [view condemn];
3704     }
3708 static void
3709 ns_redeem_scroll_bar (struct window *window)
3710 /* --------------------------------------------------------------------------
3711      External (hook): arrange to spare this window's scrollbar
3712      at next call to judge_scroll_bars.
3713    -------------------------------------------------------------------------- */
3715   id bar;
3716   NSTRACE (ns_redeem_scroll_bar);
3717   if (!NILP (window->vertical_scroll_bar))
3718     {
3719       bar =XNS_SCROLL_BAR (window->vertical_scroll_bar);
3720       [bar reprieve];
3721     }
3725 static void
3726 ns_judge_scroll_bars (struct frame *f)
3727 /* --------------------------------------------------------------------------
3728      External (hook): destroy all scrollbars on frame that weren't
3729      redeemed after call to condemn_scroll_bars.
3730    -------------------------------------------------------------------------- */
3732   int i;
3733   id view;
3734   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3735   NSTRACE (ns_judge_scroll_bars);
3736   for (i =[subviews count]-1; i >= 0; i--)
3737     {
3738       view = [subviews objectAtIndex: i];
3739       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3740       [view judge];
3741     }
3745 void
3746 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
3748   /* XXX irrelevant under NS */
3753 /* ==========================================================================
3755     Initialization
3757    ========================================================================== */
3760 x_display_pixel_height (struct ns_display_info *dpyinfo)
3762   NSScreen *screen = [NSScreen mainScreen];
3763   return [screen frame].size.height;
3767 x_display_pixel_width (struct ns_display_info *dpyinfo)
3769   NSScreen *screen = [NSScreen mainScreen];
3770   return [screen frame].size.width;
3774 static Lisp_Object ns_string_to_lispmod (const char *s)
3775 /* --------------------------------------------------------------------------
3776      Convert modifier name to lisp symbol
3777    -------------------------------------------------------------------------- */
3779   if (!strncmp (SDATA (SYMBOL_NAME (Qmeta)), s, 10))
3780     return Qmeta;
3781   else if (!strncmp (SDATA (SYMBOL_NAME (Qsuper)), s, 10))
3782     return Qsuper;
3783   else if (!strncmp (SDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3784     return Qcontrol;
3785   else if (!strncmp (SDATA (SYMBOL_NAME (Qalt)), s, 10))
3786     return Qalt;
3787   else if (!strncmp (SDATA (SYMBOL_NAME (Qhyper)), s, 10))
3788     return Qhyper;
3789   else if (!strncmp (SDATA (SYMBOL_NAME (Qnone)), s, 10))
3790     return Qnone;
3791   else
3792     return Qnil;
3796 static Lisp_Object ns_mod_to_lisp (int m)
3797 /* --------------------------------------------------------------------------
3798      Convert modifier code (see lisp.h) to lisp symbol
3799    -------------------------------------------------------------------------- */
3801   if (m == CHAR_META)
3802     return Qmeta;
3803   else if (m == CHAR_SUPER)
3804     return Qsuper;
3805   else if (m == CHAR_CTL)
3806     return Qcontrol;
3807   else if (m == CHAR_ALT)
3808     return Qalt;
3809   else if (m == CHAR_HYPER)
3810     return Qhyper;
3811   else /* if (m == 0) */
3812     return Qnone;
3816 static void
3817 ns_default (const char *parameter, Lisp_Object *result,
3818            Lisp_Object yesval, Lisp_Object noval,
3819            BOOL is_float, BOOL is_modstring)
3820 /* --------------------------------------------------------------------------
3821       Check a parameter value in user's preferences
3822    -------------------------------------------------------------------------- */
3824   const char *value = ns_get_defaults_value (parameter);
3826   if (value)
3827     {
3828       double f;
3829       char *pos;
3830       if (strcasecmp (value, "YES") == 0)
3831         *result = yesval;
3832       else if (strcasecmp (value, "NO") == 0)
3833         *result = noval;
3834       else if (is_float && (f = strtod (value, &pos), pos != value))
3835         *result = make_float (f);
3836       else if (is_modstring && value)
3837         *result = ns_string_to_lispmod (value);
3838       else fprintf (stderr,
3839                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3840     }
3844 void
3845 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3846 /* --------------------------------------------------------------------------
3847       Initialize global info and storage for display.
3848    -------------------------------------------------------------------------- */
3850     NSScreen *screen = [NSScreen mainScreen];
3851     NSWindowDepth depth = [screen depth];
3852     Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
3854     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3855     dpyinfo->resy = 72.27;
3856     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3857                                                   NSColorSpaceFromDepth (depth)]
3858                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3859                                                  NSColorSpaceFromDepth (depth)];
3860     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3861     dpyinfo->image_cache = make_image_cache ();
3862     dpyinfo->color_table
3863       = (struct ns_color_table *)xmalloc (sizeof (struct ns_color_table));
3864     dpyinfo->color_table->colors = NULL;
3865     dpyinfo->root_window = 42; /* a placeholder.. */
3867     hlinfo->mouse_face_mouse_frame = NULL;
3868     hlinfo->mouse_face_deferred_gc = 0;
3869     hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
3870     hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
3871     hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
3872     hlinfo->mouse_face_window = hlinfo->mouse_face_overlay = Qnil;
3873     hlinfo->mouse_face_hidden = 0;
3875     hlinfo->mouse_face_mouse_x = hlinfo->mouse_face_mouse_y = 0;
3876     hlinfo->mouse_face_defer = 0;
3878     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3880     dpyinfo->n_fonts = 0;
3881     dpyinfo->smallest_font_height = 1;
3882     dpyinfo->smallest_char_width = 1;
3886 /* This and next define (many of the) public functions in this file. */
3887 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3888          with using despite presence in the "system dependent" redisplay
3889          interface.  In addition, many of the ns_ methods have code that is
3890          shared with all terms, indicating need for further refactoring. */
3891 extern frame_parm_handler ns_frame_parm_handlers[];
3892 static struct redisplay_interface ns_redisplay_interface =
3894   ns_frame_parm_handlers,
3895   x_produce_glyphs,
3896   x_write_glyphs,
3897   x_insert_glyphs,
3898   x_clear_end_of_line,
3899   ns_scroll_run,
3900   ns_after_update_window_line,
3901   ns_update_window_begin,
3902   ns_update_window_end,
3903   x_cursor_to,
3904   ns_flush,
3905   0, /* flush_display_optional */
3906   x_clear_window_mouse_face,
3907   x_get_glyph_overhangs,
3908   x_fix_overlapping_area,
3909   ns_draw_fringe_bitmap,
3910   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3911   0, /* destroy_fringe_bitmap */
3912   ns_compute_glyph_string_overhangs,
3913   ns_draw_glyph_string, /* interface to nsfont.m */
3914   ns_define_frame_cursor,
3915   ns_clear_frame_area,
3916   ns_draw_window_cursor,
3917   ns_draw_vertical_window_border,
3918   ns_shift_glyphs_for_insert
3922 static void
3923 ns_delete_display (struct ns_display_info *dpyinfo)
3925   /* TODO... */
3929 /* This function is called when the last frame on a display is deleted. */
3930 static void
3931 ns_delete_terminal (struct terminal *terminal)
3933   struct ns_display_info *dpyinfo = terminal->display_info.ns;
3934   int i;
3936   /* Protect against recursive calls.  delete_frame in
3937      delete_terminal calls us back when it deletes our last frame.  */
3938   if (!terminal->name)
3939     return;
3941   BLOCK_INPUT;
3943   x_destroy_all_bitmaps (dpyinfo);
3944   ns_delete_display (dpyinfo);
3945   UNBLOCK_INPUT;
3949 static struct terminal *
3950 ns_create_terminal (struct ns_display_info *dpyinfo)
3951 /* --------------------------------------------------------------------------
3952       Set up use of NS before we make the first connection.
3953    -------------------------------------------------------------------------- */
3955   struct terminal *terminal;
3957   NSTRACE (ns_create_terminal);
3959   terminal = create_terminal ();
3961   terminal->type = output_ns;
3962   terminal->display_info.ns = dpyinfo;
3963   dpyinfo->terminal = terminal;
3965   terminal->rif = &ns_redisplay_interface;
3967   terminal->clear_frame_hook = ns_clear_frame;
3968   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
3969   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
3970   terminal->ring_bell_hook = ns_ring_bell;
3971   terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
3972   terminal->set_terminal_modes_hook = ns_set_terminal_modes;
3973   terminal->update_begin_hook = ns_update_begin;
3974   terminal->update_end_hook = ns_update_end;
3975   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
3976   terminal->read_socket_hook = ns_read_socket;
3977   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
3978   terminal->mouse_position_hook = ns_mouse_position;
3979   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
3980   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
3982   terminal->fullscreen_hook = 0; /* see XTfullscreen_hook */
3984   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
3985   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
3986   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
3987   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
3989   terminal->delete_frame_hook = x_destroy_window;
3990   terminal->delete_terminal_hook = ns_delete_terminal;
3992   terminal->scroll_region_ok = 1;
3993   terminal->char_ins_del_ok = 1;
3994   terminal->line_ins_del_ok = 1;
3995   terminal->fast_clear_end_of_line = 1;
3996   terminal->memory_below_frame = 0;
3998   return terminal;
4002 struct ns_display_info *
4003 ns_term_init (Lisp_Object display_name)
4004 /* --------------------------------------------------------------------------
4005      Start the Application and get things rolling.
4006    -------------------------------------------------------------------------- */
4008   struct terminal *terminal;
4009   struct ns_display_info *dpyinfo;
4010   static int ns_initialized = 0;
4011   Lisp_Object tmp;
4013   NSTRACE (ns_term_init);
4015   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4016   /*GSDebugAllocationActive (YES); */
4017   BLOCK_INPUT;
4018   handling_signal = 0;
4020   if (!ns_initialized)
4021     {
4022       baud_rate = 38400;
4023       Fset_input_interrupt_mode (Qnil);
4024       ns_initialized = 1;
4025     }
4027   ns_pending_files = [[NSMutableArray alloc] init];
4028   ns_pending_service_names = [[NSMutableArray alloc] init];
4029   ns_pending_service_args = [[NSMutableArray alloc] init];
4031   /* Start app and create the main menu, window, view.
4032      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4033      The view will then ask the NSApp to stop and return to Emacs. */
4034   [EmacsApp sharedApplication];
4035   if (NSApp == nil)
4036     return NULL;
4037   [NSApp setDelegate: NSApp];
4039   /* debugging: log all notifications */
4040   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4041                                          selector: @selector (logNotification:)
4042                                              name: nil object: nil]; */
4044   dpyinfo = (struct ns_display_info *)xmalloc (sizeof (struct ns_display_info));
4045   memset (dpyinfo, 0, sizeof (struct ns_display_info));
4047   ns_initialize_display_info (dpyinfo);
4048   terminal = ns_create_terminal (dpyinfo);
4050   terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
4051   init_kboard (terminal->kboard);
4052   KVAR (terminal->kboard, Vwindow_system) = Qns;
4053   terminal->kboard->next_kboard = all_kboards;
4054   all_kboards = terminal->kboard;
4055   /* Don't let the initial kboard remain current longer than necessary.
4056      That would cause problems if a file loaded on startup tries to
4057      prompt in the mini-buffer.  */
4058   if (current_kboard == initial_kboard)
4059     current_kboard = terminal->kboard;
4060   terminal->kboard->reference_count++;
4062   dpyinfo->next = x_display_list;
4063   x_display_list = dpyinfo;
4065   /* Put it on ns_display_name_list */
4066   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
4067                                 ns_display_name_list);
4068   dpyinfo->name_list_element = XCAR (ns_display_name_list);
4070   /* Set the name of the terminal. */
4071   terminal->name = (char *) xmalloc (SBYTES (display_name) + 1);
4072   strncpy (terminal->name, SDATA (display_name), SBYTES (display_name));
4073   terminal->name[SBYTES (display_name)] = 0;
4075   UNBLOCK_INPUT;
4077   if (!inhibit_x_resources)
4078     {
4079       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4080                  Qt, Qnil, NO, NO);
4081       tmp = Qnil;
4082       /* this is a standard variable */
4083       ns_default ("AppleAntiAliasingThreshold", &tmp,
4084                  make_float (10.0), make_float (6.0), YES, NO);
4085       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4086     }
4088   ns_selection_color = [[NSUserDefaults standardUserDefaults]
4089                          stringForKey: @"AppleHighlightColor"];
4090   if (ns_selection_color == nil)
4091     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
4093   {
4094     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4096     if ( cl == nil )
4097       {
4098         Lisp_Object color_file, color_map, color;
4099         int r,g,b;
4100         unsigned long c;
4101         char *name;
4103         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4104                          Fsymbol_value (intern ("data-directory")));
4105         if (NILP (Ffile_readable_p (color_file)))
4106           fatal ("Could not find %s.\n", SDATA (color_file));
4108         color_map = Fx_load_color_file (color_file);
4109         if (NILP (color_map))
4110           fatal ("Could not read %s.\n", SDATA (color_file));
4112         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4113         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4114           {
4115             color = XCAR (color_map);
4116             name = SDATA (XCAR (color));
4117             c = XINT (XCDR (color));
4118             [cl setColor:
4119                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4120                                             green: GREEN_FROM_ULONG (c) / 255.0
4121                                              blue: BLUE_FROM_ULONG (c) / 255.0
4122                                             alpha: 1.0]
4123                   forKey: [NSString stringWithUTF8String: name]];
4124           }
4125         [cl writeToFile: nil];
4126       }
4127   }
4129   {
4130     char c[128];
4131 #ifdef NS_IMPL_GNUSTEP
4132     strncpy (c, gnustep_base_version, sizeof (c));
4133 #else
4134     /*PSnextrelease (128, c); */
4135     snprintf (c, sizeof (c), "%g", NSAppKitVersionNumber);
4136 #endif
4137     Vwindow_system_version = build_string (c);
4138   }
4140   delete_keyboard_wait_descriptor (0);
4142   ns_app_name = [[NSProcessInfo processInfo] processName];
4144 /* Set up OS X app menu */
4145 #ifdef NS_IMPL_COCOA
4146   {
4147     NSMenu *appMenu;
4148     NSMenuItem *item;
4149     /* set up the application menu */
4150     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4151     [svcsMenu setAutoenablesItems: NO];
4152     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4153     [appMenu setAutoenablesItems: NO];
4154     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4155     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4157     [appMenu insertItemWithTitle: @"About Emacs"
4158                           action: @selector (orderFrontStandardAboutPanel:)
4159                    keyEquivalent: @""
4160                          atIndex: 0];
4161     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4162     [appMenu insertItemWithTitle: @"Preferences..."
4163                           action: @selector (showPreferencesWindow:)
4164                    keyEquivalent: @","
4165                          atIndex: 2];
4166     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4167     item = [appMenu insertItemWithTitle: @"Services"
4168                                  action: @selector (menuDown:)
4169                           keyEquivalent: @""
4170                                 atIndex: 4];
4171     [appMenu setSubmenu: svcsMenu forItem: item];
4172     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4173     [appMenu insertItemWithTitle: @"Hide Emacs"
4174                           action: @selector (hide:)
4175                    keyEquivalent: @"h"
4176                          atIndex: 6];
4177     item =  [appMenu insertItemWithTitle: @"Hide Others"
4178                           action: @selector (hideOtherApplications:)
4179                    keyEquivalent: @"h"
4180                          atIndex: 7];
4181     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4182     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4183     [appMenu insertItemWithTitle: @"Quit Emacs"
4184                           action: @selector (terminate:)
4185                    keyEquivalent: @"q"
4186                          atIndex: 9];
4188     item = [mainMenu insertItemWithTitle: ns_app_name
4189                                   action: @selector (menuDown:)
4190                            keyEquivalent: @""
4191                                  atIndex: 0];
4192     [mainMenu setSubmenu: appMenu forItem: item];
4193     [dockMenu insertItemWithTitle: @"New Frame"
4194                            action: @selector (newFrame:)
4195                     keyEquivalent: @""
4196                           atIndex: 0];
4198     [NSApp setMainMenu: mainMenu];
4199     [NSApp setAppleMenu: appMenu];
4200     [NSApp setServicesMenu: svcsMenu];
4201     /* Needed at least on Cocoa, to get dock menu to show windows */
4202     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4204     [[NSNotificationCenter defaultCenter]
4205       addObserver: mainMenu
4206          selector: @selector (trackingNotification:)
4207              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4208     [[NSNotificationCenter defaultCenter]
4209       addObserver: mainMenu
4210          selector: @selector (trackingNotification:)
4211              name: NSMenuDidEndTrackingNotification object: mainMenu];
4212   }
4213 #endif /* MAC OS X menu setup */
4215   [NSApp run];
4217   return dpyinfo;
4221 void
4222 ns_term_shutdown (int sig)
4224   [[NSUserDefaults standardUserDefaults] synchronize];
4226   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4227   if (STRINGP (Vauto_save_list_file_name))
4228     unlink (SDATA (Vauto_save_list_file_name));
4230   if (sig == 0 || sig == SIGTERM)
4231     {
4232       [NSApp terminate: NSApp];
4233     }
4234   else // force a stack trace to happen
4235     {
4236       abort();
4237     }
4241 /* ==========================================================================
4243     EmacsApp implementation
4245    ========================================================================== */
4248 @implementation EmacsApp
4250 - (void)logNotification: (NSNotification *)notification
4252   const char *name = [[notification name] UTF8String];
4253   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4254       && !strstr (name, "WindowNumber"))
4255     NSLog (@"notification: '%@'", [notification name]);
4259 - (void)sendEvent: (NSEvent *)theEvent
4260 /* --------------------------------------------------------------------------
4261      Called when NSApp is running for each event received.  Used to stop
4262      the loop when we choose, since there's no way to just run one iteration.
4263    -------------------------------------------------------------------------- */
4265   int type = [theEvent type];
4266   NSWindow *window = [theEvent window];
4267 /*  NSTRACE (sendEvent); */
4268 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4270 #ifdef NS_IMPL_COCOA
4271   if (type == NSApplicationDefined
4272       && [theEvent data2] == NSAPP_DATA2_RUNASSCRIPT)
4273     {
4274       ns_run_ascript ();
4275       [self stop: self];
4276       return;
4277     }
4278 #endif
4280   if (type == NSCursorUpdate && window == nil)
4281     {
4282       fprintf (stderr, "Dropping external cursor update event.\n");
4283       return;
4284     }
4286 #ifdef NS_IMPL_COCOA
4287   /* pass mouse down in resize handle and subsequent drags directly to
4288      EmacsWindow so we can generate continuous redisplays */
4289   if (ns_in_resize)
4290     {
4291       if (type == NSLeftMouseDragged)
4292         {
4293           [window mouseDragged: theEvent];
4294           return;
4295         }
4296       else if (type == NSLeftMouseUp)
4297         {
4298           [window mouseUp: theEvent];
4299           return;
4300         }
4301     }
4302   else if (type == NSLeftMouseDown)
4303     {
4304       NSRect r = ns_resize_handle_rect (window);
4305       if (NSPointInRect ([theEvent locationInWindow], r))
4306         {
4307           ns_in_resize = YES;
4308           [window mouseDown: theEvent];
4309           return;
4310         }
4311     }
4312 #endif
4314   if (type == NSApplicationDefined)
4315     {
4316       /* Events posted by ns_send_appdefined interrupt the run loop here.
4317          But, if a modal window is up, an appdefined can still come through,
4318          (e.g., from a makeKeyWindow event) but stopping self also stops the
4319          modal loop. Just defer it until later. */
4320       if ([NSApp modalWindow] == nil)
4321         {
4322           last_appdefined_event = theEvent;
4323           [self stop: self];
4324         }
4325       else
4326         {
4327           send_appdefined = YES;
4328         }
4329     }
4331   [super sendEvent: theEvent];
4335 - (void)showPreferencesWindow: (id)sender
4337   struct frame *emacsframe = SELECTED_FRAME ();
4338   NSEvent *theEvent = [NSApp currentEvent];
4340   if (!emacs_event)
4341     return;
4342   emacs_event->kind = NS_NONKEY_EVENT;
4343   emacs_event->code = KEY_NS_SHOW_PREFS;
4344   emacs_event->modifiers = 0;
4345   EV_TRAILER (theEvent);
4349 - (void)newFrame: (id)sender
4351   struct frame *emacsframe = SELECTED_FRAME ();
4352   NSEvent *theEvent = [NSApp currentEvent];
4354   if (!emacs_event)
4355     return;
4356   emacs_event->kind = NS_NONKEY_EVENT;
4357   emacs_event->code = KEY_NS_NEW_FRAME;
4358   emacs_event->modifiers = 0;
4359   EV_TRAILER (theEvent);
4363 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4364 - (BOOL) openFile: (NSString *)fileName
4366   struct frame *emacsframe = SELECTED_FRAME ();
4367   NSEvent *theEvent = [NSApp currentEvent];
4369   if (!emacs_event)
4370     return NO;
4372   emacs_event->kind = NS_NONKEY_EVENT;
4373   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4374   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4375   ns_input_line = Qnil; /* can be start or cons start,end */
4376   emacs_event->modifiers =0;
4377   EV_TRAILER (theEvent);
4379   return YES;
4383 /* **************************************************************************
4385       EmacsApp delegate implementation
4387    ************************************************************************** */
4389 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4390 /* --------------------------------------------------------------------------
4391      When application is loaded, terminate event loop in ns_term_init
4392    -------------------------------------------------------------------------- */
4394   NSTRACE (applicationDidFinishLaunching);
4395   [NSApp setServicesProvider: NSApp];
4396   ns_send_appdefined (-2);
4400 /* Termination sequences:
4401     C-x C-c:
4402     Cmd-Q:
4403     MenuBar | File | Exit:
4404     Select Quit from App menubar:
4405         -terminate
4406         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4407         ns_term_shutdown()
4409     Select Quit from Dock menu:
4410     Logout attempt:
4411         -appShouldTerminate
4412           Cancel -> Nothing else
4413           Accept ->
4415           -terminate
4416           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4417           ns_term_shutdown()
4421 - (void) terminate: (id)sender
4423   struct frame *emacsframe = SELECTED_FRAME ();
4425   if (!emacs_event)
4426     return;
4428   emacs_event->kind = NS_NONKEY_EVENT;
4429   emacs_event->code = KEY_NS_POWER_OFF;
4430   emacs_event->arg = Qt; /* mark as non-key event */
4431   EV_TRAILER ((id)nil);
4435 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4437   int ret;
4439   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4440     return NSTerminateNow;
4442     ret = NSRunAlertPanel(ns_app_name,
4443                           [NSString stringWithUTF8String:"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?"],
4444                           @"Save Buffers and Exit", @"Cancel", nil);
4446     if (ret == NSAlertDefaultReturn)
4447         return NSTerminateNow;
4448     else if (ret == NSAlertAlternateReturn)
4449         return NSTerminateCancel;
4450     return NSTerminateNow;  /* just in case */
4454 /*   Notification from the Workspace to open a file */
4455 - (BOOL)application: sender openFile: (NSString *)file
4457   [ns_pending_files addObject: file];
4458   return YES;
4462 /*   Open a file as a temporary file */
4463 - (BOOL)application: sender openTempFile: (NSString *)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   [ns_pending_files addObject: file];
4474   return YES;
4478 /*   Notification from the Workspace to open multiple files */
4479 - (void)application: sender openFiles: (NSArray *)fileList
4481   NSEnumerator *files = [fileList objectEnumerator];
4482   NSString *file;
4483   while ((file = [files nextObject]) != nil)
4484     [ns_pending_files addObject: file];
4486   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4491 /* Handle dock menu requests.  */
4492 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4494   return dockMenu;
4498 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4499 - (void)applicationWillBecomeActive: (NSNotification *)notification
4501   //ns_app_active=YES;
4503 - (void)applicationDidBecomeActive: (NSNotification *)notification
4505   NSTRACE (applicationDidBecomeActive);
4507   //ns_app_active=YES;
4509   ns_update_auto_hide_menu_bar ();
4510   // No constraining takes place when the application is not active.
4511   ns_constrain_all_frames ();
4513 - (void)applicationDidResignActive: (NSNotification *)notification
4515   //ns_app_active=NO;
4516   ns_send_appdefined (-1);
4521 /* ==========================================================================
4523     EmacsApp aux handlers for managing event loop
4525    ========================================================================== */
4528 - (void)timeout_handler: (NSTimer *)timedEntry
4529 /* --------------------------------------------------------------------------
4530      The timeout specified to ns_select has passed.
4531    -------------------------------------------------------------------------- */
4533   /*NSTRACE (timeout_handler); */
4534   ns_send_appdefined (-2);
4537 - (void)fd_handler: (NSTimer *) fdEntry
4538 /* --------------------------------------------------------------------------
4539      Check data waiting on file descriptors and terminate if so
4540    -------------------------------------------------------------------------- */
4542   int result;
4543   /* NSTRACE (fd_handler); */
4545   if (select_nfds == 0)
4546     return;
4548   memcpy (&t_readfds, &select_readfds, sizeof (fd_set));
4550   select_timeout.tv_sec = select_timeout.tv_usec = 0;
4551   result = select (select_nfds, &t_readfds, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
4552                   &select_timeout);
4553   if (result)
4554     {
4555       memcpy (&select_readfds, &t_readfds, sizeof (fd_set));
4556       ns_send_appdefined (result);
4557     }
4562 /* ==========================================================================
4564     Service provision
4566    ========================================================================== */
4568 /* called from system: queue for next pass through event loop */
4569 - (void)requestService: (NSPasteboard *)pboard
4570               userData: (NSString *)userData
4571                  error: (NSString **)error
4573   [ns_pending_service_names addObject: userData];
4574   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4575       SDATA (ns_string_from_pasteboard (pboard))]];
4579 /* called from ns_read_socket to clear queue */
4580 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4582   struct frame *emacsframe = SELECTED_FRAME ();
4583   NSEvent *theEvent = [NSApp currentEvent];
4585   if (!emacs_event)
4586     return NO;
4588   emacs_event->kind = NS_NONKEY_EVENT;
4589   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4590   ns_input_spi_name = build_string ([name UTF8String]);
4591   ns_input_spi_arg = build_string ([arg UTF8String]);
4592   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4593   EV_TRAILER (theEvent);
4595   return YES;
4599 @end  /* EmacsApp */
4603 /* ==========================================================================
4605     EmacsView implementation
4607    ========================================================================== */
4610 @implementation EmacsView
4612 /* needed to inform when window closed from LISP */
4613 - (void) setWindowClosing: (BOOL)closing
4615   windowClosing = closing;
4619 - (void)dealloc
4621   NSTRACE (EmacsView_dealloc);
4622   [toolbar release];
4623   [super dealloc];
4627 /* called on font panel selection */
4628 - (void)changeFont: (id)sender
4630   NSEvent *e =[[self window] currentEvent];
4631   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4632   id newFont;
4633   float size;
4635   NSTRACE (changeFont);
4636   if (!emacs_event)
4637     return;
4639   if (newFont = [sender convertFont:
4640                            ((struct nsfont_info *)face->font)->nsfont])
4641     {
4642       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4644       emacs_event->kind = NS_NONKEY_EVENT;
4645       emacs_event->modifiers = 0;
4646       emacs_event->code = KEY_NS_CHANGE_FONT;
4648       size = [newFont pointSize];
4649       ns_input_fontsize = make_number (lrint (size));
4650       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4651       EV_TRAILER (e);
4652     }
4656 - (BOOL)acceptsFirstResponder
4658   NSTRACE (acceptsFirstResponder);
4659   return YES;
4663 - (void)resetCursorRects
4665   NSRect visible = [self visibleRect];
4666   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4667   NSTRACE (resetCursorRects);
4669   if (currentCursor == nil)
4670     currentCursor = [NSCursor arrowCursor];
4672   if (!NSIsEmptyRect (visible))
4673     [self addCursorRect: visible cursor: currentCursor];
4674   [currentCursor setOnMouseEntered: YES];
4679 /*****************************************************************************/
4680 /* Keyboard handling. */
4681 #define NS_KEYLOG 0
4683 - (void)keyDown: (NSEvent *)theEvent
4685   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4686   int code;
4687   unsigned fnKeysym = 0;
4688   int flags;
4689   static NSMutableArray *nsEvArray;
4690 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4691   static BOOL firstTime = YES;
4692 #endif
4693   int left_is_none;
4695   NSTRACE (keyDown);
4697   /* Rhapsody and OS X give up and down events for the arrow keys */
4698   if (ns_fake_keydown == YES)
4699     ns_fake_keydown = NO;
4700   else if ([theEvent type] != NSKeyDown)
4701     return;
4703   if (!emacs_event)
4704     return;
4706  if (![[self window] isKeyWindow]
4707      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4708      /* we must avoid an infinite loop here. */
4709      && (EmacsView *)[[theEvent window] delegate] != self)
4710    {
4711      /* XXX: There is an occasional condition in which, when Emacs display
4712          updates a different frame from the current one, and temporarily
4713          selects it, then processes some interrupt-driven input
4714          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4715          for some reason that window has its first responder set to the NSView
4716          most recently updated (I guess), which is not the correct one. */
4717      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4718      return;
4719    }
4721   if (nsEvArray == nil)
4722     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4724   [NSCursor setHiddenUntilMouseMoves: YES];
4726   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4727     {
4728       clear_mouse_face (hlinfo);
4729       hlinfo->mouse_face_hidden = 1;
4730     }
4732   if (!processingCompose)
4733     {
4734       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4735         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4736       /* (Carbon way: [theEvent keyCode]) */
4738       /* is it a "function key"? */
4739       fnKeysym = ns_convert_key (code);
4740       if (fnKeysym)
4741         {
4742           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4743              because Emacs treats Delete and KP-Delete same (in simple.el). */
4744           if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4745             code = 0xFF08; /* backspace */
4746           else
4747             code = fnKeysym;
4748         }
4750       /* are there modifiers? */
4751       emacs_event->modifiers = 0;
4752       flags = [theEvent modifierFlags];
4754       if (flags & NSHelpKeyMask)
4755           emacs_event->modifiers |= hyper_modifier;
4757       if (flags & NSShiftKeyMask)
4758         emacs_event->modifiers |= shift_modifier;
4760       if ((flags & NSRightCommandKeyMask) == NSRightCommandKeyMask)
4761         emacs_event->modifiers |= parse_solitary_modifier
4762           (EQ (ns_right_command_modifier, Qleft)
4763            ? ns_command_modifier
4764            : ns_right_command_modifier);
4766       if ((flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask)
4767         {
4768           emacs_event->modifiers |= parse_solitary_modifier
4769             (ns_command_modifier);
4771           /* if super (default), take input manager's word so things like
4772              dvorak / qwerty layout work */
4773           if (EQ (ns_command_modifier, Qsuper)
4774               && !fnKeysym
4775               && [[theEvent characters] length] != 0)
4776             {
4777               /* XXX: the code we get will be unshifted, so if we have
4778                  a shift modifier, must convert ourselves */
4779               if (!(flags & NSShiftKeyMask))
4780                 code = [[theEvent characters] characterAtIndex: 0];
4781 #if 0
4782               /* this is ugly and also requires linking w/Carbon framework
4783                  (for LMGetKbdType) so for now leave this rare (?) case
4784                  undealt with.. in future look into CGEvent methods */
4785               else
4786                 {
4787                   long smv = GetScriptManagerVariable (smKeyScript);
4788                   Handle uchrHandle = GetResource
4789                     ('uchr', GetScriptVariable (smv, smScriptKeys));
4790                   UInt32 dummy = 0;
4791                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
4792                                  [[theEvent characters] characterAtIndex: 0],
4793                                  kUCKeyActionDisplay,
4794                                  (flags & ~NSCommandKeyMask) >> 8,
4795                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
4796                                  &dummy, 1, &dummy, &code);
4797                   code &= 0xFF;
4798                 }
4799 #endif
4800             }
4801         }
4803       if ((flags & NSRightControlKeyMask) == NSRightControlKeyMask)
4804           emacs_event->modifiers |= parse_solitary_modifier
4805               (EQ (ns_right_control_modifier, Qleft)
4806                ? ns_control_modifier
4807                : ns_right_control_modifier);
4809       if ((flags & NSLeftControlKeyMask) == NSLeftControlKeyMask)
4810         emacs_event->modifiers |= parse_solitary_modifier
4811           (ns_control_modifier);
4813       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
4814           emacs_event->modifiers |=
4815             parse_solitary_modifier (ns_function_modifier);
4817       left_is_none = NILP (ns_alternate_modifier)
4818         || EQ (ns_alternate_modifier, Qnone);
4820       if ((flags & NSRightAlternateKeyMask) == NSRightAlternateKeyMask)
4821         {
4822           if ((NILP (ns_right_alternate_modifier)
4823                || EQ (ns_right_alternate_modifier, Qnone)
4824                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
4825               && !fnKeysym)
4826             {   /* accept pre-interp alt comb */
4827               if ([[theEvent characters] length] > 0)
4828                 code = [[theEvent characters] characterAtIndex: 0];
4829               /*HACK: clear lone shift modifier to stop next if from firing */
4830               if (emacs_event->modifiers == shift_modifier)
4831                 emacs_event->modifiers = 0;
4832             }
4833           else
4834             emacs_event->modifiers |= parse_solitary_modifier
4835               (EQ (ns_right_alternate_modifier, Qleft)
4836                ? ns_alternate_modifier
4837                : ns_right_alternate_modifier);
4838         }
4840       if ((flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask) /* default = meta */
4841         {
4842           if (left_is_none && !fnKeysym)
4843             {   /* accept pre-interp alt comb */
4844               if ([[theEvent characters] length] > 0)
4845                 code = [[theEvent characters] characterAtIndex: 0];
4846               /*HACK: clear lone shift modifier to stop next if from firing */
4847               if (emacs_event->modifiers == shift_modifier)
4848                 emacs_event->modifiers = 0;
4849             }
4850           else
4851               emacs_event->modifiers |=
4852                 parse_solitary_modifier (ns_alternate_modifier);
4853         }
4855   if (NS_KEYLOG)
4856     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
4857              code, fnKeysym, flags, emacs_event->modifiers);
4859       /* if it was a function key or had modifiers, pass it directly to emacs */
4860       if (fnKeysym || (emacs_event->modifiers
4861                        && (emacs_event->modifiers != shift_modifier)
4862                        && [[theEvent charactersIgnoringModifiers] length] > 0))
4863 /*[[theEvent characters] length] */
4864         {
4865           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4866           if (code < 0x20)
4867             code |= (1<<28)|(3<<16);
4868           else if (code == 0x7f)
4869             code |= (1<<28)|(3<<16);
4870           else if (!fnKeysym)
4871             emacs_event->kind = code > 0xFF
4872               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4874           emacs_event->code = code;
4875           EV_TRAILER (theEvent);
4876           return;
4877         }
4878     }
4881 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4882   /* if we get here we should send the key for input manager processing */
4883   if (firstTime && [[NSInputManager currentInputManager]
4884                      wantsToDelayTextChangeNotifications] == NO)
4885     fprintf (stderr,
4886           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
4887   firstTime = NO;
4888 #endif
4889   if (NS_KEYLOG && !processingCompose)
4890     fprintf (stderr, "keyDown: Begin compose sequence.\n");
4892   processingCompose = YES;
4893   [nsEvArray addObject: theEvent];
4894   [self interpretKeyEvents: nsEvArray];
4895   [nsEvArray removeObject: theEvent];
4899 #ifdef NS_IMPL_COCOA
4900 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
4901    decided not to send key-down for.
4902    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
4903    This only applies on Tiger and earlier.
4904    If it matches one of these, send it on to keyDown. */
4905 -(void)keyUp: (NSEvent *)theEvent
4907   int flags = [theEvent modifierFlags];
4908   int code = [theEvent keyCode];
4909   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
4910       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
4911     {
4912       if (NS_KEYLOG)
4913         fprintf (stderr, "keyUp: passed test");
4914       ns_fake_keydown = YES;
4915       [self keyDown: theEvent];
4916     }
4918 #endif
4921 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
4924 /* <NSTextInput>: called when done composing;
4925    NOTE: also called when we delete over working text, followed immed.
4926          by doCommandBySelector: deleteBackward: */
4927 - (void)insertText: (id)aString
4929   int code;
4930   int len = [(NSString *)aString length];
4931   int i;
4933   if (NS_KEYLOG)
4934     NSLog (@"insertText '%@'\tlen = %d", aString, len);
4935   processingCompose = NO;
4937   if (!emacs_event)
4938     return;
4940   /* first, clear any working text */
4941   if (workingText != nil)
4942     [self deleteWorkingText];
4944   /* now insert the string as keystrokes */
4945   for (i =0; i<len; i++)
4946     {
4947       code = [aString characterAtIndex: i];
4948       /* TODO: still need this? */
4949       if (code == 0x2DC)
4950         code = '~'; /* 0x7E */
4951       emacs_event->modifiers = 0;
4952       emacs_event->kind
4953         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4954       emacs_event->code = code;
4955       EV_TRAILER ((id)nil);
4956     }
4960 /* <NSTextInput>: inserts display of composing characters */
4961 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
4963   NSString *str = [aString respondsToSelector: @selector (string)] ?
4964     [aString string] : aString;
4965   if (NS_KEYLOG)
4966     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
4967            selRange.length, selRange.location);
4969   if (workingText != nil)
4970     [self deleteWorkingText];
4971   if ([str length] == 0)
4972     return;
4974   if (!emacs_event)
4975     return;
4977   processingCompose = YES;
4978   workingText = [str copy];
4979   ns_working_text = build_string ([workingText UTF8String]);
4981   emacs_event->kind = NS_TEXT_EVENT;
4982   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
4983   EV_TRAILER ((id)nil);
4987 /* delete display of composing characters [not in <NSTextInput>] */
4988 - (void)deleteWorkingText
4990   if (workingText == nil)
4991     return;
4992   if (NS_KEYLOG)
4993     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
4994   [workingText release];
4995   workingText = nil;
4996   processingCompose = NO;
4998   if (!emacs_event)
4999     return;
5001   emacs_event->kind = NS_TEXT_EVENT;
5002   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5003   EV_TRAILER ((id)nil);
5007 - (BOOL)hasMarkedText
5009   return workingText != nil;
5013 - (NSRange)markedRange
5015   NSRange rng = workingText != nil
5016     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5017   if (NS_KEYLOG)
5018     NSLog (@"markedRange request");
5019   return rng;
5023 - (void)unmarkText
5025   if (NS_KEYLOG)
5026     NSLog (@"unmark (accept) text");
5027   [self deleteWorkingText];
5028   processingCompose = NO;
5032 /* used to position char selection windows, etc. */
5033 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5035   NSRect rect;
5036   NSPoint pt;
5037   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5038   if (NS_KEYLOG)
5039     NSLog (@"firstRectForCharRange request");
5041   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5042   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5043   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5044   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5045                                        +FRAME_LINE_HEIGHT (emacsframe));
5047   pt = [self convertPoint: pt toView: nil];
5048   pt = [[self window] convertBaseToScreen: pt];
5049   rect.origin = pt;
5050   return rect;
5054 - (long)conversationIdentifier
5056   return (long)self;
5060 - (void)doCommandBySelector: (SEL)aSelector
5062   if (NS_KEYLOG)
5063     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5065   if (aSelector == @selector (deleteBackward:))
5066     {
5067       /* happens when user backspaces over an ongoing composition:
5068          throw a 'delete' into the event queue */
5069       if (!emacs_event)
5070         return;
5071       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5072       emacs_event->code = 0xFF08;
5073       EV_TRAILER ((id)nil);
5074     }
5077 - (NSArray *)validAttributesForMarkedText
5079   static NSArray *arr = nil;
5080   if (arr == nil) arr = [NSArray new];
5081  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5082   return arr;
5085 - (NSRange)selectedRange
5087   if (NS_KEYLOG)
5088     NSLog (@"selectedRange request");
5089   return NSMakeRange (NSNotFound, 0);
5092 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5094   if (NS_KEYLOG)
5095     NSLog (@"characterIndexForPoint request");
5096   return 0;
5099 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5101   static NSAttributedString *str = nil;
5102   if (str == nil) str = [NSAttributedString new];
5103   if (NS_KEYLOG)
5104     NSLog (@"attributedSubstringFromRange request");
5105   return str;
5108 /* End <NSTextInput> impl. */
5109 /*****************************************************************************/
5112 /* This is what happens when the user presses a mouse button.  */
5113 - (void)mouseDown: (NSEvent *)theEvent
5115   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5116   Lisp_Object window;
5118   NSTRACE (mouseDown);
5120   [self deleteWorkingText];
5122   if (!emacs_event)
5123     return;
5125   last_mouse_frame = emacsframe;
5126   /* appears to be needed to prevent spurious movement events generated on
5127      button clicks */
5128   last_mouse_frame->mouse_moved = 0;
5130   if ([theEvent type] == NSScrollWheel)
5131     {
5132       float delta = [theEvent deltaY];
5133       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5134       if (delta == 0)
5135         return;
5136       emacs_event->kind = WHEEL_EVENT;
5137       emacs_event->code = 0;
5138       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5139         ((delta > 0) ? up_modifier : down_modifier);
5140     }
5141   else
5142     {
5143       emacs_event->kind = MOUSE_CLICK_EVENT;
5144       emacs_event->code = EV_BUTTON (theEvent);
5145       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5146                              | EV_UDMODIFIERS (theEvent);
5147     }
5148   XSETINT (emacs_event->x, lrint (p.x));
5149   XSETINT (emacs_event->y, lrint (p.y));
5150   EV_TRAILER (theEvent);
5154 - (void)rightMouseDown: (NSEvent *)theEvent
5156   NSTRACE (rightMouseDown);
5157   [self mouseDown: theEvent];
5161 - (void)otherMouseDown: (NSEvent *)theEvent
5163   NSTRACE (otherMouseDown);
5164   [self mouseDown: theEvent];
5168 - (void)mouseUp: (NSEvent *)theEvent
5170   NSTRACE (mouseUp);
5171   [self mouseDown: theEvent];
5175 - (void)rightMouseUp: (NSEvent *)theEvent
5177   NSTRACE (rightMouseUp);
5178   [self mouseDown: theEvent];
5182 - (void)otherMouseUp: (NSEvent *)theEvent
5184   NSTRACE (otherMouseUp);
5185   [self mouseDown: theEvent];
5189 - (void) scrollWheel: (NSEvent *)theEvent
5191   NSTRACE (scrollWheel);
5192   [self mouseDown: theEvent];
5196 /* Tell emacs the mouse has moved. */
5197 - (void)mouseMoved: (NSEvent *)e
5199   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5200   Lisp_Object frame;
5202 //  NSTRACE (mouseMoved);
5204   last_mouse_movement_time = EV_TIMESTAMP (e);
5205   last_mouse_motion_position
5206     = [self convertPoint: [e locationInWindow] fromView: nil];
5208   /* update any mouse face */
5209   if (hlinfo->mouse_face_hidden)
5210     {
5211       hlinfo->mouse_face_hidden = 0;
5212       clear_mouse_face (hlinfo);
5213     }
5215   /* tooltip handling */
5216   previous_help_echo_string = help_echo_string;
5217   help_echo_string = Qnil;
5219   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
5220                             last_mouse_motion_position.y))
5221     help_echo_string = previous_help_echo_string;
5223   XSETFRAME (frame, emacsframe);
5224   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5225     {
5226       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5227          (note_mouse_highlight), which is called through the
5228          note_mouse_movement () call above */
5229       gen_help_event (help_echo_string, frame, help_echo_window,
5230                       help_echo_object, help_echo_pos);
5231     }
5232   else
5233     {
5234       help_echo_string = Qnil;
5235       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5236     }
5238   if (emacsframe->mouse_moved && send_appdefined)
5239     ns_send_appdefined (-1);
5243 - (void)mouseDragged: (NSEvent *)e
5245   NSTRACE (mouseDragged);
5246   [self mouseMoved: e];
5250 - (void)rightMouseDragged: (NSEvent *)e
5252   NSTRACE (rightMouseDragged);
5253   [self mouseMoved: e];
5257 - (void)otherMouseDragged: (NSEvent *)e
5259   NSTRACE (otherMouseDragged);
5260   [self mouseMoved: e];
5264 - (BOOL)windowShouldClose: (id)sender
5266   NSEvent *e =[[self window] currentEvent];
5268   NSTRACE (windowShouldClose);
5269   windowClosing = YES;
5270   if (!emacs_event)
5271     return NO;
5272   emacs_event->kind = DELETE_WINDOW_EVENT;
5273   emacs_event->modifiers = 0;
5274   emacs_event->code = 0;
5275   EV_TRAILER (e);
5276   /* Don't close this window, let this be done from lisp code.  */
5277   return NO;
5281 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5282 /* normalize frame to gridded text size */
5284   NSTRACE (windowWillResize);
5285 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5287   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5288 #ifdef NS_IMPL_GNUSTEP
5289                                         frameSize.width + 3);
5290 #else
5291                                         frameSize.width);
5292 #endif
5293   if (cols < MINWIDTH)
5294     cols = MINWIDTH;
5296   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, frameSize.height
5297 #ifdef NS_IMPL_GNUSTEP
5298       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + 3
5299         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5300 #else
5301       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5302         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5303 #endif
5304   if (rows < MINHEIGHT)
5305     rows = MINHEIGHT;
5306 #ifdef NS_IMPL_COCOA
5307   {
5308     /* this sets window title to have size in it; the wm does this under GS */
5309     NSRect r = [[self window] frame];
5310     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5311       {
5312         if (old_title != 0)
5313           {
5314             xfree (old_title);
5315             old_title = 0;
5316           }
5317       }
5318     else
5319       {
5320         char *size_title;
5321         NSWindow *window = [self window];
5322         if (old_title == 0)
5323           {
5324             const char *t = [[[self window] title] UTF8String];
5325             char *pos = strstr (t, "  â€”  ");
5326             if (pos)
5327               *pos = '\0';
5328             old_title = (char *) xmalloc (strlen (t) + 1);
5329             strcpy (old_title, t);
5330           }
5331         size_title = xmalloc (strlen (old_title) + 40);
5332         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5333         [window setTitle: [NSString stringWithUTF8String: size_title]];
5334         [window display];
5335         xfree (size_title);
5336       }
5337   }
5338 #endif /* NS_IMPL_COCOA */
5339 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5341   return frameSize;
5345 - (void)windowDidResize: (NSNotification *)notification
5347   NSWindow *theWindow = [notification object];
5349 #ifdef NS_IMPL_GNUSTEP
5350    /* in GNUstep, at least currently, it's possible to get a didResize
5351       without getting a willResize.. therefore we need to act as if we got
5352       the willResize now */
5353   NSSize sz = [theWindow frame].size;
5354   sz = [self windowWillResize: theWindow toSize: sz];
5355 #endif /* NS_IMPL_GNUSTEP */
5357   NSTRACE (windowDidResize);
5358 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5360 #ifdef NS_IMPL_COCOA
5361   if (old_title != 0)
5362     {
5363       xfree (old_title);
5364       old_title = 0;
5365     }
5366 #endif /* NS_IMPL_COCOA */
5368   /* Avoid loop under GNUstep due to call at beginning of this function.
5369      (x_set_window_size causes a resize which causes
5370      a "windowDidResize" which calls x_set_window_size).  */
5371 #ifndef NS_IMPL_GNUSTEP
5372   if (cols > 0 && rows > 0)
5373     {
5374       if (ns_in_resize)
5375         x_set_window_size (emacsframe, 0, cols, rows);
5376       else
5377         {
5378           NSWindow *window = [self window];
5379           NSRect wr = [window frame];
5380           FRAME_PIXEL_WIDTH (emacsframe) = (int)wr.size.width
5381             - emacsframe->border_width;
5382           FRAME_PIXEL_HEIGHT (emacsframe) = (int)wr.size.height
5383             - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5384             - FRAME_TOOLBAR_HEIGHT (emacsframe);
5385           change_frame_size (emacsframe, rows, cols, 0, 0, 1);
5386           SET_FRAME_GARBAGED (emacsframe);
5387           cancel_mouse_face (emacsframe);
5388         }
5389     }
5390 #endif
5392   ns_send_appdefined (-1);
5396 - (void)windowDidBecomeKey: (NSNotification *)notification
5397 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5399   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5400   struct frame *old_focus = dpyinfo->x_focus_frame;
5402   NSTRACE (windowDidBecomeKey);
5404   if (emacsframe != old_focus)
5405     dpyinfo->x_focus_frame = emacsframe;
5407   ns_frame_rehighlight (emacsframe);
5409   if (emacs_event)
5410     {
5411       emacs_event->kind = FOCUS_IN_EVENT;
5412       EV_TRAILER ((id)nil);
5413     }
5417 - (void)windowDidResignKey: (NSNotification *)notification
5418 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5420   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5421   NSTRACE (windowDidResignKey);
5423   if (dpyinfo->x_focus_frame == emacsframe)
5424     dpyinfo->x_focus_frame = 0;
5426   ns_frame_rehighlight (emacsframe);
5428   /* FIXME: for some reason needed on second and subsequent clicks away
5429             from sole-frame Emacs to get hollow box to show */
5430   if (!windowClosing && [[self window] isVisible] == YES)
5431     {
5432       x_update_cursor (emacsframe, 1);
5433       x_set_frame_alpha (emacsframe);
5434     }
5436   if (emacs_event)
5437     {
5438       [self deleteWorkingText];
5439       emacs_event->kind = FOCUS_IN_EVENT;
5440       EV_TRAILER ((id)nil);
5441     }
5445 - (void)windowWillMiniaturize: sender
5447   NSTRACE (windowWillMiniaturize);
5451 - (BOOL)isFlipped
5453   return YES;
5457 - (BOOL)isOpaque
5459   return NO;
5463 - initFrameFromEmacs: (struct frame *)f
5465   NSRect r, wr;
5466   Lisp_Object tem;
5467   NSWindow *win;
5468   NSButton *toggleButton;
5469   int vbextra = NS_SCROLL_BAR_WIDTH (f);
5470   NSSize sz;
5471   NSColor *col;
5472   NSString *name;
5474   NSTRACE (initFrameFromEmacs);
5476   windowClosing = NO;
5477   processingCompose = NO;
5478   scrollbarsNeedingUpdate = 0;
5480 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5482   ns_userRect = NSMakeRect (0, 0, 0, 0);
5483   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5484                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5485   [self initWithFrame: r];
5486   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5488   FRAME_NS_VIEW (f) = self;
5489   emacsframe = f;
5490   old_title = 0;
5492   win = [[EmacsWindow alloc]
5493             initWithContentRect: r
5494                       styleMask: (NSResizableWindowMask |
5495 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5496                                   NSTitledWindowMask |
5497 #endif
5498                                   NSMiniaturizableWindowMask |
5499                                   NSClosableWindowMask)
5500                         backing: NSBackingStoreBuffered
5501                           defer: YES];
5503   wr = [win frame];
5504   f->border_width = wr.size.width - r.size.width;
5505   FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5507   [win setAcceptsMouseMovedEvents: YES];
5508   [win setDelegate: self];
5509   [win useOptimizedDrawing: YES];
5511   sz.width = FRAME_COLUMN_WIDTH (f);
5512   sz.height = FRAME_LINE_HEIGHT (f);
5513   [win setResizeIncrements: sz];
5515   [[win contentView] addSubview: self];
5517   if (ns_drag_types)
5518     [self registerForDraggedTypes: ns_drag_types];
5520   tem = f->name;
5521   name = [NSString stringWithUTF8String:
5522                    NILP (tem) ? (unsigned char *)"Emacs" : SDATA (tem)];
5523   [win setTitle: name];
5525   /* toolbar support */
5526   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5527                          [NSString stringWithFormat: @"Emacs Frame %d",
5528                                    ns_window_num]];
5529   [win setToolbar: toolbar];
5530   [toolbar setVisible: NO];
5531 #ifdef NS_IMPL_COCOA
5532   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5533   [toggleButton setTarget: self];
5534   [toggleButton setAction: @selector (toggleToolbar: )];
5535 #endif
5536   FRAME_TOOLBAR_HEIGHT (f) = 0;
5538   tem = f->icon_name;
5539   if (!NILP (tem))
5540     [win setMiniwindowTitle:
5541            [NSString stringWithUTF8String: SDATA (tem)]];
5543   {
5544     NSScreen *screen = [win screen];
5546     if (screen != 0)
5547       [win setFrameTopLeftPoint: NSMakePoint
5548            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5549             IN_BOUND (-SCREENMAX,
5550                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5551   }
5553   [win makeFirstResponder: self];
5555   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5556                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5557   [win setBackgroundColor: col];
5558   if ([col alphaComponent] != 1.0)
5559     [win setOpaque: NO];
5561   [self allocateGState];
5563   [NSApp registerServicesMenuSendTypes: ns_send_types
5564                            returnTypes: nil];
5566   ns_window_num++;
5567   return self;
5571 - (void)windowDidMove: sender
5573   NSWindow *win = [self window];
5574   NSRect r = [win frame];
5575   NSArray *screens = [NSScreen screens];
5576   NSScreen *screen = [screens objectAtIndex: 0];
5578   NSTRACE (windowDidMove);
5580   if (!emacsframe->output_data.ns)
5581     return;
5582   if (screen != nil)
5583     {
5584       emacsframe->left_pos = r.origin.x;
5585       emacsframe->top_pos =
5586         [screen frame].size.height - (r.origin.y + r.size.height);
5587     }
5591 /* Called AFTER method below, but before our windowWillResize call there leads
5592    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5593    location so set_window_size moves the frame. */
5594 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5596   emacsframe->output_data.ns->zooming = 1;
5597   return YES;
5601 /* Override to do something slightly nonstandard, but nice.  First click on
5602    zoom button will zoom vertically.  Second will zoom completely.  Third
5603    returns to original. */
5604 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5605                         defaultFrame:(NSRect)defaultFrame
5607   NSRect result = [sender frame];
5609   NSTRACE (windowWillUseStandardFrame);
5611   if (abs (defaultFrame.size.height - result.size.height)
5612       > FRAME_LINE_HEIGHT (emacsframe))
5613     {
5614       /* first click */
5615       ns_userRect = result;
5616       result.size.height = defaultFrame.size.height;
5617       result.origin.y = defaultFrame.origin.y;
5618     }
5619   else
5620     {
5621       if (abs (defaultFrame.size.width - result.size.width)
5622           > FRAME_COLUMN_WIDTH (emacsframe))
5623         result = defaultFrame;  /* second click */
5624       else
5625         {
5626           /* restore */
5627           result = ns_userRect.size.height ? ns_userRect : result;
5628           ns_userRect = NSMakeRect (0, 0, 0, 0);
5629         }
5630     }
5632   [self windowWillResize: sender toSize: result.size];
5633   return result;
5637 - (void)windowDidDeminiaturize: sender
5639   NSTRACE (windowDidDeminiaturize);
5640   if (!emacsframe->output_data.ns)
5641     return;
5642   emacsframe->async_iconified = 0;
5643   emacsframe->async_visible   = 1;
5644   windows_or_buffers_changed++;
5646   if (emacs_event)
5647     {
5648       emacs_event->kind = ICONIFY_EVENT;
5649       EV_TRAILER ((id)nil);
5650     }
5654 - (void)windowDidExpose: sender
5656   NSTRACE (windowDidExpose);
5657   if (!emacsframe->output_data.ns)
5658     return;
5659   emacsframe->async_visible = 1;
5660   SET_FRAME_GARBAGED (emacsframe);
5662   if (send_appdefined)
5663     ns_send_appdefined (-1);
5667 - (void)windowDidMiniaturize: sender
5669   NSTRACE (windowDidMiniaturize);
5670   if (!emacsframe->output_data.ns)
5671     return;
5673   emacsframe->async_iconified = 1;
5674   emacsframe->async_visible = 0;
5676   if (emacs_event)
5677     {
5678       emacs_event->kind = ICONIFY_EVENT;
5679       EV_TRAILER ((id)nil);
5680     }
5684 - (void)mouseEntered: (NSEvent *)theEvent
5686   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5687   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5688   NSTRACE (mouseEntered);
5690   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5694 - (void)mouseExited: (NSEvent *)theEvent
5696   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5697   NSRect r;
5698   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
5700   NSTRACE (mouseExited);
5702   if (!hlinfo)
5703     return;
5705   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5707   if (emacsframe == hlinfo->mouse_face_mouse_frame)
5708     {
5709       clear_mouse_face (hlinfo);
5710       hlinfo->mouse_face_mouse_frame = 0;
5711     }
5715 - menuDown: sender
5717   NSTRACE (menuDown);
5718   if (context_menu_value == -1)
5719     context_menu_value = [sender tag];
5720   else
5721     find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
5722                                   emacsframe->menu_bar_vector,
5723                                   (void *)[sender tag]);
5724   ns_send_appdefined (-1);
5725   return self;
5729 - (EmacsToolbar *)toolbar
5731   return toolbar;
5735 /* this gets called on toolbar button click */
5736 - toolbarClicked: (id)item
5738   NSEvent *theEvent;
5739   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
5741   NSTRACE (toolbarClicked);
5743   if (!emacs_event)
5744     return self;
5746   /* send first event (for some reason two needed) */
5747   theEvent = [[self window] currentEvent];
5748   emacs_event->kind = TOOL_BAR_EVENT;
5749   XSETFRAME (emacs_event->arg, emacsframe);
5750   EV_TRAILER (theEvent);
5752   emacs_event->kind = TOOL_BAR_EVENT;
5753 /*   XSETINT (emacs_event->code, 0); */
5754   emacs_event->arg = AREF (emacsframe->tool_bar_items,
5755                           idx + TOOL_BAR_ITEM_KEY);
5756   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5757   EV_TRAILER (theEvent);
5758   return self;
5762 - toggleToolbar: (id)sender
5764   if (!emacs_event)
5765     return self;
5767   emacs_event->kind = NS_NONKEY_EVENT;
5768   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
5769   EV_TRAILER ((id)nil);
5770   return self;
5774 - (void)drawRect: (NSRect)rect
5776   int x = NSMinX (rect), y = NSMinY (rect);
5777   int width = NSWidth (rect), height = NSHeight (rect);
5779   NSTRACE (drawRect);
5781   if (!emacsframe || !emacsframe->output_data.ns || ns_in_resize)
5782     return;
5784   ns_clear_frame_area (emacsframe, x, y, width, height);
5785   expose_frame (emacsframe, x, y, width, height);
5787   /*
5788     drawRect: may be called (at least in OS X 10.5) for invisible
5789     views as well for some reason.  Thus, do not infer visibility
5790     here.
5792     emacsframe->async_visible = 1;
5793     emacsframe->async_iconified = 0;
5794   */
5798 /* NSDraggingDestination protocol methods.  Actually this is not really a
5799    protocol, but a category of Object.  O well...  */
5801 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
5803   NSTRACE (draggingEntered);
5804   return NSDragOperationGeneric;
5808 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
5810   return YES;
5814 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
5816   id pb;
5817   int x, y;
5818   NSString *type;
5819   NSEvent *theEvent = [[self window] currentEvent];
5820   NSPoint position;
5822   NSTRACE (performDragOperation);
5824   if (!emacs_event)
5825     return NO;
5827   position = [self convertPoint: [sender draggingLocation] fromView: nil];
5828   x = lrint (position.x);  y = lrint (position.y);
5830   pb = [sender draggingPasteboard];
5831   type = [pb availableTypeFromArray: ns_drag_types];
5832   if (type == 0)
5833     {
5834       return NO;
5835     }
5836   else if ([type isEqualToString: NSFilenamesPboardType])
5837     {
5838       NSArray *files;
5839       NSEnumerator *fenum;
5840       NSString *file;
5842       if (!(files = [pb propertyListForType: type]))
5843         return NO;
5845       fenum = [files objectEnumerator];
5846       while ( (file = [fenum nextObject]) )
5847         {
5848           emacs_event->kind = NS_NONKEY_EVENT;
5849           emacs_event->code = KEY_NS_DRAG_FILE;
5850           XSETINT (emacs_event->x, x);
5851           XSETINT (emacs_event->y, y);
5852           ns_input_file = append2 (ns_input_file,
5853                                    build_string ([file UTF8String]));
5854           emacs_event->modifiers = EV_MODIFIERS (theEvent);
5855           EV_TRAILER (theEvent);
5856         }
5857       return YES;
5858     }
5859   else if ([type isEqualToString: NSURLPboardType])
5860     {
5861       NSString *file;
5862       NSURL *fileURL;
5864       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
5865           [fileURL isFileURL] == NO)
5866         return NO;
5868       file = [fileURL path];
5869       emacs_event->kind = NS_NONKEY_EVENT;
5870       emacs_event->code = KEY_NS_DRAG_FILE;
5871       XSETINT (emacs_event->x, x);
5872       XSETINT (emacs_event->y, y);
5873       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
5874       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5875       EV_TRAILER (theEvent);
5876       return YES;
5877     }
5878   else if ([type isEqualToString: NSStringPboardType]
5879            || [type isEqualToString: NSTabularTextPboardType])
5880     {
5881       NSString *data;
5883       if (! (data = [pb stringForType: type]))
5884         return NO;
5886       emacs_event->kind = NS_NONKEY_EVENT;
5887       emacs_event->code = KEY_NS_DRAG_TEXT;
5888       XSETINT (emacs_event->x, x);
5889       XSETINT (emacs_event->y, y);
5890       ns_input_text = build_string ([data UTF8String]);
5891       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5892       EV_TRAILER (theEvent);
5893       return YES;
5894     }
5895   else if ([type isEqualToString: NSColorPboardType])
5896     {
5897       NSColor *c = [NSColor colorFromPasteboard: pb];
5898       emacs_event->kind = NS_NONKEY_EVENT;
5899       emacs_event->code = KEY_NS_DRAG_COLOR;
5900       XSETINT (emacs_event->x, x);
5901       XSETINT (emacs_event->y, y);
5902       ns_input_color = ns_color_to_lisp (c);
5903       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5904       EV_TRAILER (theEvent);
5905       return YES;
5906     }
5907   else if ([type isEqualToString: NSFontPboardType])
5908     {
5909       /* impl based on GNUstep NSTextView.m */
5910       NSData *data = [pb dataForType: NSFontPboardType];
5911       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
5912       NSFont *font = [dict objectForKey: NSFontAttributeName];
5913       char fontSize[10];
5915       if (font == nil)
5916         return NO;
5918       emacs_event->kind = NS_NONKEY_EVENT;
5919       emacs_event->code = KEY_NS_CHANGE_FONT;
5920       XSETINT (emacs_event->x, x);
5921       XSETINT (emacs_event->y, y);
5922       ns_input_font = build_string ([[font fontName] UTF8String]);
5923       snprintf (fontSize, 10, "%f", [font pointSize]);
5924       ns_input_fontsize = build_string (fontSize);
5925       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5926       EV_TRAILER (theEvent);
5927       return YES;
5928     }
5929   else
5930     {
5931       error ("Invalid data type in dragging pasteboard.");
5932       return NO;
5933     }
5937 - (id) validRequestorForSendType: (NSString *)typeSent
5938                       returnType: (NSString *)typeReturned
5940   NSTRACE (validRequestorForSendType);
5941   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
5942       && typeReturned == nil)
5943     {
5944       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
5945         return self;
5946     }
5948   return [super validRequestorForSendType: typeSent
5949                                returnType: typeReturned];
5953 /* The next two methods are part of NSServicesRequests informal protocol,
5954    supposedly called when a services menu item is chosen from this app.
5955    But this should not happen because we override the services menu with our
5956    own entries which call ns-perform-service.
5957    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
5958    So let's at least stub them out until further investigation can be done. */
5960 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
5962   /* we could call ns_string_from_pasteboard(pboard) here but then it should
5963      be written into the buffer in place of the existing selection..
5964      ordinary service calls go through functions defined in ns-win.el */
5965   return NO;
5968 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
5970   NSArray *typesDeclared;
5971   Lisp_Object val;
5973   /* We only support NSStringPboardType */
5974   if ([types containsObject:NSStringPboardType] == NO) {
5975     return NO;
5976   }
5978   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
5979   if (CONSP (val) && SYMBOLP (XCAR (val)))
5980     {
5981       val = XCDR (val);
5982       if (CONSP (val) && NILP (XCDR (val)))
5983         val = XCAR (val);
5984     }
5985   if (! STRINGP (val))
5986     return NO;
5988   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
5989   [pb declareTypes:typesDeclared owner:nil];
5990   ns_string_to_pasteboard (pb, val);
5991   return YES;
5995 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
5996    (gives a miniaturized version of the window); currently we use the latter for
5997    frames whose active buffer doesn't correspond to any file
5998    (e.g., '*scratch*') */
5999 - setMiniwindowImage: (BOOL) setMini
6001   id image = [[self window] miniwindowImage];
6002   NSTRACE (setMiniwindowImage);
6004   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6005      about "AppleDockIconEnabled" notwithstanding, however the set message
6006      below has its effect nonetheless. */
6007   if (image != emacsframe->output_data.ns->miniimage)
6008     {
6009       if (image && [image isKindOfClass: [EmacsImage class]])
6010         [image release];
6011       [[self window] setMiniwindowImage:
6012                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6013     }
6015   return self;
6019 - (void) setRows: (int) r andColumns: (int) c
6021   rows = r;
6022   cols = c;
6025 @end  /* EmacsView */
6029 /* ==========================================================================
6031     EmacsWindow implementation
6033    ========================================================================== */
6035 @implementation EmacsWindow
6037 /* If we have multiple monitors, one above the other, we don't want to
6038    restrict the height to just one monitor.  So we override this.  */
6039 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6041   /* When making the frame visible for the first time or if there is just
6042      one screen, we want to constrain.  Other times not.  */
6043   NSUInteger nr_screens = [[NSScreen screens] count];
6044   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6045   NSTRACE (constrainFrameRect);
6047   if (nr_screens == 1)
6048     return [super constrainFrameRect:frameRect toScreen:screen];
6049   
6050   if (f->output_data.ns->dont_constrain
6051       || ns_menu_bar_should_be_hidden ())
6052     return frameRect;
6054   f->output_data.ns->dont_constrain = 1;
6055   return [super constrainFrameRect:frameRect toScreen:screen];
6059 /* called only on resize clicks by special case in EmacsApp-sendEvent */
6060 - (void)mouseDown: (NSEvent *)theEvent
6062   if (ns_in_resize)
6063     {
6064       NSSize size = [[theEvent window] frame].size;
6065       grabOffset = [theEvent locationInWindow];
6066       grabOffset.x = size.width - grabOffset.x;
6067     }
6068   else
6069     [super mouseDown: theEvent];
6073 /* stop resizing */
6074 - (void)mouseUp: (NSEvent *)theEvent
6076   if (ns_in_resize)
6077     {
6078       struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6079       ns_in_resize = NO;
6080       ns_set_name_as_filename (f);
6081       [self display];
6082       ns_send_appdefined (-1);
6083     }
6084   else
6085     [super mouseUp: theEvent];
6089 /* send resize events */
6090 - (void)mouseDragged: (NSEvent *)theEvent
6092   if (ns_in_resize)
6093     {
6094       NSPoint p = [theEvent locationInWindow];
6095       NSSize size, vettedSize, origSize = [self frame].size;
6097       size.width = p.x + grabOffset.x;
6098       size.height = origSize.height - p.y + grabOffset.y;
6100       if (size.width == origSize.width && size.height == origSize.height)
6101         return;
6103       vettedSize = [[self delegate] windowWillResize: self toSize: size];
6104       [[NSNotificationCenter defaultCenter]
6105             postNotificationName: NSWindowDidResizeNotification
6106                           object: self];
6107     }
6108   else
6109     [super mouseDragged: theEvent];
6112 @end /* EmacsWindow */
6115 /* ==========================================================================
6117     EmacsScroller implementation
6119    ========================================================================== */
6122 @implementation EmacsScroller
6124 /* for repeat button push */
6125 #define SCROLL_BAR_FIRST_DELAY 0.5
6126 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6128 + (CGFloat) scrollerWidth
6130   /* TODO: if we want to allow variable widths, this is the place to do it,
6131            however neither GNUstep nor Cocoa support it very well */
6132   return [NSScroller scrollerWidth];
6136 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6138   NSTRACE (EmacsScroller_initFrame);
6140   r.size.width = [EmacsScroller scrollerWidth];
6141   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6142   [self setContinuous: YES];
6143   [self setEnabled: YES];
6145   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6146      locked against the top and bottom edges, and right edge on OS X, where
6147      scrollers are on right. */
6148 #ifdef NS_IMPL_GNUSTEP
6149   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6150 #else
6151   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6152 #endif
6154   win = nwin;
6155   condemned = NO;
6156   pixel_height = NSHeight (r);
6157   if (pixel_height == 0) pixel_height = 1;
6158   min_portion = 20 / pixel_height;
6160   frame = XFRAME (XWINDOW (win)->frame);
6161   if (FRAME_LIVE_P (frame))
6162     {
6163       int i;
6164       EmacsView *view = FRAME_NS_VIEW (frame);
6165       NSView *sview = [[view window] contentView];
6166       NSArray *subs = [sview subviews];
6168       /* disable optimization stopping redraw of other scrollbars */
6169       view->scrollbarsNeedingUpdate = 0;
6170       for (i =[subs count]-1; i >= 0; i--)
6171         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6172           view->scrollbarsNeedingUpdate++;
6173       [sview addSubview: self];
6174     }
6176 /*  [self setFrame: r]; */
6178   return self;
6182 - (void)setFrame: (NSRect)newRect
6184   NSTRACE (EmacsScroller_setFrame);
6185 /*  BLOCK_INPUT; */
6186   pixel_height = NSHeight (newRect);
6187   if (pixel_height == 0) pixel_height = 1;
6188   min_portion = 20 / pixel_height;
6189   [super setFrame: newRect];
6190   [self display];
6191 /*  UNBLOCK_INPUT; */
6195 - (void)dealloc
6197   NSTRACE (EmacsScroller_dealloc);
6198   if (!NILP (win))
6199     XWINDOW (win)->vertical_scroll_bar = Qnil;
6200   [super dealloc];
6204 - condemn
6206   NSTRACE (condemn);
6207   condemned =YES;
6208   return self;
6212 - reprieve
6214   NSTRACE (reprieve);
6215   condemned =NO;
6216   return self;
6220 - judge
6222   NSTRACE (judge);
6223   if (condemned)
6224     {
6225       EmacsView *view;
6226       BLOCK_INPUT;
6227       /* ensure other scrollbar updates after deletion */
6228       view = (EmacsView *)FRAME_NS_VIEW (frame);
6229       if (view != nil)
6230         view->scrollbarsNeedingUpdate++;
6231       [self removeFromSuperview];
6232       [self release];
6233       UNBLOCK_INPUT;
6234     }
6235   return self;
6239 - (void)resetCursorRects
6241   NSRect visible = [self visibleRect];
6242   NSTRACE (resetCursorRects);
6244   if (!NSIsEmptyRect (visible))
6245     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6246   [[NSCursor arrowCursor] setOnMouseEntered: YES];
6250 - (int) checkSamePosition: (int) position portion: (int) portion
6251                     whole: (int) whole
6253   return em_position ==position && em_portion ==portion && em_whole ==whole
6254     && portion != whole; /* needed for resize empty buf */
6258 - setPosition: (int)position portion: (int)portion whole: (int)whole
6260   NSTRACE (setPosition);
6262   em_position = position;
6263   em_portion = portion;
6264   em_whole = whole;
6266   if (portion >= whole)
6267     {
6268 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6269       [self setKnobProportion: 1.0];
6270       [self setDoubleValue: 1.0];
6271 #else
6272       [self setFloatValue: 0.0 knobProportion: 1.0];
6273 #endif
6274     }
6275   else
6276     {
6277       float pos, por;
6278       portion = max ((float)whole*min_portion/pixel_height, portion);
6279       pos = (float)position / (whole - portion);
6280       por = (float)portion/whole;
6281 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6282       [self setKnobProportion: por];
6283       [self setDoubleValue: pos];
6284 #else
6285       [self setFloatValue: pos knobProportion: por];
6286 #endif
6287     }
6288   return self;
6291 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6292      drag events will go directly to the EmacsScroller.  Leaving in for now. */
6293 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6294                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
6296   *part = last_hit_part;
6297   *window = win;
6298   XSETINT (*y, pixel_height);
6299   if ([self floatValue] > 0.999)
6300     XSETINT (*x, pixel_height);
6301   else
6302     XSETINT (*x, pixel_height * [self floatValue]);
6306 /* set up emacs_event */
6307 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6309   if (!emacs_event)
6310     return;
6312   emacs_event->part = last_hit_part;
6313   emacs_event->code = 0;
6314   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
6315   emacs_event->frame_or_window = win;
6316   emacs_event->timestamp = EV_TIMESTAMP (e);
6317   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
6318   emacs_event->arg = Qnil;
6319   XSETINT (emacs_event->x, loc * pixel_height);
6320   XSETINT (emacs_event->y, pixel_height-20);
6322   n_emacs_events_pending++;
6323   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
6324   EVENT_INIT (*emacs_event);
6325   ns_send_appdefined (-1);
6329 /* called manually thru timer to implement repeated button action w/hold-down */
6330 - repeatScroll: (NSTimer *)scrollEntry
6332   NSEvent *e = [[self window] currentEvent];
6333   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
6334   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
6336   /* clear timer if need be */
6337   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
6338     {
6339         [scroll_repeat_entry invalidate];
6340         [scroll_repeat_entry release];
6341         scroll_repeat_entry = nil;
6343         if (inKnob)
6344           return self;
6346         scroll_repeat_entry
6347           = [[NSTimer scheduledTimerWithTimeInterval:
6348                         SCROLL_BAR_CONTINUOUS_DELAY
6349                                             target: self
6350                                           selector: @selector (repeatScroll:)
6351                                           userInfo: 0
6352                                            repeats: YES]
6353               retain];
6354     }
6356   [self sendScrollEventAtLoc: 0 fromEvent: e];
6357   return self;
6361 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
6362    mouseDragged events without going into a modal loop. */
6363 - (void)mouseDown: (NSEvent *)e
6365   NSRect sr, kr;
6366   /* hitPart is only updated AFTER event is passed on */
6367   NSScrollerPart part = [self testPart: [e locationInWindow]];
6368   double inc = 0.0, loc, kloc, pos;
6369   int edge = 0;
6371   NSTRACE (EmacsScroller_mouseDown);
6373   switch (part)
6374     {
6375     case NSScrollerDecrementPage:
6376         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
6377     case NSScrollerIncrementPage:
6378         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
6379     case NSScrollerDecrementLine:
6380       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
6381     case NSScrollerIncrementLine:
6382       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
6383     case NSScrollerKnob:
6384       last_hit_part = scroll_bar_handle; break;
6385     case NSScrollerKnobSlot:  /* GNUstep-only */
6386       last_hit_part = scroll_bar_move_ratio; break;
6387     default:  /* NSScrollerNoPart? */
6388       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
6389                (long) part);
6390       return;
6391     }
6393   if (inc != 0.0)
6394     {
6395       pos = 0;      /* ignored */
6397       /* set a timer to repeat, as we can't let superclass do this modally */
6398       scroll_repeat_entry
6399         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
6400                                             target: self
6401                                           selector: @selector (repeatScroll:)
6402                                           userInfo: 0
6403                                            repeats: YES]
6404             retain];
6405     }
6406   else
6407     {
6408       /* handle, or on GNUstep possibly slot */
6409       NSEvent *fake_event;
6411       /* compute float loc in slot and mouse offset on knob */
6412       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6413                       toView: nil];
6414       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6415       if (loc <= 0.0)
6416         {
6417           loc = 0.0;
6418           edge = -1;
6419         }
6420       else if (loc >= NSHeight (sr))
6421         {
6422           loc = NSHeight (sr);
6423           edge = 1;
6424         }
6426       if (edge)
6427         kloc = 0.5 * edge;
6428       else
6429         {
6430           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
6431                           toView: nil];
6432           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
6433         }
6434       last_mouse_offset = kloc;
6436       /* if knob, tell emacs a location offset by knob pos
6437          (to indicate top of handle) */
6438       if (part == NSScrollerKnob)
6439           pos = (loc - last_mouse_offset) / NSHeight (sr);
6440       else
6441         /* else this is a slot click on GNUstep: go straight there */
6442         pos = loc / NSHeight (sr);
6444       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
6445       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
6446                                       location: [e locationInWindow]
6447                                  modifierFlags: [e modifierFlags]
6448                                      timestamp: [e timestamp]
6449                                   windowNumber: [e windowNumber]
6450                                        context: [e context]
6451                                    eventNumber: [e eventNumber]
6452                                     clickCount: [e clickCount]
6453                                       pressure: [e pressure]];
6454       [super mouseUp: fake_event];
6455     }
6457   if (part != NSScrollerKnob)
6458     [self sendScrollEventAtLoc: pos fromEvent: e];
6462 /* Called as we manually track scroller drags, rather than superclass. */
6463 - (void)mouseDragged: (NSEvent *)e
6465     NSRect sr;
6466     double loc, pos;
6467     int edge = 0;
6469     NSTRACE (EmacsScroller_mouseDragged);
6471       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6472                       toView: nil];
6473       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6475       if (loc <= 0.0)
6476         {
6477           loc = 0.0;
6478           edge = -1;
6479         }
6480       else if (loc >= NSHeight (sr) + last_mouse_offset)
6481         {
6482           loc = NSHeight (sr) + last_mouse_offset;
6483           edge = 1;
6484         }
6486       pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
6487       [self sendScrollEventAtLoc: pos fromEvent: e];
6491 - (void)mouseUp: (NSEvent *)e
6493   if (scroll_repeat_entry)
6494     {
6495       [scroll_repeat_entry invalidate];
6496       [scroll_repeat_entry release];
6497       scroll_repeat_entry = nil;
6498     }
6499   last_hit_part = 0;
6503 /* treat scrollwheel events in the bar as though they were in the main window */
6504 - (void) scrollWheel: (NSEvent *)theEvent
6506   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
6507   [view mouseDown: theEvent];
6510 @end  /* EmacsScroller */
6515 /* ==========================================================================
6517    Font-related functions; these used to be in nsfaces.m
6519    ========================================================================== */
6522 Lisp_Object
6523 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
6525   struct font *font = XFONT_OBJECT (font_object);
6527   if (fontset < 0)
6528     fontset = fontset_from_font (font_object);
6529   FRAME_FONTSET (f) = fontset;
6531   if (FRAME_FONT (f) == font)
6532     /* This font is already set in frame F.  There's nothing more to
6533        do.  */
6534     return font_object;
6536   FRAME_FONT (f) = font;
6538   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
6539   FRAME_COLUMN_WIDTH (f) = font->average_width;
6540   FRAME_SPACE_WIDTH (f) = font->space_width;
6541   FRAME_LINE_HEIGHT (f) = font->height;
6543   compute_fringe_widths (f, 1);
6545   /* Compute the scroll bar width in character columns.  */
6546   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6547     {
6548       int wid = FRAME_COLUMN_WIDTH (f);
6549       FRAME_CONFIG_SCROLL_BAR_COLS (f)
6550         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
6551     }
6552   else
6553     {
6554       int wid = FRAME_COLUMN_WIDTH (f);
6555       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6556     }
6558   /* Now make the frame display the given font.  */
6559   if (FRAME_NS_WINDOW (f) != 0)
6560         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6562   return font_object;
6566 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
6567 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
6568          in 1.43. */
6570 const char *
6571 ns_xlfd_to_fontname (const char *xlfd)
6572 /* --------------------------------------------------------------------------
6573     Convert an X font name (XLFD) to an NS font name.
6574     Only family is used.
6575     The string returned is temporarily allocated.
6576    -------------------------------------------------------------------------- */
6578   char *name = xmalloc (180);
6579   int i, len;
6580   const char *ret;
6582   if (!strncmp (xlfd, "--", 2))
6583     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
6584   else
6585     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
6587   /* stopgap for malformed XLFD input */
6588   if (strlen (name) == 0)
6589     strcpy (name, "Monaco");
6591   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
6592      also uppercase after '-' or ' ' */
6593   name[0] = toupper (name[0]);
6594   for (len =strlen (name), i =0; i<len; i++)
6595     {
6596       if (name[i] == '$')
6597         {
6598           name[i] = '-';
6599           if (i+1<len)
6600             name[i+1] = toupper (name[i+1]);
6601         }
6602       else if (name[i] == '_')
6603         {
6604           name[i] = ' ';
6605           if (i+1<len)
6606             name[i+1] = toupper (name[i+1]);
6607         }
6608     }
6609 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
6610   ret = [[NSString stringWithUTF8String: name] UTF8String];
6611   xfree (name);
6612   return ret;
6616 void
6617 syms_of_nsterm (void)
6619   NSTRACE (syms_of_nsterm);
6621   ns_antialias_threshold = 10.0;
6623   /* from 23+ we need to tell emacs what modifiers there are.. */
6624   DEFSYM (Qmodifier_value, "modifier-value");
6625   DEFSYM (Qalt, "alt");
6626   DEFSYM (Qhyper, "hyper");
6627   DEFSYM (Qmeta, "meta");
6628   DEFSYM (Qsuper, "super");
6629   DEFSYM (Qcontrol, "control");
6630   DEFSYM (Qnone, "none");
6631   DEFSYM (QUTF8_STRING, "UTF8_STRING");
6633   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
6634   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
6635   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
6636   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
6637   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
6639   DEFVAR_LISP ("ns-input-file", ns_input_file,
6640               "The file specified in the last NS event.");
6641   ns_input_file =Qnil;
6643   DEFVAR_LISP ("ns-input-text", ns_input_text,
6644               "The data received in the last NS text drag event.");
6645   ns_input_text =Qnil;
6647   DEFVAR_LISP ("ns-working-text", ns_working_text,
6648               "String for visualizing working composition sequence.");
6649   ns_working_text =Qnil;
6651   DEFVAR_LISP ("ns-input-font", ns_input_font,
6652               "The font specified in the last NS event.");
6653   ns_input_font =Qnil;
6655   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
6656               "The fontsize specified in the last NS event.");
6657   ns_input_fontsize =Qnil;
6659   DEFVAR_LISP ("ns-input-line", ns_input_line,
6660                "The line specified in the last NS event.");
6661   ns_input_line =Qnil;
6663   DEFVAR_LISP ("ns-input-color", ns_input_color,
6664                "The color specified in the last NS event.");
6665   ns_input_color =Qnil;
6667   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
6668                "The service name specified in the last NS event.");
6669   ns_input_spi_name =Qnil;
6671   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
6672                "The service argument specified in the last NS event.");
6673   ns_input_spi_arg =Qnil;
6675   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
6676                "This variable describes the behavior of the alternate or option key.\n\
6677 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6678 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6679 at all, allowing it to be used at a lower level for accented character entry.");
6680   ns_alternate_modifier = Qmeta;
6682   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
6683                "This variable describes the behavior of the right alternate or option key.\n\
6684 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6685 Set to left means be the same key as `ns-alternate-modifier'.\n\
6686 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6687 at all, allowing it to be used at a lower level for accented character entry.");
6688   ns_right_alternate_modifier = Qleft;
6690   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
6691                "This variable describes the behavior of the command key.\n\
6692 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6693   ns_command_modifier = Qsuper;
6695   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
6696                "This variable describes the behavior of the right command key.\n\
6697 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6698 Set to left means be the same key as `ns-command-modifier'.\n\
6699 Set to none means that the command / option key is not interpreted by Emacs\n\
6700 at all, allowing it to be used at a lower level for accented character entry.");
6701   ns_right_command_modifier = Qleft;
6703   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
6704                "This variable describes the behavior of the control key.\n\
6705 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6706   ns_control_modifier = Qcontrol;
6708   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
6709                "This variable describes the behavior of the right control key.\n\
6710 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6711 Set to left means be the same key as `ns-control-modifier'.\n\
6712 Set to none means that the control / option key is not interpreted by Emacs\n\
6713 at all, allowing it to be used at a lower level for accented character entry.");
6714   ns_right_control_modifier = Qleft;
6716   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
6717                "This variable describes the behavior of the function key (on laptops).\n\
6718 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6719 Set to none means that the function key is not interpreted by Emacs at all,\n\
6720 allowing it to be used at a lower level for accented character entry.");
6721   ns_function_modifier = Qnone;
6723   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
6724                "Non-nil (the default) means to render text antialiased. Only has an effect on OS X Panther and above.");
6725   ns_antialias_text = Qt;
6727   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
6728                "Whether to confirm application quit using dialog.");
6729   ns_confirm_quit = Qnil;
6731   staticpro (&ns_display_name_list);
6732   ns_display_name_list = Qnil;
6734   staticpro (&last_mouse_motion_frame);
6735   last_mouse_motion_frame = Qnil;
6737   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
6738                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
6739 Only works on OSX 10.6 or later.  */);
6740   ns_auto_hide_menu_bar = Qnil;
6742   /* TODO: move to common code */
6743   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
6744                doc: /* Which toolkit scroll bars Emacs uses, if any.
6745 A value of nil means Emacs doesn't use toolkit scroll bars.
6746 With the X Window system, the value is a symbol describing the
6747 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
6748 With MS Windows or Nextstep, the value is t.  */);
6749   Vx_toolkit_scroll_bars = Qt;
6751   DEFVAR_BOOL ("x-use-underline-position-properties",
6752                x_use_underline_position_properties,
6753      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
6754 A value of nil means ignore them.  If you encounter fonts with bogus
6755 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
6756 to 4.1, set this to nil. */);
6757   x_use_underline_position_properties = 0;
6759   DEFVAR_BOOL ("x-underline-at-descent-line",
6760                x_underline_at_descent_line,
6761      doc: /* Non-nil means to draw the underline at the same place as the descent line.
6762 A value of nil means to draw the underline according to the value of the
6763 variable `x-use-underline-position-properties', which is usually at the
6764 baseline level.  The default value is nil.  */);
6765   x_underline_at_descent_line = 0;
6767   /* Tell emacs about this window system. */
6768   Fprovide (intern ("ns"), Qnil);