1 /* NeXT/Open/GNUstep / MacOSX communication module.
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2013 Free Software
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. */
36 #include <sys/types.h>
42 #include <c-strcase.h>
46 #include "blockinput.h"
47 #include "sysselect.h"
50 #include "character.h"
52 #include "composite.h"
55 #include "termhooks.h"
65 int term_trace_num = 0;
66 #define NSTRACE(x) fprintf (stderr, "%s:%d: [%d] " #x "\n", \
67 __FILE__, __LINE__, ++term_trace_num)
72 extern NSString *NSMenuDidBeginTrackingNotification;
74 /* ==========================================================================
78 ========================================================================== */
80 /* Convert a symbol indexed with an NSxxx value to a value as defined
81 in keyboard.c (lispy_function_key). I hope this is a correct way
83 static unsigned convert_ns_to_X_keysym[] =
85 NSHomeFunctionKey, 0x50,
86 NSLeftArrowFunctionKey, 0x51,
87 NSUpArrowFunctionKey, 0x52,
88 NSRightArrowFunctionKey, 0x53,
89 NSDownArrowFunctionKey, 0x54,
90 NSPageUpFunctionKey, 0x55,
91 NSPageDownFunctionKey, 0x56,
92 NSEndFunctionKey, 0x57,
93 NSBeginFunctionKey, 0x58,
94 NSSelectFunctionKey, 0x60,
95 NSPrintFunctionKey, 0x61,
96 NSClearLineFunctionKey, 0x0B,
97 NSExecuteFunctionKey, 0x62,
98 NSInsertFunctionKey, 0x63,
99 NSUndoFunctionKey, 0x65,
100 NSRedoFunctionKey, 0x66,
101 NSMenuFunctionKey, 0x67,
102 NSFindFunctionKey, 0x68,
103 NSHelpFunctionKey, 0x6A,
104 NSBreakFunctionKey, 0x6B,
106 NSF1FunctionKey, 0xBE,
107 NSF2FunctionKey, 0xBF,
108 NSF3FunctionKey, 0xC0,
109 NSF4FunctionKey, 0xC1,
110 NSF5FunctionKey, 0xC2,
111 NSF6FunctionKey, 0xC3,
112 NSF7FunctionKey, 0xC4,
113 NSF8FunctionKey, 0xC5,
114 NSF9FunctionKey, 0xC6,
115 NSF10FunctionKey, 0xC7,
116 NSF11FunctionKey, 0xC8,
117 NSF12FunctionKey, 0xC9,
118 NSF13FunctionKey, 0xCA,
119 NSF14FunctionKey, 0xCB,
120 NSF15FunctionKey, 0xCC,
121 NSF16FunctionKey, 0xCD,
122 NSF17FunctionKey, 0xCE,
123 NSF18FunctionKey, 0xCF,
124 NSF19FunctionKey, 0xD0,
125 NSF20FunctionKey, 0xD1,
126 NSF21FunctionKey, 0xD2,
127 NSF22FunctionKey, 0xD3,
128 NSF23FunctionKey, 0xD4,
129 NSF24FunctionKey, 0xD5,
131 NSBackspaceCharacter, 0x08, /* 8: Not on some KBs. */
132 NSDeleteCharacter, 0xFF, /* 127: Big 'delete' key upper right. */
133 NSDeleteFunctionKey, 0x9F, /* 63272: Del forw key off main array. */
135 NSTabCharacter, 0x09,
136 0x19, 0x09, /* left tab->regular since pass shift */
137 NSCarriageReturnCharacter, 0x0D,
138 NSNewlineCharacter, 0x0D,
139 NSEnterCharacter, 0x8D,
141 0x41|NSNumericPadKeyMask, 0xAE, /* KP_Decimal */
142 0x43|NSNumericPadKeyMask, 0xAA, /* KP_Multiply */
143 0x45|NSNumericPadKeyMask, 0xAB, /* KP_Add */
144 0x4B|NSNumericPadKeyMask, 0xAF, /* KP_Divide */
145 0x4E|NSNumericPadKeyMask, 0xAD, /* KP_Subtract */
146 0x51|NSNumericPadKeyMask, 0xBD, /* KP_Equal */
147 0x52|NSNumericPadKeyMask, 0xB0, /* KP_0 */
148 0x53|NSNumericPadKeyMask, 0xB1, /* KP_1 */
149 0x54|NSNumericPadKeyMask, 0xB2, /* KP_2 */
150 0x55|NSNumericPadKeyMask, 0xB3, /* KP_3 */
151 0x56|NSNumericPadKeyMask, 0xB4, /* KP_4 */
152 0x57|NSNumericPadKeyMask, 0xB5, /* KP_5 */
153 0x58|NSNumericPadKeyMask, 0xB6, /* KP_6 */
154 0x59|NSNumericPadKeyMask, 0xB7, /* KP_7 */
155 0x5B|NSNumericPadKeyMask, 0xB8, /* KP_8 */
156 0x5C|NSNumericPadKeyMask, 0xB9, /* KP_9 */
158 0x1B, 0x1B /* escape */
161 static Lisp_Object Qmodifier_value;
162 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper;
163 extern Lisp_Object Qcursor_color, Qcursor_type, Qns, Qleft;
165 static Lisp_Object QUTF8_STRING;
167 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
168 the maximum font size to NOT antialias. On GNUstep there is currently
169 no way to control this behavior. */
170 float ns_antialias_threshold;
172 /* Used to pick up AppleHighlightColor on OS X */
173 NSString *ns_selection_color;
175 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
176 NSString *ns_app_name = @"Emacs"; /* default changed later */
178 /* Display variables */
179 struct ns_display_info *x_display_list; /* Chain of existing displays */
180 Lisp_Object ns_display_name_list;
181 long context_menu_value = 0;
184 NSPoint last_mouse_motion_position;
185 static NSRect last_mouse_glyph;
186 static Time last_mouse_movement_time = 0;
187 static Lisp_Object last_mouse_motion_frame;
188 static EmacsScroller *last_mouse_scroll_bar = nil;
189 static struct frame *ns_updating_frame;
190 static NSView *focus_view = NULL;
191 static int ns_window_num = 0;
192 #ifdef NS_IMPL_GNUSTEP
195 static BOOL gsaved = NO;
196 static BOOL ns_fake_keydown = NO;
197 int ns_tmp_flags; /* FIXME */
198 struct nsfont_info *ns_tmp_font; /* FIXME */
199 static BOOL ns_menu_bar_is_hidden = NO;
200 /*static int debug_lock = 0; */
203 static BOOL send_appdefined = YES;
204 #define NO_APPDEFINED_DATA (-8)
205 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
206 static NSTimer *timed_entry = 0;
207 static NSTimer *scroll_repeat_entry = nil;
208 static fd_set select_readfds, select_writefds;
209 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
210 static int select_nfds = 0, select_valid = 0;
211 static EMACS_TIME select_timeout = { 0, 0 };
212 static int selfds[2] = { -1, -1 };
213 static pthread_mutex_t select_mutex;
214 static int apploopnr = 0;
215 static NSAutoreleasePool *outerpool;
216 static struct input_event *emacs_event = NULL;
217 static struct input_event *q_event_ptr = NULL;
218 static int n_emacs_events_pending = 0;
219 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
220 *ns_pending_service_args;
221 static BOOL ns_do_open_file = NO;
222 static BOOL ns_last_use_native_fullscreen;
225 struct input_event *q;
232 * State for pending menu activation:
233 * MENU_NONE Normal state
234 * MENU_PENDING A menu has been clicked on, but has been canceled so we can
235 * run lisp to update the menu.
236 * MENU_OPENING Menu is up to date, and the click event is redone so the menu
240 #define MENU_PENDING 1
241 #define MENU_OPENING 2
242 static int menu_will_open_state = MENU_NONE;
244 /* Saved position for menu click. */
245 static CGPoint menu_mouse_point;
247 /* Title for the menu to open. */
248 static char *menu_pending_title = 0;
250 /* Convert modifiers in a NeXTstep event to emacs style modifiers. */
251 #define NS_FUNCTION_KEY_MASK 0x800000
252 #define NSLeftControlKeyMask (0x000001 | NSControlKeyMask)
253 #define NSRightControlKeyMask (0x002000 | NSControlKeyMask)
254 #define NSLeftCommandKeyMask (0x000008 | NSCommandKeyMask)
255 #define NSRightCommandKeyMask (0x000010 | NSCommandKeyMask)
256 #define NSLeftAlternateKeyMask (0x000020 | NSAlternateKeyMask)
257 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
258 #define EV_MODIFIERS(e) \
259 ((([e modifierFlags] & NSHelpKeyMask) ? \
260 hyper_modifier : 0) \
261 | (!EQ (ns_right_alternate_modifier, Qleft) && \
262 (([e modifierFlags] & NSRightAlternateKeyMask) \
263 == NSRightAlternateKeyMask) ? \
264 parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
265 | (([e modifierFlags] & NSAlternateKeyMask) ? \
266 parse_solitary_modifier (ns_alternate_modifier) : 0) \
267 | (([e modifierFlags] & NSShiftKeyMask) ? \
268 shift_modifier : 0) \
269 | (!EQ (ns_right_control_modifier, Qleft) && \
270 (([e modifierFlags] & NSRightControlKeyMask) \
271 == NSRightControlKeyMask) ? \
272 parse_solitary_modifier (ns_right_control_modifier) : 0) \
273 | (([e modifierFlags] & NSControlKeyMask) ? \
274 parse_solitary_modifier (ns_control_modifier) : 0) \
275 | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ? \
276 parse_solitary_modifier (ns_function_modifier) : 0) \
277 | (!EQ (ns_right_command_modifier, Qleft) && \
278 (([e modifierFlags] & NSRightCommandKeyMask) \
279 == NSRightCommandKeyMask) ? \
280 parse_solitary_modifier (ns_right_command_modifier) : 0) \
281 | (([e modifierFlags] & NSCommandKeyMask) ? \
282 parse_solitary_modifier (ns_command_modifier):0))
284 #define EV_UDMODIFIERS(e) \
285 ((([e type] == NSLeftMouseDown) ? down_modifier : 0) \
286 | (([e type] == NSRightMouseDown) ? down_modifier : 0) \
287 | (([e type] == NSOtherMouseDown) ? down_modifier : 0) \
288 | (([e type] == NSLeftMouseDragged) ? down_modifier : 0) \
289 | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
290 | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
291 | (([e type] == NSLeftMouseUp) ? up_modifier : 0) \
292 | (([e type] == NSRightMouseUp) ? up_modifier : 0) \
293 | (([e type] == NSOtherMouseUp) ? up_modifier : 0))
295 #define EV_BUTTON(e) \
296 ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 : \
297 (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
298 [e buttonNumber] - 1)
300 /* Convert the time field to a timestamp in milliseconds. */
301 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
303 /* This is a piece of code which is common to all the event handling
304 methods. Maybe it should even be a function. */
305 #define EV_TRAILER(e) \
307 XSETFRAME (emacs_event->frame_or_window, emacsframe); \
308 if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \
311 n_emacs_events_pending++; \
312 kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \
315 hold_event (emacs_event); \
316 EVENT_INIT (*emacs_event); \
317 ns_send_appdefined (-1); \
320 void x_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
322 /* TODO: get rid of need for these forward declarations */
323 static void ns_condemn_scroll_bars (struct frame *f);
324 static void ns_judge_scroll_bars (struct frame *f);
325 void x_set_frame_alpha (struct frame *f);
328 /* ==========================================================================
332 ========================================================================== */
335 hold_event (struct input_event *event)
337 if (hold_event_q.nr == hold_event_q.cap)
339 if (hold_event_q.cap == 0) hold_event_q.cap = 10;
340 else hold_event_q.cap *= 2;
341 hold_event_q.q = (struct input_event *)
342 xrealloc (hold_event_q.q, hold_event_q.cap * sizeof (*hold_event_q.q));
345 hold_event_q.q[hold_event_q.nr++] = *event;
346 /* Make sure ns_read_socket is called, i.e. we have input. */
348 send_appdefined = YES;
352 append2 (Lisp_Object list, Lisp_Object item)
353 /* --------------------------------------------------------------------------
354 Utility to append to a list
355 -------------------------------------------------------------------------- */
357 Lisp_Object array[2];
359 array[1] = Fcons (item, Qnil);
360 return Fnconc (2, &array[0]);
365 ns_etc_directory (void)
366 /* If running as a self-contained app bundle, return as a string the
367 filename of the etc directory, if present; else nil. */
369 NSBundle *bundle = [NSBundle mainBundle];
370 NSString *resourceDir = [bundle resourcePath];
371 NSString *resourcePath;
372 NSFileManager *fileManager = [NSFileManager defaultManager];
375 resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
376 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
378 if (isDir) return [resourcePath UTF8String];
386 /* If running as a self-contained app bundle, return as a path string
387 the filenames of the libexec and bin directories, ie libexec:bin.
388 Otherwise, return nil.
389 Normally, Emacs does not add its own bin/ directory to the PATH.
390 However, a self-contained NS build has a different layout, with
391 bin/ and libexec/ subdirectories in the directory that contains
393 We put libexec first, because init_callproc_1 uses the first
394 element to initialize exec-directory. An alternative would be
395 for init_callproc to check for invocation-directory/libexec.
398 NSBundle *bundle = [NSBundle mainBundle];
399 NSString *resourceDir = [bundle resourcePath];
400 NSString *binDir = [bundle bundlePath];
401 NSString *resourcePath, *resourcePaths;
403 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
404 NSFileManager *fileManager = [NSFileManager defaultManager];
406 NSEnumerator *pathEnum;
409 range = [resourceDir rangeOfString: @"Contents"];
410 if (range.location != NSNotFound)
412 binDir = [binDir stringByAppendingPathComponent: @"Contents"];
414 binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
418 paths = [binDir stringsByAppendingPaths:
419 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
420 pathEnum = [paths objectEnumerator];
423 while ((resourcePath = [pathEnum nextObject]))
425 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
428 if ([resourcePaths length] > 0)
430 = [resourcePaths stringByAppendingString: pathSeparator];
432 = [resourcePaths stringByAppendingString: resourcePath];
435 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
443 /* If running as a self-contained app bundle, return as a path string
444 the filenames of the site-lisp, lisp and leim directories.
445 Ie, site-lisp:lisp:leim. Otherwise, return nil. */
447 NSBundle *bundle = [NSBundle mainBundle];
448 NSString *resourceDir = [bundle resourcePath];
449 NSString *resourcePath, *resourcePaths;
450 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
451 NSFileManager *fileManager = [NSFileManager defaultManager];
453 NSArray *paths = [resourceDir stringsByAppendingPaths:
454 [NSArray arrayWithObjects:
455 @"site-lisp", @"lisp", @"leim", nil]];
456 NSEnumerator *pathEnum = [paths objectEnumerator];
459 /* Hack to skip site-lisp. */
460 if (no_site_lisp) resourcePath = [pathEnum nextObject];
462 while ((resourcePath = [pathEnum nextObject]))
464 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
467 if ([resourcePaths length] > 0)
469 = [resourcePaths stringByAppendingString: pathSeparator];
471 = [resourcePaths stringByAppendingString: resourcePath];
474 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
480 ns_timeout (int usecs)
481 /* --------------------------------------------------------------------------
482 Blocking timer utility used by ns_ring_bell
483 -------------------------------------------------------------------------- */
485 EMACS_TIME wakeup = add_emacs_time (current_emacs_time (),
486 make_emacs_time (0, usecs * 1000));
488 /* Keep waiting until past the time wakeup. */
491 EMACS_TIME timeout, now = current_emacs_time ();
492 if (EMACS_TIME_LE (wakeup, now))
494 timeout = sub_emacs_time (wakeup, now);
496 /* Try to wait that long--but we might wake up sooner. */
497 pselect (0, NULL, NULL, NULL, &timeout, NULL);
503 ns_release_object (void *obj)
504 /* --------------------------------------------------------------------------
505 Release an object (callable from C)
506 -------------------------------------------------------------------------- */
513 ns_retain_object (void *obj)
514 /* --------------------------------------------------------------------------
515 Retain an object (callable from C)
516 -------------------------------------------------------------------------- */
523 ns_alloc_autorelease_pool (void)
524 /* --------------------------------------------------------------------------
525 Allocate a pool for temporary objects (callable from C)
526 -------------------------------------------------------------------------- */
528 return [[NSAutoreleasePool alloc] init];
533 ns_release_autorelease_pool (void *pool)
534 /* --------------------------------------------------------------------------
535 Free a pool and temporary objects it refers to (callable from C)
536 -------------------------------------------------------------------------- */
538 ns_release_object (pool);
543 /* ==========================================================================
545 Focus (clipping) and screen update
547 ========================================================================== */
550 // Window constraining
551 // -------------------
553 // To ensure that the windows are not placed under the menu bar, they
554 // are typically moved by the call-back constrainFrameRect. However,
555 // by overriding it, it's possible to inhibit this, leaving the window
556 // in it's original position.
558 // It's possible to hide the menu bar. However, technically, it's only
559 // possible to hide it when the application is active. To ensure that
560 // this work properly, the menu bar and window constraining are
561 // deferred until the application becomes active.
563 // Even though it's not possible to manually move a window above the
564 // top of the screen, it is allowed if it's done programmatically,
565 // when the menu is hidden. This allows the editable area to cover the
566 // full screen height.
571 // Use the following extra files:
574 // ;; Hide menu and place frame slightly above the top of the screen.
575 // (setq ns-auto-hide-menu-bar t)
576 // (set-frame-position (selected-frame) 0 -20)
580 // emacs -Q -l init.el
582 // Result: No menu bar, and the title bar should be above the screen.
588 // Result: Menu bar visible, frame placed immediately below the menu.
592 ns_constrain_all_frames (void)
594 Lisp_Object tail, frame;
596 FOR_EACH_FRAME (tail, frame)
598 struct frame *f = XFRAME (frame);
601 NSView *view = FRAME_NS_VIEW (f);
602 /* This no-op will trigger the default window placing
603 * constraint system. */
604 f->output_data.ns->dont_constrain = 0;
605 [[view window] setFrameOrigin:[[view window] frame].origin];
611 /* True, if the menu bar should be hidden. */
614 ns_menu_bar_should_be_hidden (void)
616 return !NILP (ns_auto_hide_menu_bar)
617 && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
621 /* Show or hide the menu bar, based on user setting. */
624 ns_update_auto_hide_menu_bar (void)
627 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
630 NSTRACE (ns_update_auto_hide_menu_bar);
634 && [NSApp respondsToSelector:@selector(setPresentationOptions:)])
636 // Note, "setPresentationOptions" triggers an error unless the
637 // application is active.
638 BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
640 if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
642 NSApplicationPresentationOptions options
643 = NSApplicationPresentationAutoHideDock;
645 if (menu_bar_should_be_hidden)
646 options |= NSApplicationPresentationAutoHideMenuBar;
648 [NSApp setPresentationOptions: options];
650 ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
652 if (!ns_menu_bar_is_hidden)
654 ns_constrain_all_frames ();
666 ns_update_begin (struct frame *f)
667 /* --------------------------------------------------------------------------
668 Prepare for a grouped sequence of drawing calls
669 external (RIF) call; whole frame, called before update_window_begin
670 -------------------------------------------------------------------------- */
672 NSView *view = FRAME_NS_VIEW (f);
673 NSRect r = [view frame];
675 NSTRACE (ns_update_begin);
677 ns_update_auto_hide_menu_bar ();
679 ns_updating_frame = f;
682 /* drawRect may have been called for say the minibuffer, and then clip path
683 is for the minibuffer. But the display engine may draw more because
684 we have set the frame as garbaged. So reset clip path to the whole
686 bp = [[NSBezierPath bezierPathWithRect: r] retain];
690 #ifdef NS_IMPL_GNUSTEP
691 uRect = NSMakeRect (0, 0, 0, 0);
697 ns_update_window_begin (struct window *w)
698 /* --------------------------------------------------------------------------
699 Prepare for a grouped sequence of drawing calls
700 external (RIF) call; for one window, called after update_begin
701 -------------------------------------------------------------------------- */
703 struct frame *f = XFRAME (WINDOW_FRAME (w));
704 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
705 NSTRACE (ns_update_window_begin);
707 set_output_cursor (&w->cursor);
711 if (f == hlinfo->mouse_face_mouse_frame)
713 /* Don't do highlighting for mouse motion during the update. */
714 hlinfo->mouse_face_defer = 1;
716 /* If the frame needs to be redrawn,
717 simply forget about any prior mouse highlighting. */
718 if (FRAME_GARBAGED_P (f))
719 hlinfo->mouse_face_window = Qnil;
721 /* (further code for mouse faces ifdef'd out in other terms elided) */
729 ns_update_window_end (struct window *w, int cursor_on_p,
730 int mouse_face_overwritten_p)
731 /* --------------------------------------------------------------------------
732 Finished a grouped sequence of drawing calls
733 external (RIF) call; for one window called before update_end
734 -------------------------------------------------------------------------- */
736 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
738 /* note: this fn is nearly identical in all terms */
739 if (!w->pseudo_window_p)
744 display_and_set_cursor (w, 1,
745 output_cursor.hpos, output_cursor.vpos,
746 output_cursor.x, output_cursor.y);
748 if (draw_window_fringes (w, 1))
749 x_draw_vertical_border (w);
754 /* If a row with mouse-face was overwritten, arrange for
755 frame_up_to_date to redisplay the mouse highlight. */
756 if (mouse_face_overwritten_p)
758 hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
759 hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
760 hlinfo->mouse_face_window = Qnil;
763 updated_window = NULL;
764 NSTRACE (update_window_end);
769 ns_update_end (struct frame *f)
770 /* --------------------------------------------------------------------------
771 Finished a grouped sequence of drawing calls
772 external (RIF) call; for whole frame, called after update_window_end
773 -------------------------------------------------------------------------- */
775 NSView *view = FRAME_NS_VIEW (f);
777 /* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
778 MOUSE_HL_INFO (f)->mouse_face_defer = 0;
782 #ifdef NS_IMPL_GNUSTEP
783 /* trigger flush only in the rectangle we tracked as being drawn */
784 [view unlockFocusNeedsFlush: NO];
785 /*fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", uRect.origin.x, uRect.origin.y, uRect.size.width, uRect.size.height); */
786 [view lockFocusInRect: uRect];
790 [[view window] flushWindow];
793 ns_updating_frame = NULL;
794 NSTRACE (ns_update_end);
799 ns_flush (struct frame *f)
800 /* --------------------------------------------------------------------------
802 NS impl is no-op since currently we flush in ns_update_end and elsewhere
803 -------------------------------------------------------------------------- */
810 ns_focus (struct frame *f, NSRect *r, int n)
811 /* --------------------------------------------------------------------------
812 Internal: Focus on given frame. During small local updates this is used to
813 draw, however during large updates, ns_update_begin and ns_update_end are
814 called to wrap the whole thing, in which case these calls are stubbed out.
815 Except, on GNUstep, we accumulate the rectangle being drawn into, because
816 the back end won't do this automatically, and will just end up flushing
818 -------------------------------------------------------------------------- */
820 // NSTRACE (ns_focus);
821 #ifdef NS_IMPL_GNUSTEP
824 u = NSUnionRect (r[0], r[1]);
829 fprintf (stderr, "focus: %d", c++);
830 if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
831 fprintf (stderr, "\n"); */
833 if (f != ns_updating_frame)
835 NSView *view = FRAME_NS_VIEW (f);
836 if (view != focus_view)
838 if (focus_view != NULL)
840 [focus_view unlockFocus];
841 [[focus_view window] flushWindow];
846 #ifdef NS_IMPL_GNUSTEP
847 r ? [view lockFocusInRect: u] : [view lockFocus];
852 /*if (view) debug_lock++; */
854 #ifdef NS_IMPL_GNUSTEP
857 /* more than one rect being drawn into */
860 [view unlockFocus]; /* add prev rect to redraw list */
861 [view lockFocusInRect: u]; /* focus for draw in new rect */
866 #ifdef NS_IMPL_GNUSTEP
869 /* in batch mode, but in GNUstep must still track rectangles explicitly */
870 uRect = (r ? NSUnionRect (uRect, u) : [FRAME_NS_VIEW (f) visibleRect]);
877 [[NSGraphicsContext currentContext] saveGraphicsState];
879 NSRectClipList (r, 2);
888 ns_unfocus (struct frame *f)
889 /* --------------------------------------------------------------------------
890 Internal: Remove focus on given frame
891 -------------------------------------------------------------------------- */
893 // NSTRACE (ns_unfocus);
897 [[NSGraphicsContext currentContext] restoreGraphicsState];
901 if (f != ns_updating_frame)
903 if (focus_view != NULL)
905 [focus_view unlockFocus];
906 [[focus_view window] flushWindow];
915 ns_clip_to_row (struct window *w, struct glyph_row *row, int area, BOOL gc)
916 /* --------------------------------------------------------------------------
917 Internal (but parallels other terms): Focus drawing on given row
918 -------------------------------------------------------------------------- */
920 struct frame *f = XFRAME (WINDOW_FRAME (w));
922 int window_x, window_y, window_width;
924 window_box (w, area, &window_x, &window_y, &window_width, 0);
926 clip_rect.origin.x = window_x;
927 clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
928 clip_rect.origin.y = max (clip_rect.origin.y, window_y);
929 clip_rect.size.width = window_width;
930 clip_rect.size.height = row->visible_height;
932 ns_focus (f, &clip_rect, 1);
937 ns_ring_bell (struct frame *f)
938 /* --------------------------------------------------------------------------
940 -------------------------------------------------------------------------- */
942 NSTRACE (ns_ring_bell);
945 NSAutoreleasePool *pool;
946 struct frame *frame = SELECTED_FRAME ();
950 pool = [[NSAutoreleasePool alloc] init];
952 view = FRAME_NS_VIEW (frame);
956 NSPoint dim = NSMakePoint (128, 128);
959 r.origin.x += (r.size.width - dim.x) / 2;
960 r.origin.y += (r.size.height - dim.y) / 2;
961 r.size.width = dim.x;
962 r.size.height = dim.y;
963 surr = NSInsetRect (r, -2, -2);
964 ns_focus (frame, &surr, 1);
965 [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
966 [ns_lookup_indexed_color (NS_FACE_FOREGROUND
967 (FRAME_DEFAULT_FACE (frame)), frame) set];
969 [[view window] flushWindow];
971 [[view window] restoreCachedImage];
972 [[view window] flushWindow];
986 ns_reset_terminal_modes (struct terminal *terminal)
987 /* Externally called as hook */
989 NSTRACE (ns_reset_terminal_modes);
994 ns_set_terminal_modes (struct terminal *terminal)
995 /* Externally called as hook */
997 NSTRACE (ns_set_terminal_modes);
1002 /* ==========================================================================
1004 Frame / window manager related functions
1006 ========================================================================== */
1010 ns_raise_frame (struct frame *f)
1011 /* --------------------------------------------------------------------------
1012 Bring window to foreground and make it active
1013 -------------------------------------------------------------------------- */
1016 check_window_system (f);
1017 view = FRAME_NS_VIEW (f);
1019 if (FRAME_VISIBLE_P (f))
1020 [[view window] makeKeyAndOrderFront: NSApp];
1026 ns_lower_frame (struct frame *f)
1027 /* --------------------------------------------------------------------------
1029 -------------------------------------------------------------------------- */
1032 check_window_system (f);
1033 view = FRAME_NS_VIEW (f);
1035 [[view window] orderBack: NSApp];
1041 ns_frame_raise_lower (struct frame *f, int raise)
1042 /* --------------------------------------------------------------------------
1044 -------------------------------------------------------------------------- */
1046 NSTRACE (ns_frame_raise_lower);
1056 ns_frame_rehighlight (struct frame *frame)
1057 /* --------------------------------------------------------------------------
1058 External (hook): called on things like window switching within frame
1059 -------------------------------------------------------------------------- */
1061 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
1062 struct frame *old_highlight = dpyinfo->x_highlight_frame;
1064 NSTRACE (ns_frame_rehighlight);
1065 if (dpyinfo->x_focus_frame)
1067 dpyinfo->x_highlight_frame
1068 = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1069 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1070 : dpyinfo->x_focus_frame);
1071 if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1073 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1074 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1078 dpyinfo->x_highlight_frame = 0;
1080 if (dpyinfo->x_highlight_frame &&
1081 dpyinfo->x_highlight_frame != old_highlight)
1085 x_update_cursor (old_highlight, 1);
1086 x_set_frame_alpha (old_highlight);
1088 if (dpyinfo->x_highlight_frame)
1090 x_update_cursor (dpyinfo->x_highlight_frame, 1);
1091 x_set_frame_alpha (dpyinfo->x_highlight_frame);
1098 x_make_frame_visible (struct frame *f)
1099 /* --------------------------------------------------------------------------
1100 External: Show the window (X11 semantics)
1101 -------------------------------------------------------------------------- */
1103 NSTRACE (x_make_frame_visible);
1104 /* XXX: at some points in past this was not needed, as the only place that
1105 called this (frame.c:Fraise_frame ()) also called raise_lower;
1106 if this ends up the case again, comment this out again. */
1107 if (!FRAME_VISIBLE_P (f))
1109 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1111 SET_FRAME_VISIBLE (f, 1);
1114 /* Making a new frame from a fullscreen frame will make the new frame
1115 fullscreen also. So skip handleFS as this will print an error. */
1116 if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1117 && [view isFullscreen])
1120 if (f->want_fullscreen != FULLSCREEN_NONE)
1131 x_make_frame_invisible (struct frame *f)
1132 /* --------------------------------------------------------------------------
1133 External: Hide the window (X11 semantics)
1134 -------------------------------------------------------------------------- */
1137 NSTRACE (x_make_frame_invisible);
1138 check_window_system (f);
1139 view = FRAME_NS_VIEW (f);
1140 [[view window] orderOut: NSApp];
1141 SET_FRAME_VISIBLE (f, 0);
1142 SET_FRAME_ICONIFIED (f, 0);
1147 x_iconify_frame (struct frame *f)
1148 /* --------------------------------------------------------------------------
1149 External: Iconify window
1150 -------------------------------------------------------------------------- */
1153 struct ns_display_info *dpyinfo;
1155 NSTRACE (x_iconify_frame);
1156 check_window_system (f);
1157 view = FRAME_NS_VIEW (f);
1158 dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1160 if (dpyinfo->x_highlight_frame == f)
1161 dpyinfo->x_highlight_frame = 0;
1163 if ([[view window] windowNumber] <= 0)
1165 /* the window is still deferred. Make it very small, bring it
1166 on screen and order it out. */
1167 NSRect s = { { 100, 100}, {0, 0} };
1169 t = [[view window] frame];
1170 [[view window] setFrame: s display: NO];
1171 [[view window] orderBack: NSApp];
1172 [[view window] orderOut: NSApp];
1173 [[view window] setFrame: t display: NO];
1175 [[view window] miniaturize: NSApp];
1178 /* Free X resources of frame F. */
1181 x_free_frame_resources (struct frame *f)
1184 struct ns_display_info *dpyinfo;
1185 Mouse_HLInfo *hlinfo;
1187 NSTRACE (x_free_frame_resources);
1188 check_window_system (f);
1189 view = FRAME_NS_VIEW (f);
1190 dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1191 hlinfo = MOUSE_HL_INFO (f);
1193 [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1197 free_frame_menubar (f);
1199 if (FRAME_FACE_CACHE (f))
1200 free_frame_faces (f);
1202 if (f == dpyinfo->x_focus_frame)
1203 dpyinfo->x_focus_frame = 0;
1204 if (f == dpyinfo->x_highlight_frame)
1205 dpyinfo->x_highlight_frame = 0;
1206 if (f == hlinfo->mouse_face_mouse_frame)
1208 hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
1209 hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
1210 hlinfo->mouse_face_window = Qnil;
1211 hlinfo->mouse_face_mouse_frame = 0;
1214 if (f->output_data.ns->miniimage != nil)
1215 [f->output_data.ns->miniimage release];
1217 [[view window] close];
1220 xfree (f->output_data.ns);
1226 x_destroy_window (struct frame *f)
1227 /* --------------------------------------------------------------------------
1228 External: Delete the window
1229 -------------------------------------------------------------------------- */
1231 NSTRACE (x_destroy_window);
1232 check_window_system (f);
1233 x_free_frame_resources (f);
1239 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1240 /* --------------------------------------------------------------------------
1241 External: Position the window
1242 -------------------------------------------------------------------------- */
1244 NSView *view = FRAME_NS_VIEW (f);
1245 NSArray *screens = [NSScreen screens];
1246 NSScreen *fscreen = [screens objectAtIndex: 0];
1247 NSScreen *screen = [[view window] screen];
1249 NSTRACE (x_set_offset);
1256 if (view != nil && screen && fscreen)
1258 f->left_pos = f->size_hint_flags & XNegative
1259 ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1261 /* We use visibleFrame here to take menu bar into account.
1262 Ideally we should also adjust left/top with visibleFrame.origin. */
1264 f->top_pos = f->size_hint_flags & YNegative
1265 ? ([screen visibleFrame].size.height + f->top_pos
1266 - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1267 - FRAME_TOOLBAR_HEIGHT (f))
1269 #ifdef NS_IMPL_GNUSTEP
1270 if (f->left_pos < 100)
1271 f->left_pos = 100; /* don't overlap menu */
1273 /* Constrain the setFrameTopLeftPoint so we don't move behind the
1275 f->output_data.ns->dont_constrain = 0;
1276 [[view window] setFrameTopLeftPoint:
1277 NSMakePoint (SCREENMAXBOUND (f->left_pos),
1278 SCREENMAXBOUND ([fscreen frame].size.height
1279 - NS_TOP_POS (f)))];
1280 f->size_hint_flags &= ~(XNegative|YNegative);
1288 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1289 /* --------------------------------------------------------------------------
1290 Adjust window pixel size based on given character grid size
1291 Impl is a bit more complex than other terms, need to do some
1293 -------------------------------------------------------------------------- */
1295 EmacsView *view = FRAME_NS_VIEW (f);
1296 NSWindow *window = [view window];
1297 NSRect wr = [window frame];
1298 int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1299 int pixelwidth, pixelheight;
1301 NSTRACE (x_set_window_size);
1306 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1310 check_frame_size (f, &rows, &cols);
1312 f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1313 compute_fringe_widths (f, 0);
1315 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
1316 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1318 /* If we have a toolbar, take its height into account. */
1319 if (tb && ! [view isFullscreen])
1320 /* NOTE: previously this would generate wrong result if toolbar not
1321 yet displayed and fixing toolbar_height=32 helped, but
1322 now (200903) seems no longer needed */
1323 FRAME_TOOLBAR_HEIGHT (f) =
1324 NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1325 - FRAME_NS_TITLEBAR_HEIGHT (f);
1327 FRAME_TOOLBAR_HEIGHT (f) = 0;
1329 wr.size.width = pixelwidth + f->border_width;
1330 wr.size.height = pixelheight;
1331 if (! [view isFullscreen])
1332 wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1333 + FRAME_TOOLBAR_HEIGHT (f);
1335 /* Do not try to constrain to this screen. We may have multiple
1336 screens, and want Emacs to span those. Constraining to screen
1337 prevents that, and that is not nice to the user. */
1338 if (f->output_data.ns->zooming)
1339 f->output_data.ns->zooming = 0;
1341 wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1343 [view setRows: rows andColumns: cols];
1344 [window setFrame: wr display: YES];
1346 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1348 /* This is a trick to compensate for Emacs' managing the scrollbar area
1349 as a fixed number of standard character columns. Instead of leaving
1350 blank space for the extra, we chopped it off above. Now for
1351 left-hand scrollbars, we shift all rendering to the left by the
1352 difference between the real width and Emacs' imagined one. For
1353 right-hand bars, don't worry about it since the extra is never used.
1354 (Obviously doesn't work for vertically split windows tho..) */
1356 NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1357 ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1358 - NS_SCROLL_BAR_WIDTH (f), 0)
1359 : NSMakePoint (0, 0);
1360 [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1361 [view setBoundsOrigin: origin];
1364 change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1365 FRAME_PIXEL_WIDTH (f) = pixelwidth;
1366 FRAME_PIXEL_HEIGHT (f) = pixelheight;
1367 /* SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1369 mark_window_cursors_off (XWINDOW (f->root_window));
1370 cancel_mouse_face (f);
1377 ns_fullscreen_hook (FRAME_PTR f)
1379 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1381 if (!FRAME_VISIBLE_P (f))
1384 if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1386 /* Old style fs don't initiate correctly if created from
1387 init/default-frame alist, so use a timer (not nice...).
1389 [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1390 selector: @selector (handleFS)
1391 userInfo: nil repeats: NO];
1400 /* ==========================================================================
1404 ========================================================================== */
1408 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1410 struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1411 if (idx < 1 || idx >= color_table->avail)
1413 return color_table->colors[idx];
1418 ns_index_color (NSColor *color, struct frame *f)
1420 struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1424 if (!color_table->colors)
1426 color_table->size = NS_COLOR_CAPACITY;
1427 color_table->avail = 1; /* skip idx=0 as marker */
1428 color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1429 color_table->colors[0] = nil;
1430 color_table->empty_indices = [[NSMutableSet alloc] init];
1433 /* do we already have this color ? */
1434 for (i = 1; i < color_table->avail; i++)
1435 if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1438 if ([color_table->empty_indices count] > 0)
1440 NSNumber *index = [color_table->empty_indices anyObject];
1441 [color_table->empty_indices removeObject: index];
1442 idx = [index unsignedLongValue];
1446 if (color_table->avail == color_table->size)
1447 color_table->colors =
1448 xpalloc (color_table->colors, &color_table->size, 1,
1449 min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1450 idx = color_table->avail++;
1453 color_table->colors[idx] = color;
1455 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1461 ns_free_indexed_color (unsigned long idx, struct frame *f)
1463 struct ns_color_table *color_table;
1470 color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1472 if (idx <= 0 || idx >= color_table->size) {
1473 message1 ("ns_free_indexed_color: Color index out of range.\n");
1477 index = [NSNumber numberWithUnsignedInt: idx];
1478 if ([color_table->empty_indices containsObject: index]) {
1479 message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1483 color = color_table->colors[idx];
1485 color_table->colors[idx] = nil;
1486 [color_table->empty_indices addObject: index];
1487 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1492 ns_get_color (const char *name, NSColor **col)
1493 /* --------------------------------------------------------------------------
1495 -------------------------------------------------------------------------- */
1496 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1497 X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1498 See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1501 static char hex[20];
1503 float r = -1.0, g, b;
1504 NSString *nsname = [NSString stringWithUTF8String: name];
1506 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1509 if ([nsname isEqualToString: @"ns_selection_color"])
1511 nsname = ns_selection_color;
1512 name = [ns_selection_color UTF8String];
1515 /* First, check for some sort of numeric specification. */
1518 if (name[0] == '0' || name[0] == '1' || name[0] == '.') /* RGB decimal */
1520 NSScanner *scanner = [NSScanner scannerWithString: nsname];
1521 [scanner scanFloat: &r];
1522 [scanner scanFloat: &g];
1523 [scanner scanFloat: &b];
1525 else if (!strncmp(name, "rgb:", 4)) /* A newer X11 format -- rgb:r/g/b */
1526 scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1527 else if (name[0] == '#') /* An old X11 format; convert to newer */
1529 int len = (strlen(name) - 1);
1530 int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1532 scaling = strlen(name+start) / 3;
1533 for (i = 0; i < 3; i++)
1534 sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1535 name + start + i * scaling);
1536 hex[3 * (scaling + 1) - 1] = '\0';
1542 float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1543 if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1553 *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1558 /* Otherwise, color is expected to be from a list */
1560 NSEnumerator *lenum, *cenum;
1564 #ifdef NS_IMPL_GNUSTEP
1565 /* XXX: who is wrong, the requestor or the implementation? */
1566 if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1568 nsname = @"highlightColor";
1571 lenum = [[NSColorList availableColorLists] objectEnumerator];
1572 while ( (clist = [lenum nextObject]) && new == nil)
1574 cenum = [[clist allKeys] objectEnumerator];
1575 while ( (name = [cenum nextObject]) && new == nil )
1577 if ([name compare: nsname
1578 options: NSCaseInsensitiveSearch] == NSOrderedSame )
1579 new = [clist colorWithKey: name];
1585 *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1592 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1593 /* --------------------------------------------------------------------------
1594 Convert a Lisp string object to a NS color
1595 -------------------------------------------------------------------------- */
1597 NSTRACE (ns_lisp_to_color);
1598 if (STRINGP (color))
1599 return ns_get_color (SSDATA (color), col);
1600 else if (SYMBOLP (color))
1601 return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1607 ns_color_to_lisp (NSColor *col)
1608 /* --------------------------------------------------------------------------
1609 Convert a color to a lisp string with the RGB equivalent
1610 -------------------------------------------------------------------------- */
1612 CGFloat red, green, blue, alpha, gray;
1615 NSTRACE (ns_color_to_lisp);
1618 if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1620 if ((str =[[col colorNameComponent] UTF8String]))
1623 return build_string ((char *)str);
1626 [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1627 getRed: &red green: &green blue: &blue alpha: &alpha];
1628 if (red ==green && red ==blue)
1630 [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1631 getWhite: &gray alpha: &alpha];
1632 snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1633 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1635 return build_string (buf);
1638 snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1639 lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1642 return build_string (buf);
1647 ns_query_color(void *col, XColor *color_def, int setPixel)
1648 /* --------------------------------------------------------------------------
1649 Get ARGB values out of NSColor col and put them into color_def.
1650 If setPixel, set the pixel to a concatenated version.
1651 and set color_def pixel to the resulting index.
1652 -------------------------------------------------------------------------- */
1656 [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1657 color_def->red = r * 65535;
1658 color_def->green = g * 65535;
1659 color_def->blue = b * 65535;
1661 if (setPixel == YES)
1663 = ARGB_TO_ULONG((int)(a*255),
1664 (int)(r*255), (int)(g*255), (int)(b*255));
1669 ns_defined_color (struct frame *f,
1674 /* --------------------------------------------------------------------------
1675 Return true if named color found, and set color_def rgb accordingly.
1676 If makeIndex and alloc are nonzero put the color in the color_table,
1677 and set color_def pixel to the resulting index.
1678 If makeIndex is zero, set color_def pixel to ARGB.
1679 Return false if not found
1680 -------------------------------------------------------------------------- */
1683 NSTRACE (ns_defined_color);
1686 if (ns_get_color (name, &col) != 0) /* Color not found */
1691 if (makeIndex && alloc)
1692 color_def->pixel = ns_index_color (col, f);
1693 ns_query_color (col, color_def, !makeIndex);
1700 ns_get_rgb_color (struct frame *f, float r, float g, float b, float a)
1701 /* --------------------------------------------------------------------------
1702 return an autoreleased RGB color
1703 -------------------------------------------------------------------------- */
1705 /*static int c = 1; fprintf (stderr, "color request %d\n", c++); */
1706 if (r < 0.0) r = 0.0;
1707 else if (r > 1.0) r = 1.0;
1708 if (g < 0.0) g = 0.0;
1709 else if (g > 1.0) g = 1.0;
1710 if (b < 0.0) b = 0.0;
1711 else if (b > 1.0) b = 1.0;
1712 if (a < 0.0) a = 0.0;
1713 else if (a > 1.0) a = 1.0;
1714 return (unsigned long) ns_index_color(
1715 [NSColor colorWithCalibratedRed: r green: g blue: b alpha: a], f);
1720 x_set_frame_alpha (struct frame *f)
1721 /* --------------------------------------------------------------------------
1722 change the entire-frame transparency
1723 -------------------------------------------------------------------------- */
1725 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1726 EmacsView *view = FRAME_NS_VIEW (f);
1728 double alpha_min = 1.0;
1730 if (dpyinfo->x_highlight_frame == f)
1731 alpha = f->alpha[0];
1733 alpha = f->alpha[1];
1735 if (FLOATP (Vframe_alpha_lower_limit))
1736 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1737 else if (INTEGERP (Vframe_alpha_lower_limit))
1738 alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1742 else if (1.0 < alpha)
1744 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1747 #ifdef NS_IMPL_COCOA
1748 [[view window] setAlphaValue: alpha];
1753 /* ==========================================================================
1757 ========================================================================== */
1761 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1762 /* --------------------------------------------------------------------------
1763 Programmatically reposition mouse pointer in pixel coordinates
1764 -------------------------------------------------------------------------- */
1766 NSTRACE (x_set_mouse_pixel_position);
1769 /* FIXME: this does not work, and what about GNUstep? */
1770 #ifdef NS_IMPL_COCOA
1771 [FRAME_NS_VIEW (f) lockFocus];
1772 PSsetmouse ((float)pix_x, (float)pix_y);
1773 [FRAME_NS_VIEW (f) unlockFocus];
1780 x_set_mouse_position (struct frame *f, int h, int v)
1781 /* --------------------------------------------------------------------------
1782 Programmatically reposition mouse pointer in character coordinates
1783 -------------------------------------------------------------------------- */
1787 pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1788 pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1790 if (pix_x < 0) pix_x = 0;
1791 if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1793 if (pix_y < 0) pix_y = 0;
1794 if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1796 x_set_mouse_pixel_position (f, pix_x, pix_y);
1801 note_mouse_movement (struct frame *frame, float x, float y)
1802 /* ------------------------------------------------------------------------
1803 Called by EmacsView on mouseMovement events. Passes on
1804 to emacs mainstream code if we moved off of a rect of interest
1805 known as last_mouse_glyph.
1806 ------------------------------------------------------------------------ */
1808 // NSTRACE (note_mouse_movement);
1810 XSETFRAME (last_mouse_motion_frame, frame);
1812 /* Note, this doesn't get called for enter/leave, since we don't have a
1813 position. Those are taken care of in the corresponding NSView methods. */
1815 /* has movement gone beyond last rect we were tracking? */
1816 if (x < last_mouse_glyph.origin.x ||
1817 x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1818 y < last_mouse_glyph.origin.y ||
1819 y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1821 ns_update_begin(frame);
1822 frame->mouse_moved = 1;
1823 note_mouse_highlight (frame, x, y);
1824 remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1825 ns_update_end(frame);
1834 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1835 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1837 /* --------------------------------------------------------------------------
1838 External (hook): inform emacs about mouse position and hit parts.
1839 If a scrollbar is being dragged, set bar_window, part, x, y, time.
1840 x & y should be position in the scrollbar (the whole bar, not the handle)
1841 and length of scrollbar respectively
1842 -------------------------------------------------------------------------- */
1846 Lisp_Object frame, tail;
1848 struct ns_display_info *dpyinfo;
1850 NSTRACE (ns_mouse_position);
1854 fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1858 dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1862 if (last_mouse_scroll_bar != nil && insist == 0)
1864 /* TODO: we do not use this path at the moment because drag events will
1865 go directly to the EmacsScroller. Leaving code in for now. */
1866 [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1868 if (time) *time = last_mouse_movement_time;
1869 last_mouse_scroll_bar = nil;
1873 /* Clear the mouse-moved flag for every frame on this display. */
1874 FOR_EACH_FRAME (tail, frame)
1875 if (FRAME_NS_P (XFRAME (frame))
1876 && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1877 XFRAME (frame)->mouse_moved = 0;
1879 last_mouse_scroll_bar = nil;
1880 if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1881 f = last_mouse_frame;
1883 f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1884 : SELECTED_FRAME ();
1886 if (f && FRAME_NS_P (f))
1888 view = FRAME_NS_VIEW (*fp);
1890 position = [[view window] mouseLocationOutsideOfEventStream];
1891 position = [view convertPoint: position fromView: nil];
1892 remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1893 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1895 if (bar_window) *bar_window = Qnil;
1896 if (part) *part = 0; /*scroll_bar_handle; */
1898 if (x) XSETINT (*x, lrint (position.x));
1899 if (y) XSETINT (*y, lrint (position.y));
1900 if (time) *time = last_mouse_movement_time;
1910 ns_frame_up_to_date (struct frame *f)
1911 /* --------------------------------------------------------------------------
1912 External (hook): Fix up mouse highlighting right after a full update.
1913 Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
1914 -------------------------------------------------------------------------- */
1916 NSTRACE (ns_frame_up_to_date);
1920 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1921 if (f == hlinfo->mouse_face_mouse_frame)
1925 if (hlinfo->mouse_face_mouse_frame)
1926 note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1927 hlinfo->mouse_face_mouse_x,
1928 hlinfo->mouse_face_mouse_y);
1937 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1938 /* --------------------------------------------------------------------------
1939 External (RIF): set frame mouse pointer type.
1940 -------------------------------------------------------------------------- */
1942 NSTRACE (ns_define_frame_cursor);
1943 if (FRAME_POINTER_TYPE (f) != cursor)
1945 EmacsView *view = FRAME_NS_VIEW (f);
1946 FRAME_POINTER_TYPE (f) = cursor;
1947 [[view window] invalidateCursorRectsForView: view];
1948 /* Redisplay assumes this function also draws the changed frame
1949 cursor, but this function doesn't, so do it explicitly. */
1950 x_update_cursor (f, 1);
1956 /* ==========================================================================
1960 ========================================================================== */
1964 ns_convert_key (unsigned code)
1965 /* --------------------------------------------------------------------------
1966 Internal call used by NSView-keyDown.
1967 -------------------------------------------------------------------------- */
1969 const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1970 / sizeof (convert_ns_to_X_keysym[0]));
1972 /* An array would be faster, but less easy to read. */
1973 for (keysym = 0; keysym < last_keysym; keysym += 2)
1974 if (code == convert_ns_to_X_keysym[keysym])
1975 return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1977 /* if decide to use keyCode and Carbon table, use this line:
1978 return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1983 x_get_keysym_name (int keysym)
1984 /* --------------------------------------------------------------------------
1985 Called by keyboard.c. Not sure if the return val is important, except
1987 -------------------------------------------------------------------------- */
1989 static char value[16];
1990 NSTRACE (x_get_keysym_name);
1991 sprintf (value, "%d", keysym);
1997 /* ==========================================================================
1999 Block drawing operations
2001 ========================================================================== */
2005 ns_redraw_scroll_bars (struct frame *f)
2009 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2010 NSTRACE (ns_redraw_scroll_bars);
2011 for (i =[subviews count]-1; i >= 0; i--)
2013 view = [subviews objectAtIndex: i];
2014 if (![view isKindOfClass: [EmacsScroller class]]) continue;
2021 ns_clear_frame (struct frame *f)
2022 /* --------------------------------------------------------------------------
2023 External (hook): Erase the entire frame
2024 -------------------------------------------------------------------------- */
2026 NSView *view = FRAME_NS_VIEW (f);
2029 NSTRACE (ns_clear_frame);
2031 /* comes on initial frame because we have
2032 after-make-frame-functions = select-frame */
2033 if (!FRAME_DEFAULT_FACE (f))
2036 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2038 output_cursor.hpos = output_cursor.vpos = 0;
2039 output_cursor.x = -1;
2044 ns_focus (f, &r, 1);
2045 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2049 /* as of 2006/11 or so this is now needed */
2050 ns_redraw_scroll_bars (f);
2056 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2057 /* --------------------------------------------------------------------------
2058 External (RIF): Clear section of frame
2059 -------------------------------------------------------------------------- */
2061 NSRect r = NSMakeRect (x, y, width, height);
2062 NSView *view = FRAME_NS_VIEW (f);
2063 struct face *face = FRAME_DEFAULT_FACE (f);
2068 NSTRACE (ns_clear_frame_area);
2070 r = NSIntersectionRect (r, [view frame]);
2071 ns_focus (f, &r, 1);
2072 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2082 ns_scroll_run (struct window *w, struct run *run)
2083 /* --------------------------------------------------------------------------
2084 External (RIF): Insert or delete n lines at line vpos
2085 -------------------------------------------------------------------------- */
2087 struct frame *f = XFRAME (w->frame);
2088 int x, y, width, height, from_y, to_y, bottom_y;
2090 NSTRACE (ns_scroll_run);
2092 /* begin copy from other terms */
2093 /* Get frame-relative bounding box of the text display area of W,
2094 without mode lines. Include in this box the left and right
2096 window_box (w, -1, &x, &y, &width, &height);
2098 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2099 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2100 bottom_y = y + height;
2104 /* Scrolling up. Make sure we don't copy part of the mode
2105 line at the bottom. */
2106 if (from_y + run->height > bottom_y)
2107 height = bottom_y - from_y;
2109 height = run->height;
2113 /* Scrolling down. Make sure we don't copy over the mode line.
2115 if (to_y + run->height > bottom_y)
2116 height = bottom_y - to_y;
2118 height = run->height;
2120 /* end copy from other terms */
2131 NSRect srcRect = NSMakeRect (x, from_y, width, height);
2132 NSRect dstRect = NSMakeRect (x, to_y, width, height);
2133 NSPoint dstOrigin = NSMakePoint (x, to_y);
2135 ns_focus (f, &dstRect, 1);
2136 NSCopyBits (0, srcRect , dstOrigin);
2145 ns_after_update_window_line (struct glyph_row *desired_row)
2146 /* --------------------------------------------------------------------------
2147 External (RIF): preparatory to fringe update after text was updated
2148 -------------------------------------------------------------------------- */
2150 struct window *w = updated_window;
2154 NSTRACE (ns_after_update_window_line);
2156 /* begin copy from other terms */
2159 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2160 desired_row->redraw_fringe_bitmaps_p = 1;
2162 /* When a window has disappeared, make sure that no rest of
2163 full-width rows stays visible in the internal border. */
2164 if (windows_or_buffers_changed
2165 && desired_row->full_width_p
2166 && (f = XFRAME (w->frame),
2167 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2169 && (height = desired_row->visible_height,
2172 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2175 ns_clear_frame_area (f, 0, y, width, height);
2176 ns_clear_frame_area (f,
2177 FRAME_PIXEL_WIDTH (f) - width,
2185 ns_shift_glyphs_for_insert (struct frame *f,
2186 int x, int y, int width, int height,
2188 /* --------------------------------------------------------------------------
2189 External (RIF): copy an area horizontally, don't worry about clearing src
2190 -------------------------------------------------------------------------- */
2192 NSRect srcRect = NSMakeRect (x, y, width, height);
2193 NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2194 NSPoint dstOrigin = dstRect.origin;
2196 NSTRACE (ns_shift_glyphs_for_insert);
2198 ns_focus (f, &dstRect, 1);
2199 NSCopyBits (0, srcRect, dstOrigin);
2205 /* ==========================================================================
2207 Character encoding and metrics
2209 ========================================================================== */
2213 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2214 /* --------------------------------------------------------------------------
2215 External (RIF); compute left/right overhang of whole string and set in s
2216 -------------------------------------------------------------------------- */
2218 struct font *font = s->font;
2222 struct font_metrics metrics;
2223 unsigned int codes[2];
2224 codes[0] = *(s->char2b);
2225 codes[1] = *(s->char2b + s->nchars - 1);
2227 font->driver->text_extents (font, codes, 2, &metrics);
2228 s->left_overhang = -metrics.lbearing;
2230 = metrics.rbearing > metrics.width
2231 ? metrics.rbearing - metrics.width : 0;
2235 s->left_overhang = 0;
2236 s->right_overhang = ((struct nsfont_info *)font)->ital ?
2237 FONT_HEIGHT (font) * 0.2 : 0;
2243 /* ==========================================================================
2245 Fringe and cursor drawing
2247 ========================================================================== */
2250 extern int max_used_fringe_bitmap;
2252 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2253 struct draw_fringe_bitmap_params *p)
2254 /* --------------------------------------------------------------------------
2255 External (RIF); fringe-related
2256 -------------------------------------------------------------------------- */
2258 struct frame *f = XFRAME (WINDOW_FRAME (w));
2259 struct face *face = p->face;
2261 static EmacsImage **bimgs = NULL;
2262 static int nBimgs = 0;
2264 /* grow bimgs if needed */
2265 if (nBimgs < max_used_fringe_bitmap)
2267 bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2268 memset (bimgs + nBimgs, 0,
2269 (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2270 nBimgs = max_used_fringe_bitmap;
2273 /* Must clip because of partially visible lines. */
2274 rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2275 ns_clip_to_row (w, row, -1, YES);
2279 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2281 /* If the fringe is adjacent to the left (right) scroll bar of a
2282 leftmost (rightmost, respectively) window, then extend its
2283 background to the gap between the fringe and the bar. */
2284 if ((WINDOW_LEFTMOST_P (w)
2285 && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2286 || (WINDOW_RIGHTMOST_P (w)
2287 && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2289 int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2293 int bar_area_x = WINDOW_SCROLL_BAR_AREA_X (w);
2294 int bar_area_width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2295 * FRAME_COLUMN_WIDTH (f));
2299 /* Bitmap fills the fringe. */
2300 if (bar_area_x + bar_area_width == p->x)
2301 bx = bar_area_x + sb_width;
2302 else if (p->x + p->wd == bar_area_x)
2306 int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2308 nx = bar_area_width - sb_width;
2309 by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2311 ny = row->visible_height;
2316 if (bar_area_x + bar_area_width == bx)
2318 bx = bar_area_x + sb_width;
2319 nx += bar_area_width - sb_width;
2321 else if (bx + nx == bar_area_x)
2322 nx += bar_area_width - sb_width;
2327 if (bx >= 0 && nx > 0)
2329 NSRect r = NSMakeRect (bx, by, nx, ny);
2331 [ns_lookup_indexed_color (face->background, f) set];
2338 NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2339 EmacsImage *img = bimgs[p->which - 1];
2343 unsigned short *bits = p->bits + p->dh;
2346 unsigned char *cbits = xmalloc (len);
2348 for (i = 0; i < len; i++)
2349 cbits[i] = ~(bits[i] & 0xff);
2350 img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2352 bimgs[p->which - 1] = img;
2357 /* Since we composite the bitmap instead of just blitting it, we need
2358 to erase the whole background. */
2359 [ns_lookup_indexed_color(face->background, f) set];
2361 [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2362 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2364 fromRect: NSZeroRect
2365 operation: NSCompositeSourceOver
2371 NSPoint pt = r.origin;
2373 [img compositeToPoint: pt operation: NSCompositeSourceOver];
2382 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2383 int x, int y, int cursor_type, int cursor_width,
2384 int on_p, int active_p)
2385 /* --------------------------------------------------------------------------
2386 External call (RIF): draw cursor.
2387 Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2388 -------------------------------------------------------------------------- */
2391 int fx, fy, h, cursor_height;
2392 struct frame *f = WINDOW_XFRAME (w);
2393 struct glyph *phys_cursor_glyph;
2395 struct glyph *cursor_glyph;
2397 NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2399 /* If cursor is out of bounds, don't draw garbage. This can happen
2400 in mini-buffer windows when switching between echo area glyphs
2403 NSTRACE (dumpcursor);
2408 w->phys_cursor_type = cursor_type;
2409 w->phys_cursor_on_p = on_p;
2411 if (cursor_type == NO_CURSOR)
2413 w->phys_cursor_width = 0;
2417 if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2419 if (glyph_row->exact_window_width_line_p
2420 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2422 glyph_row->cursor_in_fringe_p = 1;
2423 draw_fringe_bitmap (w, glyph_row, 0);
2428 /* We draw the cursor (with NSRectFill), then draw the glyph on top
2429 (other terminals do it the other way round). We must set
2430 w->phys_cursor_width to the cursor width. For bar cursors, that
2431 is CURSOR_WIDTH; for box cursors, it is the glyph width. */
2432 get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2434 /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2435 to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2436 if (cursor_type == BAR_CURSOR)
2438 if (cursor_width < 1)
2439 cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2440 w->phys_cursor_width = cursor_width;
2442 /* If we have an HBAR, "cursor_width" MAY specify height. */
2443 else if (cursor_type == HBAR_CURSOR)
2445 cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2446 fy += h - cursor_height;
2450 r.origin.x = fx, r.origin.y = fy;
2452 r.size.width = w->phys_cursor_width;
2454 /* TODO: only needed in rare cases with last-resort font in HELLO..
2455 should we do this more efficiently? */
2456 ns_clip_to_row (w, glyph_row, -1, NO); /* do ns_focus(f, &r, 1); if remove */
2459 face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2460 if (face && NS_FACE_BACKGROUND (face)
2461 == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2463 [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2464 hollow_color = FRAME_CURSOR_COLOR (f);
2467 [FRAME_CURSOR_COLOR (f) set];
2469 #ifdef NS_IMPL_COCOA
2470 /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2471 atomic. Cleaner ways of doing this should be investigated.
2472 One way would be to set a global variable DRAWING_CURSOR
2473 when making the call to draw_phys..(), don't focus in that
2474 case, then move the ns_unfocus() here after that call. */
2475 NSDisableScreenUpdates ();
2478 switch (cursor_type)
2482 case FILLED_BOX_CURSOR:
2485 case HOLLOW_BOX_CURSOR:
2488 NSRectFill (NSInsetRect (r, 1, 1));
2489 [FRAME_CURSOR_COLOR (f) set];
2496 /* If the character under cursor is R2L, draw the bar cursor
2497 on the right of its glyph, rather than on the left. */
2498 cursor_glyph = get_phys_cursor_glyph (w);
2499 if ((cursor_glyph->resolved_level & 1) != 0)
2500 s.origin.x += cursor_glyph->pixel_width - s.size.width;
2507 /* draw the character under the cursor */
2508 if (cursor_type != NO_CURSOR)
2509 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2511 #ifdef NS_IMPL_COCOA
2512 NSEnableScreenUpdates ();
2519 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2520 /* --------------------------------------------------------------------------
2521 External (RIF): Draw a vertical line.
2522 -------------------------------------------------------------------------- */
2524 struct frame *f = XFRAME (WINDOW_FRAME (w));
2526 NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2528 NSTRACE (ns_draw_vertical_window_border);
2530 face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2532 [ns_lookup_indexed_color(face->foreground, f) set];
2534 ns_focus (f, &r, 1);
2541 show_hourglass (struct atimer *timer)
2543 if (hourglass_shown_p)
2548 /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2550 hourglass_shown_p = 1;
2556 hide_hourglass (void)
2558 if (!hourglass_shown_p)
2563 /* TODO: remove NSProgressIndicator from all frames */
2565 hourglass_shown_p = 0;
2571 /* ==========================================================================
2573 Glyph drawing operations
2575 ========================================================================== */
2578 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2579 /* --------------------------------------------------------------------------
2580 Wrapper utility to account for internal border width on full-width lines,
2581 and allow top full-width rows to hit the frame top. nr should be pointer
2582 to two successive NSRects. Number of rects actually used is returned.
2583 -------------------------------------------------------------------------- */
2585 int n = get_glyph_string_clip_rects (s, nr, 2);
2589 /* --------------------------------------------------------------------
2590 Draw a wavy line under glyph string s. The wave fills wave_height
2597 wave_height = 3 | * * * *
2598 --------------------------------------------------------------------- */
2601 ns_draw_underwave (struct glyph_string *s, CGFloat width, CGFloat x)
2603 int wave_height = 3, wave_length = 2;
2604 int y, dx, dy, odd, xmax;
2609 dy = wave_height - 1;
2610 y = s->ybase - wave_height + 3;
2613 /* Find and set clipping rectangle */
2614 waveClip = NSMakeRect (x, y, width, wave_height);
2615 [[NSGraphicsContext currentContext] saveGraphicsState];
2616 NSRectClip (waveClip);
2618 /* Draw the waves */
2619 a.x = x - ((int)(x) % dx) + 0.5;
2621 odd = (int)(a.x/dx) % 2;
2622 a.y = b.y = y + 0.5;
2631 [NSBezierPath strokeLineFromPoint:a toPoint:b];
2632 a.x = b.x, a.y = b.y;
2633 b.x += dx, b.y = y + 0.5 + odd*dy;
2637 /* Restore previous clipping rectangle(s) */
2638 [[NSGraphicsContext currentContext] restoreGraphicsState];
2644 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2645 NSColor *defaultCol, CGFloat width, CGFloat x)
2646 /* --------------------------------------------------------------------------
2647 Draw underline, overline, and strike-through on glyph string s.
2648 -------------------------------------------------------------------------- */
2650 if (s->for_overlaps)
2654 if (face->underline_p)
2656 if (s->face->underline_type == FACE_UNDER_WAVE)
2658 if (face->underline_defaulted_p)
2661 [ns_lookup_indexed_color (face->underline_color, s->f) set];
2663 ns_draw_underwave (s, width, x);
2665 else if (s->face->underline_type == FACE_UNDER_LINE)
2669 unsigned long thickness, position;
2671 /* If the prev was underlined, match its appearance. */
2672 if (s->prev && s->prev->face->underline_p
2673 && s->prev->face->underline_type == FACE_UNDER_LINE
2674 && s->prev->underline_thickness > 0)
2676 thickness = s->prev->underline_thickness;
2677 position = s->prev->underline_position;
2682 unsigned long descent;
2685 descent = s->y + s->height - s->ybase;
2687 /* Use underline thickness of font, defaulting to 1. */
2688 thickness = (font && font->underline_thickness > 0)
2689 ? font->underline_thickness : 1;
2691 /* Determine the offset of underlining from the baseline. */
2692 if (x_underline_at_descent_line)
2693 position = descent - thickness;
2694 else if (x_use_underline_position_properties
2695 && font && font->underline_position >= 0)
2696 position = font->underline_position;
2698 position = lround (font->descent / 2);
2700 position = underline_minimum_offset;
2702 position = max (position, underline_minimum_offset);
2704 /* Ensure underlining is not cropped. */
2705 if (descent <= position)
2707 position = descent - 1;
2710 else if (descent < position + thickness)
2714 s->underline_thickness = thickness;
2715 s->underline_position = position;
2717 r = NSMakeRect (x, s->ybase + position, width, thickness);
2719 if (face->underline_defaulted_p)
2722 [ns_lookup_indexed_color (face->underline_color, s->f) set];
2726 /* Do overline. We follow other terms in using a thickness of 1
2727 and ignoring overline_margin. */
2728 if (face->overline_p)
2731 r = NSMakeRect (x, s->y, width, 1);
2733 if (face->overline_color_defaulted_p)
2736 [ns_lookup_indexed_color (face->overline_color, s->f) set];
2740 /* Do strike-through. We follow other terms for thickness and
2741 vertical position.*/
2742 if (face->strike_through_p)
2747 dy = lrint ((s->height - 1) / 2);
2748 r = NSMakeRect (x, s->y + dy, width, 1);
2750 if (face->strike_through_color_defaulted_p)
2753 [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2759 ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char right_p)
2760 /* --------------------------------------------------------------------------
2761 Draw an unfilled rect inside r, optionally leaving left and/or right open.
2762 Note we can't just use an NSDrawRect command, because of the possibility
2763 of some sides not being drawn, and because the rect will be filled.
2764 -------------------------------------------------------------------------- */
2770 s.size.height = thickness;
2772 s.origin.y += r.size.height - thickness;
2775 s.size.height = r.size.height;
2776 s.origin.y = r.origin.y;
2778 /* left, right (optional) */
2779 s.size.width = thickness;
2784 s.origin.x += r.size.width - thickness;
2791 ns_draw_relief (NSRect r, int thickness, char raised_p,
2792 char top_p, char bottom_p, char left_p, char right_p,
2793 struct glyph_string *s)
2794 /* --------------------------------------------------------------------------
2795 Draw a relief rect inside r, optionally leaving some sides open.
2796 Note we can't just use an NSDrawBezel command, because of the possibility
2797 of some sides not being drawn, and because the rect will be filled.
2798 -------------------------------------------------------------------------- */
2800 static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2801 NSColor *newBaseCol = nil;
2804 NSTRACE (ns_draw_relief);
2808 if (s->face->use_box_color_for_shadows_p)
2810 newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2812 /* else if (s->first_glyph->type == IMAGE_GLYPH
2814 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2816 newBaseCol = IMAGE_BACKGROUND (s->img, s->f, 0);
2820 newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2823 if (newBaseCol == nil)
2824 newBaseCol = [NSColor grayColor];
2826 if (newBaseCol != baseCol) /* TODO: better check */
2829 baseCol = [newBaseCol retain];
2831 lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2833 darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2836 [(raised_p ? lightCol : darkCol) set];
2838 /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2841 sr.size.height = thickness;
2842 if (top_p) NSRectFill (sr);
2845 sr.size.height = r.size.height;
2846 sr.size.width = thickness;
2847 if (left_p) NSRectFill (sr);
2849 [(raised_p ? darkCol : lightCol) set];
2852 sr.size.width = r.size.width;
2853 sr.size.height = thickness;
2854 sr.origin.y += r.size.height - thickness;
2855 if (bottom_p) NSRectFill (sr);
2858 sr.size.height = r.size.height;
2859 sr.origin.y = r.origin.y;
2860 sr.size.width = thickness;
2861 sr.origin.x += r.size.width - thickness;
2862 if (right_p) NSRectFill (sr);
2867 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2868 /* --------------------------------------------------------------------------
2869 Function modeled after x_draw_glyph_string_box ().
2870 Sets up parameters for drawing.
2871 -------------------------------------------------------------------------- */
2873 int right_x, last_x;
2874 char left_p, right_p;
2875 struct glyph *last_glyph;
2880 if (s->hl == DRAW_MOUSE_FACE)
2882 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2884 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2889 thickness = face->box_line_width;
2891 NSTRACE (ns_dumpglyphs_box_or_relief);
2893 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2894 ? WINDOW_RIGHT_EDGE_X (s->w)
2895 : window_box_right (s->w, s->area));
2896 last_glyph = (s->cmp || s->img
2897 ? s->first_glyph : s->first_glyph + s->nchars-1);
2899 right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2900 ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2902 left_p = (s->first_glyph->left_box_line_p
2903 || (s->hl == DRAW_MOUSE_FACE
2904 && (s->prev == NULL || s->prev->hl != s->hl)));
2905 right_p = (last_glyph->right_box_line_p
2906 || (s->hl == DRAW_MOUSE_FACE
2907 && (s->next == NULL || s->next->hl != s->hl)));
2909 r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2911 /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2912 if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2914 ns_draw_box (r, abs (thickness),
2915 ns_lookup_indexed_color (face->box_color, s->f),
2920 ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2921 1, 1, left_p, right_p, s);
2927 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2928 /* --------------------------------------------------------------------------
2929 Modeled after x_draw_glyph_string_background, which draws BG in
2930 certain cases. Others are left to the text rendering routine.
2931 -------------------------------------------------------------------------- */
2933 NSTRACE (ns_maybe_dumpglyphs_background);
2935 if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2937 int box_line_width = max (s->face->box_line_width, 0);
2938 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2939 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2942 if (s->hl == DRAW_MOUSE_FACE)
2944 face = FACE_FROM_ID (s->f,
2945 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2947 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2950 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2952 [(NS_FACE_BACKGROUND (face) != 0
2953 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2954 : FRAME_BACKGROUND_COLOR (s->f)) set];
2957 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2958 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2961 if (s->hl != DRAW_CURSOR)
2963 NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2964 s->background_width,
2965 s->height-2*box_line_width);
2969 s->background_filled_p = 1;
2976 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2977 /* --------------------------------------------------------------------------
2978 Renders an image and associated borders.
2979 -------------------------------------------------------------------------- */
2981 EmacsImage *img = s->img->pixmap;
2982 int box_line_vwidth = max (s->face->box_line_width, 0);
2983 int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2984 int bg_x, bg_y, bg_height;
2991 NSTRACE (ns_dumpglyphs_image);
2993 if (s->face->box != FACE_NO_BOX
2994 && s->first_glyph->left_box_line_p && s->slice.x == 0)
2995 x += abs (s->face->box_line_width);
2998 bg_y = s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2999 bg_height = s->height;
3000 /* other terms have this, but was causing problems w/tabbar mode */
3001 /* - 2 * box_line_vwidth; */
3003 if (s->slice.x == 0) x += s->img->hmargin;
3004 if (s->slice.y == 0) y += s->img->vmargin;
3006 /* Draw BG: if we need larger area than image itself cleared, do that,
3007 otherwise, since we composite the image under NS (instead of mucking
3008 with its background color), we must clear just the image area. */
3009 if (s->hl == DRAW_MOUSE_FACE)
3011 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3013 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3016 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3018 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3020 if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3021 || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3023 br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3024 s->background_filled_p = 1;
3028 br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3033 /* Draw the image.. do we need to draw placeholder if img ==nil? */
3036 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
3037 NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3038 NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3039 s->slice.width, s->slice.height);
3042 operation: NSCompositeSourceOver
3047 [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3048 operation: NSCompositeSourceOver];
3052 if (s->hl == DRAW_CURSOR)
3054 [FRAME_CURSOR_COLOR (s->f) set];
3055 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3056 tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3058 /* Currently on NS img->mask is always 0. Since
3059 get_window_cursor_type specifies a hollow box cursor when on
3060 a non-masked image we never reach this clause. But we put it
3061 in in anticipation of better support for image masks on
3063 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3067 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3070 /* Draw underline, overline, strike-through. */
3071 ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3073 /* Draw relief, if requested */
3074 if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3076 if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3078 th = tool_bar_button_relief >= 0 ?
3079 tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3080 raised_p = (s->hl == DRAW_IMAGE_RAISED);
3084 th = abs (s->img->relief);
3085 raised_p = (s->img->relief > 0);
3088 r.origin.x = x - th;
3089 r.origin.y = y - th;
3090 r.size.width = s->slice.width + 2*th-1;
3091 r.size.height = s->slice.height + 2*th-1;
3092 ns_draw_relief (r, th, raised_p,
3094 s->slice.y + s->slice.height == s->img->height,
3096 s->slice.x + s->slice.width == s->img->width, s);
3099 /* If there is no mask, the background won't be seen,
3100 so draw a rectangle on the image for the cursor.
3101 Do this for all images, getting transparency right is not reliable. */
3102 if (s->hl == DRAW_CURSOR)
3104 int thickness = abs (s->img->relief);
3105 if (thickness == 0) thickness = 1;
3106 ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3112 ns_dumpglyphs_stretch (struct glyph_string *s)
3117 NSColor *fgCol, *bgCol;
3119 if (!s->background_filled_p)
3121 n = ns_get_glyph_string_clip_rect (s, r);
3122 *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3124 ns_focus (s->f, r, n);
3126 if (s->hl == DRAW_MOUSE_FACE)
3128 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3130 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3133 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3135 bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3136 fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3138 for (i = 0; i < n; ++i)
3140 if (!s->row->full_width_p)
3142 int overrun, leftoverrun;
3144 /* truncate to avoid overwriting fringe and/or scrollbar */
3145 overrun = max (0, (s->x + s->background_width)
3146 - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3147 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3148 r[i].size.width -= overrun;
3150 /* truncate to avoid overwriting to left of the window box */
3151 leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3152 + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3154 if (leftoverrun > 0)
3156 r[i].origin.x += leftoverrun;
3157 r[i].size.width -= leftoverrun;
3160 /* XXX: Try to work between problem where a stretch glyph on
3161 a partially-visible bottom row will clear part of the
3162 modeline, and another where list-buffers headers and similar
3163 rows erroneously have visible_height set to 0. Not sure
3164 where this is coming from as other terms seem not to show. */
3165 r[i].size.height = min (s->height, s->row->visible_height);
3170 /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3171 overwriting cursor (usually when cursor on a tab) */
3172 if (s->hl == DRAW_CURSOR)
3177 width = s->w->phys_cursor_width;
3178 r[i].size.width -= width;
3179 r[i].origin.x += width;
3183 /* Draw overlining, etc. on the cursor. */
3184 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3185 ns_draw_text_decoration (s, face, bgCol, width, x);
3187 ns_draw_text_decoration (s, face, fgCol, width, x);
3194 /* Draw overlining, etc. on the stretch glyph (or the part
3195 of the stretch glyph after the cursor). */
3196 ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3200 s->background_filled_p = 1;
3206 ns_draw_glyph_string (struct glyph_string *s)
3207 /* --------------------------------------------------------------------------
3208 External (RIF): Main draw-text call.
3209 -------------------------------------------------------------------------- */
3211 /* TODO (optimize): focus for box and contents draw */
3214 char box_drawn_p = 0;
3216 NSTRACE (ns_draw_glyph_string);
3218 if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3221 struct glyph_string *next;
3223 for (width = 0, next = s->next;
3224 next && width < s->right_overhang;
3225 width += next->width, next = next->next)
3226 if (next->first_glyph->type != IMAGE_GLYPH)
3228 if (next->first_glyph->type != STRETCH_GLYPH)
3230 n = ns_get_glyph_string_clip_rect (s->next, r);
3231 ns_focus (s->f, r, n);
3232 ns_maybe_dumpglyphs_background (s->next, 1);
3237 ns_dumpglyphs_stretch (s->next);
3239 next->num_clips = 0;
3243 if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3244 && (s->first_glyph->type == CHAR_GLYPH
3245 || s->first_glyph->type == COMPOSITE_GLYPH))
3247 n = ns_get_glyph_string_clip_rect (s, r);
3248 ns_focus (s->f, r, n);
3249 ns_maybe_dumpglyphs_background (s, 1);
3250 ns_dumpglyphs_box_or_relief (s);
3255 switch (s->first_glyph->type)
3259 n = ns_get_glyph_string_clip_rect (s, r);
3260 ns_focus (s->f, r, n);
3261 ns_dumpglyphs_image (s, r[0]);
3266 ns_dumpglyphs_stretch (s);
3270 case COMPOSITE_GLYPH:
3271 n = ns_get_glyph_string_clip_rect (s, r);
3272 ns_focus (s->f, r, n);
3274 if (s->for_overlaps || (s->cmp_from > 0
3275 && ! s->first_glyph->u.cmp.automatic))
3276 s->background_filled_p = 1;
3278 ns_maybe_dumpglyphs_background
3279 (s, s->first_glyph->type == COMPOSITE_GLYPH);
3281 ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3282 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3283 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3284 NS_DUMPGLYPH_NORMAL));
3285 ns_tmp_font = (struct nsfont_info *)s->face->font;
3286 if (ns_tmp_font == NULL)
3287 ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
3289 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3291 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3292 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3293 NS_FACE_FOREGROUND (s->face) = tmp;
3296 ns_tmp_font->font.driver->draw
3297 (s, 0, s->nchars, s->x, s->y,
3298 (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3299 || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
3301 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3303 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3304 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3305 NS_FACE_FOREGROUND (s->face) = tmp;
3311 case GLYPHLESS_GLYPH:
3312 n = ns_get_glyph_string_clip_rect (s, r);
3313 ns_focus (s->f, r, n);
3315 if (s->for_overlaps || (s->cmp_from > 0
3316 && ! s->first_glyph->u.cmp.automatic))
3317 s->background_filled_p = 1;
3319 ns_maybe_dumpglyphs_background
3320 (s, s->first_glyph->type == COMPOSITE_GLYPH);
3322 /* Not yet implemented. */
3331 /* Draw box if not done already. */
3332 if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3334 n = ns_get_glyph_string_clip_rect (s, r);
3335 ns_focus (s->f, r, n);
3336 ns_dumpglyphs_box_or_relief (s);
3345 /* ==========================================================================
3349 ========================================================================== */
3353 ns_send_appdefined (int value)
3354 /* --------------------------------------------------------------------------
3355 Internal: post an appdefined event which EmacsApp-sendEvent will
3356 recognize and take as a command to halt the event loop.
3357 -------------------------------------------------------------------------- */
3359 /*NSTRACE (ns_send_appdefined); */
3361 /* Only post this event if we haven't already posted one. This will end
3362 the [NXApp run] main loop after having processed all events queued at
3364 if (send_appdefined)
3368 /* We only need one NX_APPDEFINED event to stop NXApp from running. */
3369 send_appdefined = NO;
3371 /* Don't need wakeup timer any more */
3374 [timed_entry invalidate];
3375 [timed_entry release];
3379 nxev = [NSEvent otherEventWithType: NSApplicationDefined
3380 location: NSMakePoint (0, 0)
3383 windowNumber: [[NSApp mainWindow] windowNumber]
3384 context: [NSApp context]
3389 /* Post an application defined event on the event queue. When this is
3390 received the [NXApp run] will return, thus having processed all
3391 events which are currently queued. */
3392 [NSApp postEvent: nxev atStart: NO];
3396 #ifdef HAVE_NATIVE_FS
3400 Lisp_Object frame, tail;
3402 if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3405 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3407 /* Clear the mouse-moved flag for every frame on this display. */
3408 FOR_EACH_FRAME (tail, frame)
3410 struct frame *f = XFRAME (frame);
3413 EmacsView *view = FRAME_NS_VIEW (f);
3414 [view updateCollectionBehaviour];
3421 ns_get_pending_menu_title ()
3423 return menu_pending_title;
3426 /* Check if menu open should be cancelled or continued as normal. */
3428 ns_check_menu_open (NSMenu *menu)
3430 /* GNUStep and OSX <= 10.4 does not have cancelTracking. */
3431 #if defined(NS_IMPL_COCOA) && \
3432 MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
3434 /* Click in menu bar? */
3435 NSArray *a = [[NSApp mainMenu] itemArray];
3438 for (i = 0; ! found && i < [a count]; i++)
3439 found = menu == [[a objectAtIndex:i] submenu];
3442 if (menu_will_open_state == MENU_NONE && emacs_event)
3444 NSEvent *theEvent = [NSApp currentEvent];
3445 struct frame *emacsframe = SELECTED_FRAME ();
3447 [menu cancelTracking];
3448 menu_will_open_state = MENU_PENDING;
3449 emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3450 EV_TRAILER (theEvent);
3452 CGEventRef ourEvent = CGEventCreate (NULL);
3453 menu_mouse_point = CGEventGetLocation (ourEvent);
3454 CFRelease (ourEvent);
3455 xfree (menu_pending_title);
3456 menu_pending_title = xstrdup ([[menu title] UTF8String]);
3458 else if (menu_will_open_state == MENU_OPENING)
3460 menu_will_open_state = MENU_NONE;
3466 /* Redo saved menu click if state is MENU_PENDING. */
3468 ns_check_pending_open_menu ()
3470 #ifdef NS_IMPL_COCOA
3471 if (menu_will_open_state == MENU_PENDING)
3473 CGEventSourceRef source
3474 = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3476 CGEventRef event = CGEventCreateMouseEvent (source,
3477 kCGEventLeftMouseDown,
3479 kCGMouseButtonLeft);
3480 CGEventSetType (event, kCGEventLeftMouseDown);
3481 CGEventPost (kCGHIDEventTap, event);
3485 menu_will_open_state = MENU_OPENING;
3492 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3493 /* --------------------------------------------------------------------------
3494 External (hook): Post an event to ourself and keep reading events until
3495 we read it back again. In effect process all events which were waiting.
3496 From 21+ we have to manage the event buffer ourselves.
3497 -------------------------------------------------------------------------- */
3499 struct input_event ev;
3502 /* NSTRACE (ns_read_socket); */
3504 #ifdef HAVE_NATIVE_FS
3508 if ([NSApp modalWindow] != nil)
3511 if (hold_event_q.nr > 0)
3514 for (i = 0; i < hold_event_q.nr; ++i)
3515 kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3516 hold_event_q.nr = 0;
3521 n_emacs_events_pending = 0;
3524 q_event_ptr = hold_quit;
3526 /* we manage autorelease pools by allocate/reallocate each time around
3527 the loop; strict nesting is occasionally violated but seems not to
3528 matter.. earlier methods using full nesting caused major memory leaks */
3529 [outerpool release];
3530 outerpool = [[NSAutoreleasePool alloc] init];
3532 /* If have pending open-file requests, attend to the next one of those. */
3533 if (ns_pending_files && [ns_pending_files count] != 0
3534 && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3536 [ns_pending_files removeObjectAtIndex: 0];
3538 /* Deal with pending service requests. */
3539 else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3541 NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3542 withArg: [ns_pending_service_args objectAtIndex: 0]])
3544 [ns_pending_service_names removeObjectAtIndex: 0];
3545 [ns_pending_service_args removeObjectAtIndex: 0];
3549 /* Run and wait for events. We must always send one NX_APPDEFINED event
3550 to ourself, otherwise [NXApp run] will never exit. */
3551 send_appdefined = YES;
3552 ns_send_appdefined (-1);
3554 if (++apploopnr != 1)
3562 nevents = n_emacs_events_pending;
3563 n_emacs_events_pending = 0;
3564 emacs_event = q_event_ptr = NULL;
3572 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3573 fd_set *exceptfds, EMACS_TIME *timeout, sigset_t *sigmask)
3574 /* --------------------------------------------------------------------------
3575 Replacement for select, checking for events
3576 -------------------------------------------------------------------------- */
3580 struct input_event event;
3583 /* NSTRACE (ns_select); */
3585 #ifdef HAVE_NATIVE_FS
3589 if (hold_event_q.nr > 0)
3591 /* We already have events pending. */
3597 for (k = 0; k < nfds+1; k++)
3599 if (readfds && FD_ISSET(k, readfds)) ++nr;
3600 if (writefds && FD_ISSET(k, writefds)) ++nr;
3604 || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3605 return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3607 [outerpool release];
3608 outerpool = [[NSAutoreleasePool alloc] init];
3611 send_appdefined = YES;
3614 pthread_mutex_lock (&select_mutex);
3619 select_readfds = *readfds;
3620 select_valid += SELECT_HAVE_READ;
3624 select_writefds = *writefds;
3625 select_valid += SELECT_HAVE_WRITE;
3630 select_timeout = *timeout;
3631 select_valid += SELECT_HAVE_TMO;
3634 pthread_mutex_unlock (&select_mutex);
3636 /* Inform fd_handler that select should be called */
3638 emacs_write (selfds[1], &c, 1);
3640 else if (nr == 0 && timeout)
3642 /* No file descriptor, just a timeout, no need to wake fd_handler */
3643 double time = EMACS_TIME_TO_DOUBLE (*timeout);
3644 timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3647 @selector (timeout_handler:)
3652 else /* No timeout and no file descriptors, can this happen? */
3654 /* Send appdefined so we exit from the loop */
3655 ns_send_appdefined (-1);
3660 emacs_event = &event;
3661 if (++apploopnr != 1)
3668 if (nr > 0 && readfds)
3671 emacs_write (selfds[1], &c, 1);
3675 t = last_appdefined_event_data;
3677 if (t != NO_APPDEFINED_DATA)
3679 last_appdefined_event_data = NO_APPDEFINED_DATA;
3683 /* The NX_APPDEFINED event we received was a timeout. */
3688 /* The NX_APPDEFINED event we received was the result of
3689 at least one real input event arriving. */
3695 /* Received back from select () in fd_handler; copy the results */
3696 pthread_mutex_lock (&select_mutex);
3697 if (readfds) *readfds = select_readfds;
3698 if (writefds) *writefds = select_writefds;
3699 if (timeout) *timeout = select_timeout;
3700 pthread_mutex_unlock (&select_mutex);
3715 /* ==========================================================================
3719 ========================================================================== */
3723 ns_set_vertical_scroll_bar (struct window *window,
3724 int portion, int whole, int position)
3725 /* --------------------------------------------------------------------------
3726 External (hook): Update or add scrollbar
3727 -------------------------------------------------------------------------- */
3731 struct frame *f = XFRAME (WINDOW_FRAME (window));
3732 EmacsView *view = FRAME_NS_VIEW (f);
3733 int window_y, window_height;
3734 int top, left, height, width, sb_width, sb_left;
3736 BOOL fringe_extended_p;
3738 /* optimization; display engine sends WAY too many of these.. */
3739 if (!NILP (window->vertical_scroll_bar))
3741 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3742 if ([bar checkSamePosition: position portion: portion whole: whole])
3744 if (view->scrollbarsNeedingUpdate == 0)
3746 if (!windows_or_buffers_changed)
3750 view->scrollbarsNeedingUpdate--;
3754 NSTRACE (ns_set_vertical_scroll_bar);
3756 /* Get dimensions. */
3757 window_box (window, -1, 0, &window_y, 0, &window_height);
3759 height = window_height;
3760 width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3761 left = WINDOW_SCROLL_BAR_AREA_X (window);
3763 /* allow for displaying a skinnier scrollbar than char area allotted */
3764 sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3765 WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3768 r = NSMakeRect (sb_left, top, sb_width, height);
3769 /* the parent view is flipped, so we need to flip y value */
3771 r.origin.y = (v.size.height - r.size.height - r.origin.y);
3773 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (window))
3774 fringe_extended_p = (WINDOW_LEFTMOST_P (window)
3775 && WINDOW_LEFT_FRINGE_WIDTH (window)
3776 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (window)
3777 || WINDOW_LEFT_MARGIN_COLS (window) == 0));
3779 fringe_extended_p = (WINDOW_RIGHTMOST_P (window)
3780 && WINDOW_RIGHT_FRINGE_WIDTH (window)
3781 && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (window)
3782 || WINDOW_RIGHT_MARGIN_COLS (window) == 0));
3784 XSETWINDOW (win, window);
3787 /* we want at least 5 lines to display a scrollbar */
3788 if (WINDOW_TOTAL_LINES (window) < 5)
3790 if (!NILP (window->vertical_scroll_bar))
3792 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3793 [bar removeFromSuperview];
3794 wset_vertical_scroll_bar (window, Qnil);
3796 ns_clear_frame_area (f, sb_left, top, width, height);
3801 if (NILP (window->vertical_scroll_bar))
3803 if (width > 0 && height > 0)
3805 if (fringe_extended_p)
3806 ns_clear_frame_area (f, sb_left, top, sb_width, height);
3808 ns_clear_frame_area (f, left, top, width, height);
3811 bar = [[EmacsScroller alloc] initFrame: r window: win];
3812 wset_vertical_scroll_bar (window, make_save_pointer (bar));
3817 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3818 oldRect = [bar frame];
3819 r.size.width = oldRect.size.width;
3820 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3822 if (oldRect.origin.x != r.origin.x)
3823 ns_clear_frame_area (f, sb_left, top, width, height);
3828 [bar setPosition: position portion: portion whole: whole];
3834 ns_condemn_scroll_bars (struct frame *f)
3835 /* --------------------------------------------------------------------------
3836 External (hook): arrange for all frame's scrollbars to be removed
3837 at next call to judge_scroll_bars, except for those redeemed.
3838 -------------------------------------------------------------------------- */
3842 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3844 NSTRACE (ns_condemn_scroll_bars);
3846 for (i =[subviews count]-1; i >= 0; i--)
3848 view = [subviews objectAtIndex: i];
3849 if ([view isKindOfClass: [EmacsScroller class]])
3856 ns_redeem_scroll_bar (struct window *window)
3857 /* --------------------------------------------------------------------------
3858 External (hook): arrange to spare this window's scrollbar
3859 at next call to judge_scroll_bars.
3860 -------------------------------------------------------------------------- */
3863 NSTRACE (ns_redeem_scroll_bar);
3864 if (!NILP (window->vertical_scroll_bar))
3866 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3873 ns_judge_scroll_bars (struct frame *f)
3874 /* --------------------------------------------------------------------------
3875 External (hook): destroy all scrollbars on frame that weren't
3876 redeemed after call to condemn_scroll_bars.
3877 -------------------------------------------------------------------------- */
3881 EmacsView *eview = FRAME_NS_VIEW (f);
3882 NSArray *subviews = [[eview superview] subviews];
3885 NSTRACE (ns_judge_scroll_bars);
3886 for (i = [subviews count]-1; i >= 0; --i)
3888 view = [subviews objectAtIndex: i];
3889 if (![view isKindOfClass: [EmacsScroller class]]) continue;
3895 [eview updateFrameSize: NO];
3900 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
3902 /* XXX irrelevant under NS */
3907 /* ==========================================================================
3911 ========================================================================== */
3914 x_display_pixel_height (struct ns_display_info *dpyinfo)
3916 NSScreen *screen = [NSScreen mainScreen];
3917 return [screen frame].size.height;
3921 x_display_pixel_width (struct ns_display_info *dpyinfo)
3923 NSScreen *screen = [NSScreen mainScreen];
3924 return [screen frame].size.width;
3928 static Lisp_Object ns_string_to_lispmod (const char *s)
3929 /* --------------------------------------------------------------------------
3930 Convert modifier name to lisp symbol
3931 -------------------------------------------------------------------------- */
3933 if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
3935 else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
3937 else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3939 else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
3941 else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
3943 else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
3951 ns_default (const char *parameter, Lisp_Object *result,
3952 Lisp_Object yesval, Lisp_Object noval,
3953 BOOL is_float, BOOL is_modstring)
3954 /* --------------------------------------------------------------------------
3955 Check a parameter value in user's preferences
3956 -------------------------------------------------------------------------- */
3958 const char *value = ns_get_defaults_value (parameter);
3964 if (c_strcasecmp (value, "YES") == 0)
3966 else if (c_strcasecmp (value, "NO") == 0)
3968 else if (is_float && (f = strtod (value, &pos), pos != value))
3969 *result = make_float (f);
3970 else if (is_modstring && value)
3971 *result = ns_string_to_lispmod (value);
3972 else fprintf (stderr,
3973 "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3979 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3980 /* --------------------------------------------------------------------------
3981 Initialize global info and storage for display.
3982 -------------------------------------------------------------------------- */
3984 NSScreen *screen = [NSScreen mainScreen];
3985 NSWindowDepth depth = [screen depth];
3986 Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
3988 dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3989 dpyinfo->resy = 72.27;
3990 dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3991 NSColorSpaceFromDepth (depth)]
3992 && ![NSCalibratedWhiteColorSpace isEqualToString:
3993 NSColorSpaceFromDepth (depth)];
3994 dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3995 dpyinfo->image_cache = make_image_cache ();
3996 dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
3997 dpyinfo->color_table->colors = NULL;
3998 dpyinfo->root_window = 42; /* a placeholder.. */
4000 hlinfo->mouse_face_mouse_frame = NULL;
4001 hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
4002 hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
4003 hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
4004 hlinfo->mouse_face_window = hlinfo->mouse_face_overlay = Qnil;
4005 hlinfo->mouse_face_hidden = 0;
4007 hlinfo->mouse_face_mouse_x = hlinfo->mouse_face_mouse_y = 0;
4008 hlinfo->mouse_face_defer = 0;
4010 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4012 dpyinfo->n_fonts = 0;
4013 dpyinfo->smallest_font_height = 1;
4014 dpyinfo->smallest_char_width = 1;
4018 /* This and next define (many of the) public functions in this file. */
4019 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4020 with using despite presence in the "system dependent" redisplay
4021 interface. In addition, many of the ns_ methods have code that is
4022 shared with all terms, indicating need for further refactoring. */
4023 extern frame_parm_handler ns_frame_parm_handlers[];
4024 static struct redisplay_interface ns_redisplay_interface =
4026 ns_frame_parm_handlers,
4030 x_clear_end_of_line,
4032 ns_after_update_window_line,
4033 ns_update_window_begin,
4034 ns_update_window_end,
4037 0, /* flush_display_optional */
4038 x_clear_window_mouse_face,
4039 x_get_glyph_overhangs,
4040 x_fix_overlapping_area,
4041 ns_draw_fringe_bitmap,
4042 0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4043 0, /* destroy_fringe_bitmap */
4044 ns_compute_glyph_string_overhangs,
4045 ns_draw_glyph_string, /* interface to nsfont.m */
4046 ns_define_frame_cursor,
4047 ns_clear_frame_area,
4048 ns_draw_window_cursor,
4049 ns_draw_vertical_window_border,
4050 ns_shift_glyphs_for_insert
4055 ns_delete_display (struct ns_display_info *dpyinfo)
4061 /* This function is called when the last frame on a display is deleted. */
4063 ns_delete_terminal (struct terminal *terminal)
4065 struct ns_display_info *dpyinfo = terminal->display_info.ns;
4067 /* Protect against recursive calls. delete_frame in
4068 delete_terminal calls us back when it deletes our last frame. */
4069 if (!terminal->name)
4074 x_destroy_all_bitmaps (dpyinfo);
4075 ns_delete_display (dpyinfo);
4080 static struct terminal *
4081 ns_create_terminal (struct ns_display_info *dpyinfo)
4082 /* --------------------------------------------------------------------------
4083 Set up use of NS before we make the first connection.
4084 -------------------------------------------------------------------------- */
4086 struct terminal *terminal;
4088 NSTRACE (ns_create_terminal);
4090 terminal = create_terminal ();
4092 terminal->type = output_ns;
4093 terminal->display_info.ns = dpyinfo;
4094 dpyinfo->terminal = terminal;
4096 terminal->rif = &ns_redisplay_interface;
4098 terminal->clear_frame_hook = ns_clear_frame;
4099 terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
4100 terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
4101 terminal->ring_bell_hook = ns_ring_bell;
4102 terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
4103 terminal->set_terminal_modes_hook = ns_set_terminal_modes;
4104 terminal->update_begin_hook = ns_update_begin;
4105 terminal->update_end_hook = ns_update_end;
4106 terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
4107 terminal->read_socket_hook = ns_read_socket;
4108 terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4109 terminal->mouse_position_hook = ns_mouse_position;
4110 terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4111 terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4113 terminal->fullscreen_hook = ns_fullscreen_hook;
4115 terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4116 terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4117 terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4118 terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4120 terminal->delete_frame_hook = x_destroy_window;
4121 terminal->delete_terminal_hook = ns_delete_terminal;
4123 terminal->scroll_region_ok = 1;
4124 terminal->char_ins_del_ok = 1;
4125 terminal->line_ins_del_ok = 1;
4126 terminal->fast_clear_end_of_line = 1;
4127 terminal->memory_below_frame = 0;
4133 struct ns_display_info *
4134 ns_term_init (Lisp_Object display_name)
4135 /* --------------------------------------------------------------------------
4136 Start the Application and get things rolling.
4137 -------------------------------------------------------------------------- */
4139 struct terminal *terminal;
4140 struct ns_display_info *dpyinfo;
4141 static int ns_initialized = 0;
4144 if (ns_initialized) return x_display_list;
4147 NSTRACE (ns_term_init);
4149 [outerpool release];
4150 outerpool = [[NSAutoreleasePool alloc] init];
4152 /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4153 /*GSDebugAllocationActive (YES); */
4157 Fset_input_interrupt_mode (Qnil);
4159 if (selfds[0] == -1)
4161 if (pipe (selfds) == -1)
4163 fprintf (stderr, "Failed to create pipe: %s\n",
4164 emacs_strerror (errno));
4168 fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4169 FD_ZERO (&select_readfds);
4170 FD_ZERO (&select_writefds);
4171 pthread_mutex_init (&select_mutex, NULL);
4174 ns_pending_files = [[NSMutableArray alloc] init];
4175 ns_pending_service_names = [[NSMutableArray alloc] init];
4176 ns_pending_service_args = [[NSMutableArray alloc] init];
4178 /* Start app and create the main menu, window, view.
4179 Needs to be here because ns_initialize_display_info () uses AppKit classes.
4180 The view will then ask the NSApp to stop and return to Emacs. */
4181 [EmacsApp sharedApplication];
4184 [NSApp setDelegate: NSApp];
4186 /* Start the select thread. */
4187 [NSThread detachNewThreadSelector:@selector (fd_handler:)
4191 /* debugging: log all notifications */
4192 /* [[NSNotificationCenter defaultCenter] addObserver: NSApp
4193 selector: @selector (logNotification:)
4194 name: nil object: nil]; */
4196 dpyinfo = xzalloc (sizeof *dpyinfo);
4198 ns_initialize_display_info (dpyinfo);
4199 terminal = ns_create_terminal (dpyinfo);
4201 terminal->kboard = xmalloc (sizeof *terminal->kboard);
4202 init_kboard (terminal->kboard);
4203 kset_window_system (terminal->kboard, Qns);
4204 terminal->kboard->next_kboard = all_kboards;
4205 all_kboards = terminal->kboard;
4206 /* Don't let the initial kboard remain current longer than necessary.
4207 That would cause problems if a file loaded on startup tries to
4208 prompt in the mini-buffer. */
4209 if (current_kboard == initial_kboard)
4210 current_kboard = terminal->kboard;
4211 terminal->kboard->reference_count++;
4213 dpyinfo->next = x_display_list;
4214 x_display_list = dpyinfo;
4216 /* Put it on ns_display_name_list */
4217 ns_display_name_list = Fcons (Fcons (display_name, Qnil),
4218 ns_display_name_list);
4219 dpyinfo->name_list_element = XCAR (ns_display_name_list);
4221 terminal->name = xstrdup (SSDATA (display_name));
4225 if (!inhibit_x_resources)
4227 ns_default ("GSFontAntiAlias", &ns_antialias_text,
4230 /* this is a standard variable */
4231 ns_default ("AppleAntiAliasingThreshold", &tmp,
4232 make_float (10.0), make_float (6.0), YES, NO);
4233 ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4236 ns_selection_color = [[NSUserDefaults standardUserDefaults]
4237 stringForKey: @"AppleHighlightColor"];
4238 if (ns_selection_color == nil)
4239 ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
4242 NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4246 Lisp_Object color_file, color_map, color;
4250 color_file = Fexpand_file_name (build_string ("rgb.txt"),
4251 Fsymbol_value (intern ("data-directory")));
4253 color_map = Fx_load_color_file (color_file);
4254 if (NILP (color_map))
4255 fatal ("Could not read %s.\n", SDATA (color_file));
4257 cl = [[NSColorList alloc] initWithName: @"Emacs"];
4258 for ( ; CONSP (color_map); color_map = XCDR (color_map))
4260 color = XCAR (color_map);
4261 name = SSDATA (XCAR (color));
4262 c = XINT (XCDR (color));
4264 [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4265 green: GREEN_FROM_ULONG (c) / 255.0
4266 blue: BLUE_FROM_ULONG (c) / 255.0
4268 forKey: [NSString stringWithUTF8String: name]];
4270 [cl writeToFile: nil];
4275 #ifdef NS_IMPL_GNUSTEP
4276 Vwindow_system_version = build_string (gnustep_base_version);
4278 /*PSnextrelease (128, c); */
4279 char c[DBL_BUFSIZE_BOUND];
4280 int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4281 Vwindow_system_version = make_unibyte_string (c, len);
4285 delete_keyboard_wait_descriptor (0);
4287 ns_app_name = [[NSProcessInfo processInfo] processName];
4289 /* Set up OS X app menu */
4290 #ifdef NS_IMPL_COCOA
4294 /* set up the application menu */
4295 svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4296 [svcsMenu setAutoenablesItems: NO];
4297 appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4298 [appMenu setAutoenablesItems: NO];
4299 mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4300 dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4302 [appMenu insertItemWithTitle: @"About Emacs"
4303 action: @selector (orderFrontStandardAboutPanel:)
4306 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4307 [appMenu insertItemWithTitle: @"Preferences..."
4308 action: @selector (showPreferencesWindow:)
4311 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4312 item = [appMenu insertItemWithTitle: @"Services"
4313 action: @selector (menuDown:)
4316 [appMenu setSubmenu: svcsMenu forItem: item];
4317 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4318 [appMenu insertItemWithTitle: @"Hide Emacs"
4319 action: @selector (hide:)
4322 item = [appMenu insertItemWithTitle: @"Hide Others"
4323 action: @selector (hideOtherApplications:)
4326 [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4327 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4328 [appMenu insertItemWithTitle: @"Quit Emacs"
4329 action: @selector (terminate:)
4333 item = [mainMenu insertItemWithTitle: ns_app_name
4334 action: @selector (menuDown:)
4337 [mainMenu setSubmenu: appMenu forItem: item];
4338 [dockMenu insertItemWithTitle: @"New Frame"
4339 action: @selector (newFrame:)
4343 [NSApp setMainMenu: mainMenu];
4344 [NSApp setAppleMenu: appMenu];
4345 [NSApp setServicesMenu: svcsMenu];
4346 /* Needed at least on Cocoa, to get dock menu to show windows */
4347 [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4349 [[NSNotificationCenter defaultCenter]
4350 addObserver: mainMenu
4351 selector: @selector (trackingNotification:)
4352 name: NSMenuDidBeginTrackingNotification object: mainMenu];
4353 [[NSNotificationCenter defaultCenter]
4354 addObserver: mainMenu
4355 selector: @selector (trackingNotification:)
4356 name: NSMenuDidEndTrackingNotification object: mainMenu];
4358 #endif /* MAC OS X menu setup */
4360 /* Register our external input/output types, used for determining
4361 applicable services and also drag/drop eligibility. */
4362 ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4363 ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4365 ns_drag_types = [[NSArray arrayWithObjects:
4367 NSTabularTextPboardType,
4368 NSFilenamesPboardType,
4371 NSFontPboardType, nil] retain];
4373 /* If fullscreen is in init/default-frame-alist, focus isn't set
4374 right for fullscreen windows, so set this. */
4375 [NSApp activateIgnoringOtherApps:YES];
4378 ns_do_open_file = YES;
4384 ns_term_shutdown (int sig)
4386 [[NSUserDefaults standardUserDefaults] synchronize];
4388 /* code not reached in emacs.c after this is called by shut_down_emacs: */
4389 if (STRINGP (Vauto_save_list_file_name))
4390 unlink (SSDATA (Vauto_save_list_file_name));
4392 if (sig == 0 || sig == SIGTERM)
4394 [NSApp terminate: NSApp];
4396 else // force a stack trace to happen
4403 /* ==========================================================================
4405 EmacsApp implementation
4407 ========================================================================== */
4410 @implementation EmacsApp
4412 - (void)logNotification: (NSNotification *)notification
4414 const char *name = [[notification name] UTF8String];
4415 if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4416 && !strstr (name, "WindowNumber"))
4417 NSLog (@"notification: '%@'", [notification name]);
4421 - (void)sendEvent: (NSEvent *)theEvent
4422 /* --------------------------------------------------------------------------
4423 Called when NSApp is running for each event received. Used to stop
4424 the loop when we choose, since there's no way to just run one iteration.
4425 -------------------------------------------------------------------------- */
4427 int type = [theEvent type];
4428 NSWindow *window = [theEvent window];
4429 /* NSTRACE (sendEvent); */
4430 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4432 #ifdef NS_IMPL_COCOA
4433 if (type == NSApplicationDefined
4434 && [theEvent data2] == NSAPP_DATA2_RUNASSCRIPT)
4442 if (type == NSCursorUpdate && window == nil)
4444 fprintf (stderr, "Dropping external cursor update event.\n");
4448 if (type == NSApplicationDefined)
4450 /* Events posted by ns_send_appdefined interrupt the run loop here.
4451 But, if a modal window is up, an appdefined can still come through,
4452 (e.g., from a makeKeyWindow event) but stopping self also stops the
4453 modal loop. Just defer it until later. */
4454 if ([NSApp modalWindow] == nil)
4456 last_appdefined_event_data = [theEvent data1];
4461 send_appdefined = YES;
4465 [super sendEvent: theEvent];
4469 - (void)showPreferencesWindow: (id)sender
4471 struct frame *emacsframe = SELECTED_FRAME ();
4472 NSEvent *theEvent = [NSApp currentEvent];
4476 emacs_event->kind = NS_NONKEY_EVENT;
4477 emacs_event->code = KEY_NS_SHOW_PREFS;
4478 emacs_event->modifiers = 0;
4479 EV_TRAILER (theEvent);
4483 - (void)newFrame: (id)sender
4485 struct frame *emacsframe = SELECTED_FRAME ();
4486 NSEvent *theEvent = [NSApp currentEvent];
4490 emacs_event->kind = NS_NONKEY_EVENT;
4491 emacs_event->code = KEY_NS_NEW_FRAME;
4492 emacs_event->modifiers = 0;
4493 EV_TRAILER (theEvent);
4497 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4498 - (BOOL) openFile: (NSString *)fileName
4500 struct frame *emacsframe = SELECTED_FRAME ();
4501 NSEvent *theEvent = [NSApp currentEvent];
4506 emacs_event->kind = NS_NONKEY_EVENT;
4507 emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4508 ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4509 ns_input_line = Qnil; /* can be start or cons start,end */
4510 emacs_event->modifiers =0;
4511 EV_TRAILER (theEvent);
4517 /* **************************************************************************
4519 EmacsApp delegate implementation
4521 ************************************************************************** */
4523 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4524 /* --------------------------------------------------------------------------
4525 When application is loaded, terminate event loop in ns_term_init
4526 -------------------------------------------------------------------------- */
4528 NSTRACE (applicationDidFinishLaunching);
4529 [NSApp setServicesProvider: NSApp];
4530 ns_send_appdefined (-2);
4534 /* Termination sequences:
4537 MenuBar | File | Exit:
4538 Select Quit from App menubar:
4540 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4543 Select Quit from Dock menu:
4546 Cancel -> Nothing else
4550 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4555 - (void) terminate: (id)sender
4557 struct frame *emacsframe = SELECTED_FRAME ();
4562 emacs_event->kind = NS_NONKEY_EVENT;
4563 emacs_event->code = KEY_NS_POWER_OFF;
4564 emacs_event->arg = Qt; /* mark as non-key event */
4565 EV_TRAILER ((id)nil);
4569 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4573 if (NILP (ns_confirm_quit)) // || ns_shutdown_properly --> TO DO
4574 return NSTerminateNow;
4576 ret = NSRunAlertPanel(ns_app_name,
4577 @"Exit requested. Would you like to Save Buffers and Exit, or Cancel the request?",
4578 @"Save Buffers and Exit", @"Cancel", nil);
4580 if (ret == NSAlertDefaultReturn)
4581 return NSTerminateNow;
4582 else if (ret == NSAlertAlternateReturn)
4583 return NSTerminateCancel;
4584 return NSTerminateNow; /* just in case */
4588 not_in_argv (NSString *arg)
4591 const char *a = [arg UTF8String];
4592 for (k = 1; k < initial_argc; ++k)
4593 if (strcmp (a, initial_argv[k]) == 0) return 0;
4597 /* Notification from the Workspace to open a file */
4598 - (BOOL)application: sender openFile: (NSString *)file
4600 if (ns_do_open_file || not_in_argv (file))
4601 [ns_pending_files addObject: file];
4606 /* Open a file as a temporary file */
4607 - (BOOL)application: sender openTempFile: (NSString *)file
4609 if (ns_do_open_file || not_in_argv (file))
4610 [ns_pending_files addObject: file];
4615 /* Notification from the Workspace to open a file noninteractively (?) */
4616 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4618 if (ns_do_open_file || not_in_argv (file))
4619 [ns_pending_files addObject: file];
4623 /* Notification from the Workspace to open multiple files */
4624 - (void)application: sender openFiles: (NSArray *)fileList
4626 NSEnumerator *files = [fileList objectEnumerator];
4628 /* Don't open files from the command line unconditionally,
4629 Cocoa parses the command line wrong, --option value tries to open value
4630 if --option is the last option. */
4631 while ((file = [files nextObject]) != nil)
4632 if (ns_do_open_file || not_in_argv (file))
4633 [ns_pending_files addObject: file];
4635 [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4640 /* Handle dock menu requests. */
4641 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4647 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4648 - (void)applicationWillBecomeActive: (NSNotification *)notification
4650 //ns_app_active=YES;
4652 - (void)applicationDidBecomeActive: (NSNotification *)notification
4654 NSTRACE (applicationDidBecomeActive);
4656 //ns_app_active=YES;
4658 ns_update_auto_hide_menu_bar ();
4659 // No constraining takes place when the application is not active.
4660 ns_constrain_all_frames ();
4662 - (void)applicationDidResignActive: (NSNotification *)notification
4665 ns_send_appdefined (-1);
4670 /* ==========================================================================
4672 EmacsApp aux handlers for managing event loop
4674 ========================================================================== */
4677 - (void)timeout_handler: (NSTimer *)timedEntry
4678 /* --------------------------------------------------------------------------
4679 The timeout specified to ns_select has passed.
4680 -------------------------------------------------------------------------- */
4682 /*NSTRACE (timeout_handler); */
4683 ns_send_appdefined (-2);
4686 - (void)fd_handler:(id)unused
4687 /* --------------------------------------------------------------------------
4688 Check data waiting on file descriptors and terminate if so
4689 -------------------------------------------------------------------------- */
4692 int waiting = 1, nfds;
4695 SELECT_TYPE readfds, writefds, *wfds;
4696 EMACS_TIME timeout, *tmo;
4697 NSAutoreleasePool *pool = nil;
4699 /* NSTRACE (fd_handler); */
4704 pool = [[NSAutoreleasePool alloc] init];
4710 FD_SET (selfds[0], &fds);
4711 result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
4712 if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
4717 pthread_mutex_lock (&select_mutex);
4720 if (select_valid & SELECT_HAVE_READ)
4721 readfds = select_readfds;
4725 if (select_valid & SELECT_HAVE_WRITE)
4727 writefds = select_writefds;
4732 if (select_valid & SELECT_HAVE_TMO)
4734 timeout = select_timeout;
4740 pthread_mutex_unlock (&select_mutex);
4742 FD_SET (selfds[0], &readfds);
4743 if (selfds[0] >= nfds) nfds = selfds[0]+1;
4745 result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
4748 ns_send_appdefined (-2);
4749 else if (result > 0)
4751 if (FD_ISSET (selfds[0], &readfds))
4753 if (read (selfds[0], &c, 1) == 1 && c == 's')
4758 pthread_mutex_lock (&select_mutex);
4759 if (select_valid & SELECT_HAVE_READ)
4760 select_readfds = readfds;
4761 if (select_valid & SELECT_HAVE_WRITE)
4762 select_writefds = writefds;
4763 if (select_valid & SELECT_HAVE_TMO)
4764 select_timeout = timeout;
4765 pthread_mutex_unlock (&select_mutex);
4767 ns_send_appdefined (result);
4777 /* ==========================================================================
4781 ========================================================================== */
4783 /* called from system: queue for next pass through event loop */
4784 - (void)requestService: (NSPasteboard *)pboard
4785 userData: (NSString *)userData
4786 error: (NSString **)error
4788 [ns_pending_service_names addObject: userData];
4789 [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4790 SSDATA (ns_string_from_pasteboard (pboard))]];
4794 /* called from ns_read_socket to clear queue */
4795 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4797 struct frame *emacsframe = SELECTED_FRAME ();
4798 NSEvent *theEvent = [NSApp currentEvent];
4803 emacs_event->kind = NS_NONKEY_EVENT;
4804 emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4805 ns_input_spi_name = build_string ([name UTF8String]);
4806 ns_input_spi_arg = build_string ([arg UTF8String]);
4807 emacs_event->modifiers = EV_MODIFIERS (theEvent);
4808 EV_TRAILER (theEvent);
4818 /* ==========================================================================
4820 EmacsView implementation
4822 ========================================================================== */
4825 @implementation EmacsView
4827 /* needed to inform when window closed from LISP */
4828 - (void) setWindowClosing: (BOOL)closing
4830 windowClosing = closing;
4836 NSTRACE (EmacsView_dealloc);
4838 if (fs_state == FULLSCREEN_BOTH)
4839 [nonfs_window release];
4844 /* called on font panel selection */
4845 - (void)changeFont: (id)sender
4847 NSEvent *e =[[self window] currentEvent];
4848 struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4852 NSTRACE (changeFont);
4856 if ((newFont = [sender convertFont:
4857 ((struct nsfont_info *)face->font)->nsfont]))
4859 SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4861 emacs_event->kind = NS_NONKEY_EVENT;
4862 emacs_event->modifiers = 0;
4863 emacs_event->code = KEY_NS_CHANGE_FONT;
4865 size = [newFont pointSize];
4866 ns_input_fontsize = make_number (lrint (size));
4867 ns_input_font = build_string ([[newFont familyName] UTF8String]);
4873 - (BOOL)acceptsFirstResponder
4875 NSTRACE (acceptsFirstResponder);
4880 - (void)resetCursorRects
4882 NSRect visible = [self visibleRect];
4883 NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4884 NSTRACE (resetCursorRects);
4886 if (currentCursor == nil)
4887 currentCursor = [NSCursor arrowCursor];
4889 if (!NSIsEmptyRect (visible))
4890 [self addCursorRect: visible cursor: currentCursor];
4891 [currentCursor setOnMouseEntered: YES];
4896 /*****************************************************************************/
4897 /* Keyboard handling. */
4900 - (void)keyDown: (NSEvent *)theEvent
4902 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4904 unsigned fnKeysym = 0;
4905 static NSMutableArray *nsEvArray;
4906 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4907 static BOOL firstTime = YES;
4910 unsigned int flags = [theEvent modifierFlags];
4914 /* Rhapsody and OS X give up and down events for the arrow keys */
4915 if (ns_fake_keydown == YES)
4916 ns_fake_keydown = NO;
4917 else if ([theEvent type] != NSKeyDown)
4923 if (![[self window] isKeyWindow]
4924 && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4925 /* we must avoid an infinite loop here. */
4926 && (EmacsView *)[[theEvent window] delegate] != self)
4928 /* XXX: There is an occasional condition in which, when Emacs display
4929 updates a different frame from the current one, and temporarily
4930 selects it, then processes some interrupt-driven input
4931 (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4932 for some reason that window has its first responder set to the NSView
4933 most recently updated (I guess), which is not the correct one. */
4934 [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4938 if (nsEvArray == nil)
4939 nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4941 [NSCursor setHiddenUntilMouseMoves: YES];
4943 if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4945 clear_mouse_face (hlinfo);
4946 hlinfo->mouse_face_hidden = 1;
4949 if (!processingCompose)
4951 /* When using screen sharing, no left or right information is sent,
4952 so use Left key in those cases. */
4953 int is_left_key, is_right_key;
4955 code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4956 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4958 /* (Carbon way: [theEvent keyCode]) */
4960 /* is it a "function key"? */
4961 fnKeysym = (code < 0x00ff && (flags&NSNumericPadKeyMask))
4962 ? ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask)
4963 : ns_convert_key (code);
4967 /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4968 because Emacs treats Delete and KP-Delete same (in simple.el). */
4969 if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4970 code = 0xFF08; /* backspace */
4975 /* are there modifiers? */
4976 emacs_event->modifiers = 0;
4978 if (flags & NSHelpKeyMask)
4979 emacs_event->modifiers |= hyper_modifier;
4981 if (flags & NSShiftKeyMask)
4982 emacs_event->modifiers |= shift_modifier;
4984 is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
4985 is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
4986 || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
4989 emacs_event->modifiers |= parse_solitary_modifier
4990 (EQ (ns_right_command_modifier, Qleft)
4991 ? ns_command_modifier
4992 : ns_right_command_modifier);
4996 emacs_event->modifiers |= parse_solitary_modifier
4997 (ns_command_modifier);
4999 /* if super (default), take input manager's word so things like
5000 dvorak / qwerty layout work */
5001 if (EQ (ns_command_modifier, Qsuper)
5003 && [[theEvent characters] length] != 0)
5005 /* XXX: the code we get will be unshifted, so if we have
5006 a shift modifier, must convert ourselves */
5007 if (!(flags & NSShiftKeyMask))
5008 code = [[theEvent characters] characterAtIndex: 0];
5010 /* this is ugly and also requires linking w/Carbon framework
5011 (for LMGetKbdType) so for now leave this rare (?) case
5012 undealt with.. in future look into CGEvent methods */
5015 long smv = GetScriptManagerVariable (smKeyScript);
5016 Handle uchrHandle = GetResource
5017 ('uchr', GetScriptVariable (smv, smScriptKeys));
5019 UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5020 [[theEvent characters] characterAtIndex: 0],
5021 kUCKeyActionDisplay,
5022 (flags & ~NSCommandKeyMask) >> 8,
5023 LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5024 &dummy, 1, &dummy, &code);
5031 is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5032 is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5033 || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5036 emacs_event->modifiers |= parse_solitary_modifier
5037 (EQ (ns_right_control_modifier, Qleft)
5038 ? ns_control_modifier
5039 : ns_right_control_modifier);
5042 emacs_event->modifiers |= parse_solitary_modifier
5043 (ns_control_modifier);
5045 if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5046 emacs_event->modifiers |=
5047 parse_solitary_modifier (ns_function_modifier);
5049 left_is_none = NILP (ns_alternate_modifier)
5050 || EQ (ns_alternate_modifier, Qnone);
5052 is_right_key = (flags & NSRightAlternateKeyMask)
5053 == NSRightAlternateKeyMask;
5054 is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5056 && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5060 if ((NILP (ns_right_alternate_modifier)
5061 || EQ (ns_right_alternate_modifier, Qnone)
5062 || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5064 { /* accept pre-interp alt comb */
5065 if ([[theEvent characters] length] > 0)
5066 code = [[theEvent characters] characterAtIndex: 0];
5067 /*HACK: clear lone shift modifier to stop next if from firing */
5068 if (emacs_event->modifiers == shift_modifier)
5069 emacs_event->modifiers = 0;
5072 emacs_event->modifiers |= parse_solitary_modifier
5073 (EQ (ns_right_alternate_modifier, Qleft)
5074 ? ns_alternate_modifier
5075 : ns_right_alternate_modifier);
5078 if (is_left_key) /* default = meta */
5080 if (left_is_none && !fnKeysym)
5081 { /* accept pre-interp alt comb */
5082 if ([[theEvent characters] length] > 0)
5083 code = [[theEvent characters] characterAtIndex: 0];
5084 /*HACK: clear lone shift modifier to stop next if from firing */
5085 if (emacs_event->modifiers == shift_modifier)
5086 emacs_event->modifiers = 0;
5089 emacs_event->modifiers |=
5090 parse_solitary_modifier (ns_alternate_modifier);
5094 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5095 code, fnKeysym, flags, emacs_event->modifiers);
5097 /* if it was a function key or had modifiers, pass it directly to emacs */
5098 if (fnKeysym || (emacs_event->modifiers
5099 && (emacs_event->modifiers != shift_modifier)
5100 && [[theEvent charactersIgnoringModifiers] length] > 0))
5101 /*[[theEvent characters] length] */
5103 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5105 code |= (1<<28)|(3<<16);
5106 else if (code == 0x7f)
5107 code |= (1<<28)|(3<<16);
5109 emacs_event->kind = code > 0xFF
5110 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5112 emacs_event->code = code;
5113 EV_TRAILER (theEvent);
5114 processingCompose = NO;
5120 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
5121 /* if we get here we should send the key for input manager processing */
5122 if (firstTime && [[NSInputManager currentInputManager]
5123 wantsToDelayTextChangeNotifications] == NO)
5125 "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
5128 if (NS_KEYLOG && !processingCompose)
5129 fprintf (stderr, "keyDown: Begin compose sequence.\n");
5131 processingCompose = YES;
5132 [nsEvArray addObject: theEvent];
5133 [self interpretKeyEvents: nsEvArray];
5134 [nsEvArray removeObject: theEvent];
5138 #ifdef NS_IMPL_COCOA
5139 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5140 decided not to send key-down for.
5141 See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5142 This only applies on Tiger and earlier.
5143 If it matches one of these, send it on to keyDown. */
5144 -(void)keyUp: (NSEvent *)theEvent
5146 int flags = [theEvent modifierFlags];
5147 int code = [theEvent keyCode];
5148 if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5149 code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5152 fprintf (stderr, "keyUp: passed test");
5153 ns_fake_keydown = YES;
5154 [self keyDown: theEvent];
5160 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5163 /* <NSTextInput>: called when done composing;
5164 NOTE: also called when we delete over working text, followed immed.
5165 by doCommandBySelector: deleteBackward: */
5166 - (void)insertText: (id)aString
5169 int len = [(NSString *)aString length];
5173 NSLog (@"insertText '%@'\tlen = %d", aString, len);
5174 processingCompose = NO;
5179 /* first, clear any working text */
5180 if (workingText != nil)
5181 [self deleteWorkingText];
5183 /* now insert the string as keystrokes */
5184 for (i =0; i<len; i++)
5186 code = [aString characterAtIndex: i];
5187 /* TODO: still need this? */
5189 code = '~'; /* 0x7E */
5190 if (code != 32) /* Space */
5191 emacs_event->modifiers = 0;
5193 = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5194 emacs_event->code = code;
5195 EV_TRAILER ((id)nil);
5200 /* <NSTextInput>: inserts display of composing characters */
5201 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5203 NSString *str = [aString respondsToSelector: @selector (string)] ?
5204 [aString string] : aString;
5206 NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
5207 selRange.length, selRange.location);
5209 if (workingText != nil)
5210 [self deleteWorkingText];
5211 if ([str length] == 0)
5217 processingCompose = YES;
5218 workingText = [str copy];
5219 ns_working_text = build_string ([workingText UTF8String]);
5221 emacs_event->kind = NS_TEXT_EVENT;
5222 emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5223 EV_TRAILER ((id)nil);
5227 /* delete display of composing characters [not in <NSTextInput>] */
5228 - (void)deleteWorkingText
5230 if (workingText == nil)
5233 NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
5234 [workingText release];
5236 processingCompose = NO;
5241 emacs_event->kind = NS_TEXT_EVENT;
5242 emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5243 EV_TRAILER ((id)nil);
5247 - (BOOL)hasMarkedText
5249 return workingText != nil;
5253 - (NSRange)markedRange
5255 NSRange rng = workingText != nil
5256 ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5258 NSLog (@"markedRange request");
5266 NSLog (@"unmark (accept) text");
5267 [self deleteWorkingText];
5268 processingCompose = NO;
5272 /* used to position char selection windows, etc. */
5273 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5277 struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5279 NSLog (@"firstRectForCharRange request");
5281 rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5282 rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5283 pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5284 pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5285 +FRAME_LINE_HEIGHT (emacsframe));
5287 pt = [self convertPoint: pt toView: nil];
5288 pt = [[self window] convertBaseToScreen: pt];
5294 - (NSInteger)conversationIdentifier
5296 return (NSInteger)self;
5300 - (void)doCommandBySelector: (SEL)aSelector
5303 NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5305 processingCompose = NO;
5306 if (aSelector == @selector (deleteBackward:))
5308 /* happens when user backspaces over an ongoing composition:
5309 throw a 'delete' into the event queue */
5312 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5313 emacs_event->code = 0xFF08;
5314 EV_TRAILER ((id)nil);
5318 - (NSArray *)validAttributesForMarkedText
5320 static NSArray *arr = nil;
5321 if (arr == nil) arr = [NSArray new];
5322 /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5326 - (NSRange)selectedRange
5329 NSLog (@"selectedRange request");
5330 return NSMakeRange (NSNotFound, 0);
5333 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5336 NSLog (@"characterIndexForPoint request");
5340 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5342 static NSAttributedString *str = nil;
5343 if (str == nil) str = [NSAttributedString new];
5345 NSLog (@"attributedSubstringFromRange request");
5349 /* End <NSTextInput> impl. */
5350 /*****************************************************************************/
5353 /* This is what happens when the user presses a mouse button. */
5354 - (void)mouseDown: (NSEvent *)theEvent
5356 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5358 NSTRACE (mouseDown);
5360 [self deleteWorkingText];
5365 last_mouse_frame = emacsframe;
5366 /* appears to be needed to prevent spurious movement events generated on
5368 last_mouse_frame->mouse_moved = 0;
5370 if ([theEvent type] == NSScrollWheel)
5372 float delta = [theEvent deltaY];
5373 /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5376 emacs_event->kind = WHEEL_EVENT;
5377 emacs_event->code = 0;
5378 emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5379 ((delta > 0) ? up_modifier : down_modifier);
5383 emacs_event->kind = MOUSE_CLICK_EVENT;
5384 emacs_event->code = EV_BUTTON (theEvent);
5385 emacs_event->modifiers = EV_MODIFIERS (theEvent)
5386 | EV_UDMODIFIERS (theEvent);
5388 XSETINT (emacs_event->x, lrint (p.x));
5389 XSETINT (emacs_event->y, lrint (p.y));
5390 EV_TRAILER (theEvent);
5394 - (void)rightMouseDown: (NSEvent *)theEvent
5396 NSTRACE (rightMouseDown);
5397 [self mouseDown: theEvent];
5401 - (void)otherMouseDown: (NSEvent *)theEvent
5403 NSTRACE (otherMouseDown);
5404 [self mouseDown: theEvent];
5408 - (void)mouseUp: (NSEvent *)theEvent
5411 [self mouseDown: theEvent];
5415 - (void)rightMouseUp: (NSEvent *)theEvent
5417 NSTRACE (rightMouseUp);
5418 [self mouseDown: theEvent];
5422 - (void)otherMouseUp: (NSEvent *)theEvent
5424 NSTRACE (otherMouseUp);
5425 [self mouseDown: theEvent];
5429 - (void) scrollWheel: (NSEvent *)theEvent
5431 NSTRACE (scrollWheel);
5432 [self mouseDown: theEvent];
5436 /* Tell emacs the mouse has moved. */
5437 - (void)mouseMoved: (NSEvent *)e
5439 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5442 // NSTRACE (mouseMoved);
5444 last_mouse_movement_time = EV_TIMESTAMP (e);
5445 last_mouse_motion_position
5446 = [self convertPoint: [e locationInWindow] fromView: nil];
5448 /* update any mouse face */
5449 if (hlinfo->mouse_face_hidden)
5451 hlinfo->mouse_face_hidden = 0;
5452 clear_mouse_face (hlinfo);
5455 /* tooltip handling */
5456 previous_help_echo_string = help_echo_string;
5457 help_echo_string = Qnil;
5459 if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
5460 last_mouse_motion_position.y))
5461 help_echo_string = previous_help_echo_string;
5463 XSETFRAME (frame, emacsframe);
5464 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5466 /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5467 (note_mouse_highlight), which is called through the
5468 note_mouse_movement () call above */
5469 gen_help_event (help_echo_string, frame, help_echo_window,
5470 help_echo_object, help_echo_pos);
5474 help_echo_string = Qnil;
5475 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5478 if (emacsframe->mouse_moved && send_appdefined)
5479 ns_send_appdefined (-1);
5483 - (void)mouseDragged: (NSEvent *)e
5485 NSTRACE (mouseDragged);
5486 [self mouseMoved: e];
5490 - (void)rightMouseDragged: (NSEvent *)e
5492 NSTRACE (rightMouseDragged);
5493 [self mouseMoved: e];
5497 - (void)otherMouseDragged: (NSEvent *)e
5499 NSTRACE (otherMouseDragged);
5500 [self mouseMoved: e];
5504 - (BOOL)windowShouldClose: (id)sender
5506 NSEvent *e =[[self window] currentEvent];
5508 NSTRACE (windowShouldClose);
5509 windowClosing = YES;
5512 emacs_event->kind = DELETE_WINDOW_EVENT;
5513 emacs_event->modifiers = 0;
5514 emacs_event->code = 0;
5516 /* Don't close this window, let this be done from lisp code. */
5520 - (void) updateFrameSize: (BOOL) delay;
5522 NSWindow *window = [self window];
5523 NSRect wr = [window frame];
5526 #ifdef NS_IMPL_GNUSTEP
5530 int oldc = cols, oldr = rows;
5531 int oldw = FRAME_PIXEL_WIDTH (emacsframe),
5532 oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5535 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, wr.size.width + gsextra);
5537 if (cols < MINWIDTH)
5540 if (! [self isFullscreen])
5542 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5543 + FRAME_TOOLBAR_HEIGHT (emacsframe) - gsextra;
5546 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, wr.size.height - extra);
5548 if (rows < MINHEIGHT)
5551 neww = (int)wr.size.width - emacsframe->border_width;
5552 newh = (int)wr.size.height - extra;
5554 if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5556 struct frame *f = emacsframe;
5557 NSView *view = FRAME_NS_VIEW (emacsframe);
5558 NSWindow *win = [view window];
5559 NSSize sz = [win resizeIncrements];
5561 FRAME_PIXEL_WIDTH (emacsframe) = neww;
5562 FRAME_PIXEL_HEIGHT (emacsframe) = newh;
5563 change_frame_size (emacsframe, rows, cols, 0, delay, 0);
5564 SET_FRAME_GARBAGED (emacsframe);
5565 cancel_mouse_face (emacsframe);
5567 // Did resize increments change because of a font change?
5568 if (sz.width != FRAME_COLUMN_WIDTH (emacsframe) ||
5569 sz.height != FRAME_LINE_HEIGHT (emacsframe))
5571 sz.width = FRAME_COLUMN_WIDTH (emacsframe);
5572 sz.height = FRAME_LINE_HEIGHT (emacsframe);
5573 [win setResizeIncrements: sz];
5576 [view setFrame: NSMakeRect (0, 0, neww, newh)];
5577 [self windowDidMove:nil]; // Update top/left.
5581 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5582 /* normalize frame to gridded text size */
5586 #ifdef NS_IMPL_GNUSTEP
5590 NSTRACE (windowWillResize);
5591 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5593 if (fs_state == FULLSCREEN_MAXIMIZED
5594 && (maximized_width != (int)frameSize.width
5595 || maximized_height != (int)frameSize.height))
5596 [self setFSValue: FULLSCREEN_NONE];
5597 else if (fs_state == FULLSCREEN_WIDTH
5598 && maximized_width != (int)frameSize.width)
5599 [self setFSValue: FULLSCREEN_NONE];
5600 else if (fs_state == FULLSCREEN_HEIGHT
5601 && maximized_height != (int)frameSize.height)
5602 [self setFSValue: FULLSCREEN_NONE];
5603 if (fs_state == FULLSCREEN_NONE)
5604 maximized_width = maximized_height = -1;
5606 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5607 frameSize.width + gsextra);
5608 if (cols < MINWIDTH)
5611 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
5612 frameSize.height - extra);
5613 if (rows < MINHEIGHT)
5615 #ifdef NS_IMPL_COCOA
5617 /* this sets window title to have size in it; the wm does this under GS */
5618 NSRect r = [[self window] frame];
5619 if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5630 NSWindow *window = [self window];
5633 const char *t = [[[self window] title] UTF8String];
5634 char *pos = strstr (t, " — ");
5637 old_title = xstrdup (t);
5639 size_title = xmalloc (strlen (old_title) + 40);
5640 esprintf (size_title, "%s — (%d x %d)", old_title, cols, rows);
5641 [window setTitle: [NSString stringWithUTF8String: size_title]];
5646 #endif /* NS_IMPL_COCOA */
5647 /*fprintf (stderr," ...size became %.0f x %.0f (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5653 - (void)windowDidResize: (NSNotification *)notification
5655 if (! [self fsIsNative])
5657 NSWindow *theWindow = [notification object];
5658 /* We can get notification on the non-FS window when in
5660 if ([self window] != theWindow) return;
5663 #ifdef NS_IMPL_GNUSTEP
5664 NSWindow *theWindow = [notification object];
5666 /* In GNUstep, at least currently, it's possible to get a didResize
5667 without getting a willResize.. therefore we need to act as if we got
5668 the willResize now */
5669 NSSize sz = [theWindow frame].size;
5670 sz = [self windowWillResize: theWindow toSize: sz];
5671 #endif /* NS_IMPL_GNUSTEP */
5673 NSTRACE (windowDidResize);
5674 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5676 #ifdef NS_IMPL_COCOA
5682 #endif /* NS_IMPL_COCOA */
5684 if (cols > 0 && rows > 0)
5686 [self updateFrameSize: YES];
5689 ns_send_appdefined (-1);
5693 - (void)windowDidBecomeKey: (NSNotification *)notification
5694 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5696 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5697 struct frame *old_focus = dpyinfo->x_focus_frame;
5699 NSTRACE (windowDidBecomeKey);
5701 if (emacsframe != old_focus)
5702 dpyinfo->x_focus_frame = emacsframe;
5704 ns_frame_rehighlight (emacsframe);
5708 emacs_event->kind = FOCUS_IN_EVENT;
5709 EV_TRAILER ((id)nil);
5714 - (void)windowDidResignKey: (NSNotification *)notification
5715 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5717 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5718 NSTRACE (windowDidResignKey);
5720 if (dpyinfo->x_focus_frame == emacsframe)
5721 dpyinfo->x_focus_frame = 0;
5723 ns_frame_rehighlight (emacsframe);
5725 /* FIXME: for some reason needed on second and subsequent clicks away
5726 from sole-frame Emacs to get hollow box to show */
5727 if (!windowClosing && [[self window] isVisible] == YES)
5729 x_update_cursor (emacsframe, 1);
5730 x_set_frame_alpha (emacsframe);
5735 [self deleteWorkingText];
5736 emacs_event->kind = FOCUS_IN_EVENT;
5737 EV_TRAILER ((id)nil);
5742 - (void)windowWillMiniaturize: sender
5744 NSTRACE (windowWillMiniaturize);
5760 - initFrameFromEmacs: (struct frame *)f
5765 NSButton *toggleButton;
5770 NSTRACE (initFrameFromEmacs);
5773 processingCompose = NO;
5774 scrollbarsNeedingUpdate = 0;
5775 fs_state = FULLSCREEN_NONE;
5776 fs_before_fs = next_maximized = -1;
5777 #ifdef HAVE_NATIVE_FS
5778 fs_is_native = ns_use_native_fullscreen;
5782 maximized_width = maximized_height = -1;
5785 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5787 ns_userRect = NSMakeRect (0, 0, 0, 0);
5788 r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5789 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5790 [self initWithFrame: r];
5791 [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5793 FRAME_NS_VIEW (f) = self;
5797 win = [[EmacsWindow alloc]
5798 initWithContentRect: r
5799 styleMask: (NSResizableWindowMask |
5800 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5801 NSTitledWindowMask |
5803 NSMiniaturizableWindowMask |
5804 NSClosableWindowMask)
5805 backing: NSBackingStoreBuffered
5808 #ifdef HAVE_NATIVE_FS
5809 [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
5813 bwidth = f->border_width = wr.size.width - r.size.width;
5814 tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5816 [win setAcceptsMouseMovedEvents: YES];
5817 [win setDelegate: self];
5818 [win useOptimizedDrawing: YES];
5820 sz.width = FRAME_COLUMN_WIDTH (f);
5821 sz.height = FRAME_LINE_HEIGHT (f);
5822 [win setResizeIncrements: sz];
5824 [[win contentView] addSubview: self];
5827 [self registerForDraggedTypes: ns_drag_types];
5830 name = [NSString stringWithUTF8String:
5831 NILP (tem) ? "Emacs" : SSDATA (tem)];
5832 [win setTitle: name];
5834 /* toolbar support */
5835 toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5836 [NSString stringWithFormat: @"Emacs Frame %d",
5838 [win setToolbar: toolbar];
5839 [toolbar setVisible: NO];
5840 #ifdef NS_IMPL_COCOA
5841 toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5842 [toggleButton setTarget: self];
5843 [toggleButton setAction: @selector (toggleToolbar: )];
5845 FRAME_TOOLBAR_HEIGHT (f) = 0;
5849 [win setMiniwindowTitle:
5850 [NSString stringWithUTF8String: SSDATA (tem)]];
5853 NSScreen *screen = [win screen];
5856 [win setFrameTopLeftPoint: NSMakePoint
5857 (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5858 IN_BOUND (-SCREENMAX,
5859 [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5862 [win makeFirstResponder: self];
5864 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5865 (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5866 [win setBackgroundColor: col];
5867 if ([col alphaComponent] != 1.0)
5868 [win setOpaque: NO];
5870 [self allocateGState];
5872 [NSApp registerServicesMenuSendTypes: ns_send_types
5880 - (void)windowDidMove: sender
5882 NSWindow *win = [self window];
5883 NSRect r = [win frame];
5884 NSArray *screens = [NSScreen screens];
5885 NSScreen *screen = [screens objectAtIndex: 0];
5887 NSTRACE (windowDidMove);
5889 if (!emacsframe->output_data.ns)
5893 emacsframe->left_pos = r.origin.x;
5894 emacsframe->top_pos =
5895 [screen frame].size.height - (r.origin.y + r.size.height);
5900 /* Called AFTER method below, but before our windowWillResize call there leads
5901 to windowDidResize -> x_set_window_size. Update emacs' notion of frame
5902 location so set_window_size moves the frame. */
5903 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5905 emacsframe->output_data.ns->zooming = 1;
5910 /* Override to do something slightly nonstandard, but nice. First click on
5911 zoom button will zoom vertically. Second will zoom completely. Third
5912 returns to original. */
5913 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5914 defaultFrame:(NSRect)defaultFrame
5916 NSRect result = [sender frame];
5918 NSTRACE (windowWillUseStandardFrame);
5920 if (fs_before_fs != -1) /* Entering fullscreen */
5922 result = defaultFrame;
5924 else if (next_maximized == FULLSCREEN_HEIGHT
5925 || (next_maximized == -1
5926 && abs (defaultFrame.size.height - result.size.height)
5927 > FRAME_LINE_HEIGHT (emacsframe)))
5930 ns_userRect = result;
5931 maximized_height = result.size.height = defaultFrame.size.height;
5932 maximized_width = -1;
5933 result.origin.y = defaultFrame.origin.y;
5934 [self setFSValue: FULLSCREEN_HEIGHT];
5936 else if (next_maximized == FULLSCREEN_WIDTH)
5938 ns_userRect = result;
5939 maximized_width = result.size.width = defaultFrame.size.width;
5940 maximized_height = -1;
5941 result.origin.x = defaultFrame.origin.x;
5942 [self setFSValue: FULLSCREEN_WIDTH];
5944 else if (next_maximized == FULLSCREEN_MAXIMIZED
5945 || (next_maximized == -1
5946 && abs (defaultFrame.size.width - result.size.width)
5947 > FRAME_COLUMN_WIDTH (emacsframe)))
5949 result = defaultFrame; /* second click */
5950 maximized_width = result.size.width;
5951 maximized_height = result.size.height;
5952 [self setFSValue: FULLSCREEN_MAXIMIZED];
5957 result = ns_userRect.size.height ? ns_userRect : result;
5958 ns_userRect = NSMakeRect (0, 0, 0, 0);
5959 [self setFSValue: FULLSCREEN_NONE];
5960 maximized_width = maximized_width = -1;
5963 if (fs_before_fs == -1) next_maximized = -1;
5964 [self windowWillResize: sender toSize: result.size];
5969 - (void)windowDidDeminiaturize: sender
5971 NSTRACE (windowDidDeminiaturize);
5972 if (!emacsframe->output_data.ns)
5975 SET_FRAME_ICONIFIED (emacsframe, 0);
5976 SET_FRAME_VISIBLE (emacsframe, 1);
5977 windows_or_buffers_changed++;
5981 emacs_event->kind = DEICONIFY_EVENT;
5982 EV_TRAILER ((id)nil);
5987 - (void)windowDidExpose: sender
5989 NSTRACE (windowDidExpose);
5990 if (!emacsframe->output_data.ns)
5993 SET_FRAME_VISIBLE (emacsframe, 1);
5994 SET_FRAME_GARBAGED (emacsframe);
5996 if (send_appdefined)
5997 ns_send_appdefined (-1);
6001 - (void)windowDidMiniaturize: sender
6003 NSTRACE (windowDidMiniaturize);
6004 if (!emacsframe->output_data.ns)
6007 SET_FRAME_ICONIFIED (emacsframe, 1);
6008 SET_FRAME_VISIBLE (emacsframe, 0);
6012 emacs_event->kind = ICONIFY_EVENT;
6013 EV_TRAILER ((id)nil);
6017 #ifdef HAVE_NATIVE_FS
6018 - (NSApplicationPresentationOptions)window:(NSWindow *)window
6019 willUseFullScreenPresentationOptions:
6020 (NSApplicationPresentationOptions)proposedOptions
6022 return proposedOptions|NSApplicationPresentationAutoHideToolbar;
6026 - (void)windowWillEnterFullScreen:(NSNotification *)notification
6028 fs_before_fs = fs_state;
6031 - (void)windowDidEnterFullScreen:(NSNotification *)notification
6033 [self setFSValue: FULLSCREEN_BOTH];
6034 if (! [self fsIsNative])
6036 [self windowDidBecomeKey:notification];
6037 [nonfs_window orderOut:self];
6039 else if (! FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6040 [toolbar setVisible:NO];
6043 - (void)windowWillExitFullScreen:(NSNotification *)notification
6045 if (next_maximized != -1)
6046 fs_before_fs = next_maximized;
6049 - (void)windowDidExitFullScreen:(NSNotification *)notification
6051 [self setFSValue: fs_before_fs];
6053 [self updateCollectionBehaviour];
6054 if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6056 [toolbar setVisible:YES];
6057 update_frame_tool_bar (emacsframe);
6058 [self updateFrameSize:YES];
6059 [[self window] display];
6062 [toolbar setVisible:NO];
6064 if (next_maximized != -1)
6065 [[self window] performZoom:self];
6070 return fs_is_native;
6073 - (BOOL)isFullscreen
6075 if (! fs_is_native) return nonfs_window != nil;
6076 #ifdef HAVE_NATIVE_FS
6077 return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
6083 #ifdef HAVE_NATIVE_FS
6084 - (void)updateCollectionBehaviour
6086 if (! [self isFullscreen])
6088 NSWindow *win = [self window];
6089 NSWindowCollectionBehavior b = [win collectionBehavior];
6090 if (ns_use_native_fullscreen)
6091 b |= NSWindowCollectionBehaviorFullScreenPrimary;
6093 b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
6095 [win setCollectionBehavior: b];
6096 fs_is_native = ns_use_native_fullscreen;
6101 - (void)toggleFullScreen: (id)sender
6112 [[self window] toggleFullScreen:sender];
6117 onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
6120 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6121 (FRAME_DEFAULT_FACE (f)),
6124 sz.width = FRAME_COLUMN_WIDTH (f);
6125 sz.height = FRAME_LINE_HEIGHT (f);
6127 if (fs_state != FULLSCREEN_BOTH)
6129 /* Hide dock and menubar if we are on the primary screen. */
6132 #if defined (NS_IMPL_COCOA) && \
6133 MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6134 NSApplicationPresentationOptions options
6135 = NSApplicationPresentationAutoHideDock
6136 | NSApplicationPresentationAutoHideMenuBar;
6138 [NSApp setPresentationOptions: options];
6140 [NSMenu setMenuBarVisible:NO];
6144 fw = [[EmacsFSWindow alloc]
6145 initWithContentRect:[w contentRectForFrameRect:wr]
6146 styleMask:NSBorderlessWindowMask
6147 backing:NSBackingStoreBuffered
6151 [fw setContentView:[w contentView]];
6152 [fw setTitle:[w title]];
6153 [fw setDelegate:self];
6154 [fw setAcceptsMouseMovedEvents: YES];
6155 [fw useOptimizedDrawing: YES];
6156 [fw setResizeIncrements: sz];
6157 [fw setBackgroundColor: col];
6158 if ([col alphaComponent] != 1.0)
6161 f->border_width = 0;
6162 FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
6163 tobar_height = FRAME_TOOLBAR_HEIGHT (f);
6164 FRAME_TOOLBAR_HEIGHT (f) = 0;
6168 [self windowWillEnterFullScreen:nil];
6169 [fw makeKeyAndOrderFront:NSApp];
6170 [fw makeFirstResponder:self];
6172 r = [fw frameRectForContentRect:[[fw screen] frame]];
6173 [fw setFrame: r display:YES animate:YES];
6174 [self windowDidEnterFullScreen:nil];
6185 #if defined (NS_IMPL_COCOA) && \
6186 MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6187 [NSApp setPresentationOptions: NSApplicationPresentationDefault];
6189 [NSMenu setMenuBarVisible:YES];
6193 [w setContentView:[fw contentView]];
6194 [w setResizeIncrements: sz];
6195 [w setBackgroundColor: col];
6196 if ([col alphaComponent] != 1.0)
6199 f->border_width = bwidth;
6200 FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
6201 if (FRAME_EXTERNAL_TOOL_BAR (f))
6202 FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
6204 [self windowWillExitFullScreen:nil];
6205 [fw setFrame: [w frame] display:YES animate:YES];
6207 [w makeKeyAndOrderFront:NSApp];
6208 [self windowDidExitFullScreen:nil];
6209 [self updateFrameSize:YES];
6215 if (fs_state != emacsframe->want_fullscreen)
6217 if (fs_state == FULLSCREEN_BOTH)
6219 [self toggleFullScreen:self];
6222 switch (emacsframe->want_fullscreen)
6224 case FULLSCREEN_BOTH:
6225 [self toggleFullScreen:self];
6227 case FULLSCREEN_WIDTH:
6228 next_maximized = FULLSCREEN_WIDTH;
6229 if (fs_state != FULLSCREEN_BOTH)
6230 [[self window] performZoom:self];
6232 case FULLSCREEN_HEIGHT:
6233 next_maximized = FULLSCREEN_HEIGHT;
6234 if (fs_state != FULLSCREEN_BOTH)
6235 [[self window] performZoom:self];
6237 case FULLSCREEN_MAXIMIZED:
6238 next_maximized = FULLSCREEN_MAXIMIZED;
6239 if (fs_state != FULLSCREEN_BOTH)
6240 [[self window] performZoom:self];
6242 case FULLSCREEN_NONE:
6243 if (fs_state != FULLSCREEN_BOTH)
6245 next_maximized = FULLSCREEN_NONE;
6246 [[self window] performZoom:self];
6251 emacsframe->want_fullscreen = FULLSCREEN_NONE;
6256 - (void) setFSValue: (int)value
6258 Lisp_Object lval = Qnil;
6261 case FULLSCREEN_BOTH:
6264 case FULLSCREEN_WIDTH:
6267 case FULLSCREEN_HEIGHT:
6270 case FULLSCREEN_MAXIMIZED:
6274 store_frame_param (emacsframe, Qfullscreen, lval);
6278 - (void)mouseEntered: (NSEvent *)theEvent
6280 NSTRACE (mouseEntered);
6281 last_mouse_movement_time = EV_TIMESTAMP (theEvent);
6285 - (void)mouseExited: (NSEvent *)theEvent
6287 Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6289 NSTRACE (mouseExited);
6294 last_mouse_movement_time = EV_TIMESTAMP (theEvent);
6296 if (emacsframe == hlinfo->mouse_face_mouse_frame)
6298 clear_mouse_face (hlinfo);
6299 hlinfo->mouse_face_mouse_frame = 0;
6307 if (context_menu_value == -1)
6308 context_menu_value = [sender tag];
6311 NSInteger tag = [sender tag];
6312 find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6313 emacsframe->menu_bar_vector,
6317 ns_send_appdefined (-1);
6322 - (EmacsToolbar *)toolbar
6328 /* this gets called on toolbar button click */
6329 - toolbarClicked: (id)item
6332 int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6334 NSTRACE (toolbarClicked);
6339 /* send first event (for some reason two needed) */
6340 theEvent = [[self window] currentEvent];
6341 emacs_event->kind = TOOL_BAR_EVENT;
6342 XSETFRAME (emacs_event->arg, emacsframe);
6343 EV_TRAILER (theEvent);
6345 emacs_event->kind = TOOL_BAR_EVENT;
6346 /* XSETINT (emacs_event->code, 0); */
6347 emacs_event->arg = AREF (emacsframe->tool_bar_items,
6348 idx + TOOL_BAR_ITEM_KEY);
6349 emacs_event->modifiers = EV_MODIFIERS (theEvent);
6350 EV_TRAILER (theEvent);
6355 - toggleToolbar: (id)sender
6360 emacs_event->kind = NS_NONKEY_EVENT;
6361 emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6362 EV_TRAILER ((id)nil);
6367 - (void)drawRect: (NSRect)rect
6369 int x = NSMinX (rect), y = NSMinY (rect);
6370 int width = NSWidth (rect), height = NSHeight (rect);
6374 if (!emacsframe || !emacsframe->output_data.ns)
6377 ns_clear_frame_area (emacsframe, x, y, width, height);
6378 expose_frame (emacsframe, x, y, width, height);
6381 drawRect: may be called (at least in OS X 10.5) for invisible
6382 views as well for some reason. Thus, do not infer visibility
6385 emacsframe->async_visible = 1;
6386 emacsframe->async_iconified = 0;
6391 /* NSDraggingDestination protocol methods. Actually this is not really a
6392 protocol, but a category of Object. O well... */
6394 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
6396 NSTRACE (draggingEntered);
6397 return NSDragOperationGeneric;
6401 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6407 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6412 NSEvent *theEvent = [[self window] currentEvent];
6415 NSTRACE (performDragOperation);
6420 position = [self convertPoint: [sender draggingLocation] fromView: nil];
6421 x = lrint (position.x); y = lrint (position.y);
6423 pb = [sender draggingPasteboard];
6424 type = [pb availableTypeFromArray: ns_drag_types];
6429 else if ([type isEqualToString: NSFilenamesPboardType])
6432 NSEnumerator *fenum;
6435 if (!(files = [pb propertyListForType: type]))
6438 fenum = [files objectEnumerator];
6439 while ( (file = [fenum nextObject]) )
6441 emacs_event->kind = NS_NONKEY_EVENT;
6442 emacs_event->code = KEY_NS_DRAG_FILE;
6443 XSETINT (emacs_event->x, x);
6444 XSETINT (emacs_event->y, y);
6445 ns_input_file = append2 (ns_input_file,
6446 build_string ([file UTF8String]));
6447 emacs_event->modifiers = EV_MODIFIERS (theEvent);
6448 EV_TRAILER (theEvent);
6452 else if ([type isEqualToString: NSURLPboardType])
6457 if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
6458 [fileURL isFileURL] == NO)
6461 file = [fileURL path];
6462 emacs_event->kind = NS_NONKEY_EVENT;
6463 emacs_event->code = KEY_NS_DRAG_FILE;
6464 XSETINT (emacs_event->x, x);
6465 XSETINT (emacs_event->y, y);
6466 ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
6467 emacs_event->modifiers = EV_MODIFIERS (theEvent);
6468 EV_TRAILER (theEvent);
6471 else if ([type isEqualToString: NSStringPboardType]
6472 || [type isEqualToString: NSTabularTextPboardType])
6476 if (! (data = [pb stringForType: type]))
6479 emacs_event->kind = NS_NONKEY_EVENT;
6480 emacs_event->code = KEY_NS_DRAG_TEXT;
6481 XSETINT (emacs_event->x, x);
6482 XSETINT (emacs_event->y, y);
6483 ns_input_text = build_string ([data UTF8String]);
6484 emacs_event->modifiers = EV_MODIFIERS (theEvent);
6485 EV_TRAILER (theEvent);
6488 else if ([type isEqualToString: NSColorPboardType])
6490 NSColor *c = [NSColor colorFromPasteboard: pb];
6491 emacs_event->kind = NS_NONKEY_EVENT;
6492 emacs_event->code = KEY_NS_DRAG_COLOR;
6493 XSETINT (emacs_event->x, x);
6494 XSETINT (emacs_event->y, y);
6495 ns_input_color = ns_color_to_lisp (c);
6496 emacs_event->modifiers = EV_MODIFIERS (theEvent);
6497 EV_TRAILER (theEvent);
6500 else if ([type isEqualToString: NSFontPboardType])
6502 /* impl based on GNUstep NSTextView.m */
6503 NSData *data = [pb dataForType: NSFontPboardType];
6504 NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
6505 NSFont *font = [dict objectForKey: NSFontAttributeName];
6511 emacs_event->kind = NS_NONKEY_EVENT;
6512 emacs_event->code = KEY_NS_CHANGE_FONT;
6513 XSETINT (emacs_event->x, x);
6514 XSETINT (emacs_event->y, y);
6515 ns_input_font = build_string ([[font fontName] UTF8String]);
6516 snprintf (fontSize, 10, "%f", [font pointSize]);
6517 ns_input_fontsize = build_string (fontSize);
6518 emacs_event->modifiers = EV_MODIFIERS (theEvent);
6519 EV_TRAILER (theEvent);
6524 error ("Invalid data type in dragging pasteboard.");
6530 - (id) validRequestorForSendType: (NSString *)typeSent
6531 returnType: (NSString *)typeReturned
6533 NSTRACE (validRequestorForSendType);
6534 if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6535 && typeReturned == nil)
6537 if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6541 return [super validRequestorForSendType: typeSent
6542 returnType: typeReturned];
6546 /* The next two methods are part of NSServicesRequests informal protocol,
6547 supposedly called when a services menu item is chosen from this app.
6548 But this should not happen because we override the services menu with our
6549 own entries which call ns-perform-service.
6550 Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6551 So let's at least stub them out until further investigation can be done. */
6553 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6555 /* we could call ns_string_from_pasteboard(pboard) here but then it should
6556 be written into the buffer in place of the existing selection..
6557 ordinary service calls go through functions defined in ns-win.el */
6561 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6563 NSArray *typesDeclared;
6566 /* We only support NSStringPboardType */
6567 if ([types containsObject:NSStringPboardType] == NO) {
6571 val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6572 if (CONSP (val) && SYMBOLP (XCAR (val)))
6575 if (CONSP (val) && NILP (XCDR (val)))
6578 if (! STRINGP (val))
6581 typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6582 [pb declareTypes:typesDeclared owner:nil];
6583 ns_string_to_pasteboard (pb, val);
6588 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6589 (gives a miniaturized version of the window); currently we use the latter for
6590 frames whose active buffer doesn't correspond to any file
6591 (e.g., '*scratch*') */
6592 - setMiniwindowImage: (BOOL) setMini
6594 id image = [[self window] miniwindowImage];
6595 NSTRACE (setMiniwindowImage);
6597 /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6598 about "AppleDockIconEnabled" notwithstanding, however the set message
6599 below has its effect nonetheless. */
6600 if (image != emacsframe->output_data.ns->miniimage)
6602 if (image && [image isKindOfClass: [EmacsImage class]])
6604 [[self window] setMiniwindowImage:
6605 setMini ? emacsframe->output_data.ns->miniimage : nil];
6612 - (void) setRows: (int) r andColumns: (int) c
6618 @end /* EmacsView */
6622 /* ==========================================================================
6624 EmacsWindow implementation
6626 ========================================================================== */
6628 @implementation EmacsWindow
6630 #ifdef NS_IMPL_COCOA
6631 - (id)accessibilityAttributeValue:(NSString *)attribute
6633 Lisp_Object str = Qnil;
6634 struct frame *f = SELECTED_FRAME ();
6635 struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
6637 if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6638 return NSAccessibilityTextFieldRole;
6640 if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6641 && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6643 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6645 else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
6647 if (! NILP (BVAR (curbuf, mark_active)))
6648 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6652 ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
6653 ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
6654 ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
6656 if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
6657 str = make_uninit_multibyte_string (range, byte_range);
6659 str = make_uninit_string (range);
6660 /* To check: This returns emacs-utf-8, which is a superset of utf-8.
6661 Is this a problem? */
6662 memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
6669 if (CONSP (str) && SYMBOLP (XCAR (str)))
6672 if (CONSP (str) && NILP (XCDR (str)))
6677 const char *utfStr = SSDATA (str);
6678 NSString *nsStr = [NSString stringWithUTF8String: utfStr];
6683 return [super accessibilityAttributeValue:attribute];
6685 #endif /* NS_IMPL_COCOA */
6687 /* If we have multiple monitors, one above the other, we don't want to
6688 restrict the height to just one monitor. So we override this. */
6689 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6691 /* When making the frame visible for the first time or if there is just
6692 one screen, we want to constrain. Other times not. */
6693 NSUInteger nr_screens = [[NSScreen screens] count];
6694 struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6695 NSTRACE (constrainFrameRect);
6697 if (nr_screens == 1)
6699 NSRect r = [super constrainFrameRect:frameRect toScreen:screen];
6703 if (f->output_data.ns->dont_constrain
6704 || ns_menu_bar_should_be_hidden ())
6707 f->output_data.ns->dont_constrain = 1;
6708 return [super constrainFrameRect:frameRect toScreen:screen];
6711 @end /* EmacsWindow */
6714 @implementation EmacsFSWindow
6716 - (BOOL)canBecomeKeyWindow
6721 - (BOOL)canBecomeMainWindow
6728 /* ==========================================================================
6730 EmacsScroller implementation
6732 ========================================================================== */
6735 @implementation EmacsScroller
6737 /* for repeat button push */
6738 #define SCROLL_BAR_FIRST_DELAY 0.5
6739 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6741 + (CGFloat) scrollerWidth
6743 /* TODO: if we want to allow variable widths, this is the place to do it,
6744 however neither GNUstep nor Cocoa support it very well */
6745 return [NSScroller scrollerWidth];
6749 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6751 NSTRACE (EmacsScroller_initFrame);
6753 r.size.width = [EmacsScroller scrollerWidth];
6754 [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6755 [self setContinuous: YES];
6756 [self setEnabled: YES];
6758 /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6759 locked against the top and bottom edges, and right edge on OS X, where
6760 scrollers are on right. */
6761 #ifdef NS_IMPL_GNUSTEP
6762 [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6764 [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6769 pixel_height = NSHeight (r);
6770 if (pixel_height == 0) pixel_height = 1;
6771 min_portion = 20 / pixel_height;
6773 frame = XFRAME (XWINDOW (win)->frame);
6774 if (FRAME_LIVE_P (frame))
6777 EmacsView *view = FRAME_NS_VIEW (frame);
6778 NSView *sview = [[view window] contentView];
6779 NSArray *subs = [sview subviews];
6781 /* disable optimization stopping redraw of other scrollbars */
6782 view->scrollbarsNeedingUpdate = 0;
6783 for (i =[subs count]-1; i >= 0; i--)
6784 if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6785 view->scrollbarsNeedingUpdate++;
6786 [sview addSubview: self];
6789 /* [self setFrame: r]; */
6795 - (void)setFrame: (NSRect)newRect
6797 NSTRACE (EmacsScroller_setFrame);
6798 /* block_input (); */
6799 pixel_height = NSHeight (newRect);
6800 if (pixel_height == 0) pixel_height = 1;
6801 min_portion = 20 / pixel_height;
6802 [super setFrame: newRect];
6804 /* unblock_input (); */
6810 NSTRACE (EmacsScroller_dealloc);
6812 wset_vertical_scroll_bar (XWINDOW (win), Qnil);
6840 /* ensure other scrollbar updates after deletion */
6841 view = (EmacsView *)FRAME_NS_VIEW (frame);
6843 view->scrollbarsNeedingUpdate++;
6844 [self removeFromSuperview];
6852 - (void)resetCursorRects
6854 NSRect visible = [self visibleRect];
6855 NSTRACE (resetCursorRects);
6857 if (!NSIsEmptyRect (visible))
6858 [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6859 [[NSCursor arrowCursor] setOnMouseEntered: YES];
6863 - (int) checkSamePosition: (int) position portion: (int) portion
6866 return em_position ==position && em_portion ==portion && em_whole ==whole
6867 && portion != whole; /* needed for resize empty buf */
6871 - setPosition: (int)position portion: (int)portion whole: (int)whole
6873 NSTRACE (setPosition);
6875 em_position = position;
6876 em_portion = portion;
6879 if (portion >= whole)
6881 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6882 [self setKnobProportion: 1.0];
6883 [self setDoubleValue: 1.0];
6885 [self setFloatValue: 0.0 knobProportion: 1.0];
6891 portion = max ((float)whole*min_portion/pixel_height, portion);
6892 pos = (float)position / (whole - portion);
6893 por = (float)portion/whole;
6894 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6895 [self setKnobProportion: por];
6896 [self setDoubleValue: pos];
6898 [self setFloatValue: pos knobProportion: por];
6902 /* Events may come here even if the event loop is not running.
6903 If we don't enter the event loop, the scroll bar will not update.
6904 So send SIGIO to ourselves. */
6905 if (apploopnr == 0) raise (SIGIO);
6910 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6911 drag events will go directly to the EmacsScroller. Leaving in for now. */
6912 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6913 x: (Lisp_Object *)x y: ( Lisp_Object *)y
6915 *part = last_hit_part;
6917 XSETINT (*y, pixel_height);
6918 if ([self floatValue] > 0.999)
6919 XSETINT (*x, pixel_height);
6921 XSETINT (*x, pixel_height * [self floatValue]);
6925 /* set up emacs_event */
6926 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6931 emacs_event->part = last_hit_part;
6932 emacs_event->code = 0;
6933 emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
6934 emacs_event->frame_or_window = win;
6935 emacs_event->timestamp = EV_TIMESTAMP (e);
6936 emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
6937 emacs_event->arg = Qnil;
6938 XSETINT (emacs_event->x, loc * pixel_height);
6939 XSETINT (emacs_event->y, pixel_height-20);
6943 n_emacs_events_pending++;
6944 kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
6947 hold_event (emacs_event);
6948 EVENT_INIT (*emacs_event);
6949 ns_send_appdefined (-1);
6953 /* called manually thru timer to implement repeated button action w/hold-down */
6954 - repeatScroll: (NSTimer *)scrollEntry
6956 NSEvent *e = [[self window] currentEvent];
6957 NSPoint p = [[self window] mouseLocationOutsideOfEventStream];
6958 BOOL inKnob = [self testPart: p] == NSScrollerKnob;
6960 /* clear timer if need be */
6961 if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
6963 [scroll_repeat_entry invalidate];
6964 [scroll_repeat_entry release];
6965 scroll_repeat_entry = nil;
6971 = [[NSTimer scheduledTimerWithTimeInterval:
6972 SCROLL_BAR_CONTINUOUS_DELAY
6974 selector: @selector (repeatScroll:)
6980 [self sendScrollEventAtLoc: 0 fromEvent: e];
6985 /* Asynchronous mouse tracking for scroller. This allows us to dispatch
6986 mouseDragged events without going into a modal loop. */
6987 - (void)mouseDown: (NSEvent *)e
6990 /* hitPart is only updated AFTER event is passed on */
6991 NSScrollerPart part = [self testPart: [e locationInWindow]];
6992 double inc = 0.0, loc, kloc, pos;
6995 NSTRACE (EmacsScroller_mouseDown);
6999 case NSScrollerDecrementPage:
7000 last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
7001 case NSScrollerIncrementPage:
7002 last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
7003 case NSScrollerDecrementLine:
7004 last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
7005 case NSScrollerIncrementLine:
7006 last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
7007 case NSScrollerKnob:
7008 last_hit_part = scroll_bar_handle; break;
7009 case NSScrollerKnobSlot: /* GNUstep-only */
7010 last_hit_part = scroll_bar_move_ratio; break;
7011 default: /* NSScrollerNoPart? */
7012 fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
7019 pos = 0; /* ignored */
7021 /* set a timer to repeat, as we can't let superclass do this modally */
7023 = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
7025 selector: @selector (repeatScroll:)
7032 /* handle, or on GNUstep possibly slot */
7033 NSEvent *fake_event;
7035 /* compute float loc in slot and mouse offset on knob */
7036 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7038 loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7044 else if (loc >= NSHeight (sr))
7046 loc = NSHeight (sr);
7054 kr = [self convertRect: [self rectForPart: NSScrollerKnob]
7056 kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
7058 last_mouse_offset = kloc;
7060 /* if knob, tell emacs a location offset by knob pos
7061 (to indicate top of handle) */
7062 if (part == NSScrollerKnob)
7063 pos = (loc - last_mouse_offset) / NSHeight (sr);
7065 /* else this is a slot click on GNUstep: go straight there */
7066 pos = loc / NSHeight (sr);
7068 /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
7069 fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
7070 location: [e locationInWindow]
7071 modifierFlags: [e modifierFlags]
7072 timestamp: [e timestamp]
7073 windowNumber: [e windowNumber]
7074 context: [e context]
7075 eventNumber: [e eventNumber]
7076 clickCount: [e clickCount]
7077 pressure: [e pressure]];
7078 [super mouseUp: fake_event];
7081 if (part != NSScrollerKnob)
7082 [self sendScrollEventAtLoc: pos fromEvent: e];
7086 /* Called as we manually track scroller drags, rather than superclass. */
7087 - (void)mouseDragged: (NSEvent *)e
7093 NSTRACE (EmacsScroller_mouseDragged);
7095 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7097 loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7104 else if (loc >= NSHeight (sr) + last_mouse_offset)
7106 loc = NSHeight (sr) + last_mouse_offset;
7110 pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
7111 [self sendScrollEventAtLoc: pos fromEvent: e];
7115 - (void)mouseUp: (NSEvent *)e
7117 if (scroll_repeat_entry)
7119 [scroll_repeat_entry invalidate];
7120 [scroll_repeat_entry release];
7121 scroll_repeat_entry = nil;
7127 /* treat scrollwheel events in the bar as though they were in the main window */
7128 - (void) scrollWheel: (NSEvent *)theEvent
7130 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
7131 [view mouseDown: theEvent];
7134 @end /* EmacsScroller */
7139 /* ==========================================================================
7141 Font-related functions; these used to be in nsfaces.m
7143 ========================================================================== */
7147 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
7149 struct font *font = XFONT_OBJECT (font_object);
7152 fontset = fontset_from_font (font_object);
7153 FRAME_FONTSET (f) = fontset;
7155 if (FRAME_FONT (f) == font)
7156 /* This font is already set in frame F. There's nothing more to
7160 FRAME_FONT (f) = font;
7162 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
7163 FRAME_COLUMN_WIDTH (f) = font->average_width;
7164 FRAME_LINE_HEIGHT (f) = font->height;
7166 compute_fringe_widths (f, 1);
7168 /* Compute the scroll bar width in character columns. */
7169 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
7171 int wid = FRAME_COLUMN_WIDTH (f);
7172 FRAME_CONFIG_SCROLL_BAR_COLS (f)
7173 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
7177 int wid = FRAME_COLUMN_WIDTH (f);
7178 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
7181 /* Now make the frame display the given font. */
7182 if (FRAME_NS_WINDOW (f) != 0)
7183 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
7189 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
7190 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
7194 ns_xlfd_to_fontname (const char *xlfd)
7195 /* --------------------------------------------------------------------------
7196 Convert an X font name (XLFD) to an NS font name.
7197 Only family is used.
7198 The string returned is temporarily allocated.
7199 -------------------------------------------------------------------------- */
7201 char *name = xmalloc (180);
7205 if (!strncmp (xlfd, "--", 2))
7206 sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7208 sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7210 /* stopgap for malformed XLFD input */
7211 if (strlen (name) == 0)
7212 strcpy (name, "Monaco");
7214 /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7215 also uppercase after '-' or ' ' */
7216 name[0] = c_toupper (name[0]);
7217 for (len =strlen (name), i =0; i<len; i++)
7223 name[i+1] = c_toupper (name[i+1]);
7225 else if (name[i] == '_')
7229 name[i+1] = c_toupper (name[i+1]);
7232 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name); */
7233 ret = [[NSString stringWithUTF8String: name] UTF8String];
7240 syms_of_nsterm (void)
7242 NSTRACE (syms_of_nsterm);
7244 ns_antialias_threshold = 10.0;
7246 /* from 23+ we need to tell emacs what modifiers there are.. */
7247 DEFSYM (Qmodifier_value, "modifier-value");
7248 DEFSYM (Qalt, "alt");
7249 DEFSYM (Qhyper, "hyper");
7250 DEFSYM (Qmeta, "meta");
7251 DEFSYM (Qsuper, "super");
7252 DEFSYM (Qcontrol, "control");
7253 DEFSYM (QUTF8_STRING, "UTF8_STRING");
7255 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7256 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7257 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7258 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7259 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7261 DEFVAR_LISP ("ns-input-file", ns_input_file,
7262 "The file specified in the last NS event.");
7263 ns_input_file =Qnil;
7265 DEFVAR_LISP ("ns-input-text", ns_input_text,
7266 "The data received in the last NS text drag event.");
7267 ns_input_text =Qnil;
7269 DEFVAR_LISP ("ns-working-text", ns_working_text,
7270 "String for visualizing working composition sequence.");
7271 ns_working_text =Qnil;
7273 DEFVAR_LISP ("ns-input-font", ns_input_font,
7274 "The font specified in the last NS event.");
7275 ns_input_font =Qnil;
7277 DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7278 "The fontsize specified in the last NS event.");
7279 ns_input_fontsize =Qnil;
7281 DEFVAR_LISP ("ns-input-line", ns_input_line,
7282 "The line specified in the last NS event.");
7283 ns_input_line =Qnil;
7285 DEFVAR_LISP ("ns-input-color", ns_input_color,
7286 "The color specified in the last NS event.");
7287 ns_input_color =Qnil;
7289 DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7290 "The service name specified in the last NS event.");
7291 ns_input_spi_name =Qnil;
7293 DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7294 "The service argument specified in the last NS event.");
7295 ns_input_spi_arg =Qnil;
7297 DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7298 "This variable describes the behavior of the alternate or option key.\n\
7299 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7300 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7301 at all, allowing it to be used at a lower level for accented character entry.");
7302 ns_alternate_modifier = Qmeta;
7304 DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7305 "This variable describes the behavior of the right alternate or option key.\n\
7306 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7307 Set to left means be the same key as `ns-alternate-modifier'.\n\
7308 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7309 at all, allowing it to be used at a lower level for accented character entry.");
7310 ns_right_alternate_modifier = Qleft;
7312 DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7313 "This variable describes the behavior of the command key.\n\
7314 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7315 ns_command_modifier = Qsuper;
7317 DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7318 "This variable describes the behavior of the right command key.\n\
7319 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7320 Set to left means be the same key as `ns-command-modifier'.\n\
7321 Set to none means that the command / option key is not interpreted by Emacs\n\
7322 at all, allowing it to be used at a lower level for accented character entry.");
7323 ns_right_command_modifier = Qleft;
7325 DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7326 "This variable describes the behavior of the control key.\n\
7327 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7328 ns_control_modifier = Qcontrol;
7330 DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7331 "This variable describes the behavior of the right control key.\n\
7332 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7333 Set to left means be the same key as `ns-control-modifier'.\n\
7334 Set to none means that the control / option key is not interpreted by Emacs\n\
7335 at all, allowing it to be used at a lower level for accented character entry.");
7336 ns_right_control_modifier = Qleft;
7338 DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7339 "This variable describes the behavior of the function key (on laptops).\n\
7340 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7341 Set to none means that the function key is not interpreted by Emacs at all,\n\
7342 allowing it to be used at a lower level for accented character entry.");
7343 ns_function_modifier = Qnone;
7345 DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7346 "Non-nil (the default) means to render text antialiased.");
7347 ns_antialias_text = Qt;
7349 DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7350 "Whether to confirm application quit using dialog.");
7351 ns_confirm_quit = Qnil;
7353 staticpro (&ns_display_name_list);
7354 ns_display_name_list = Qnil;
7356 staticpro (&last_mouse_motion_frame);
7357 last_mouse_motion_frame = Qnil;
7359 DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7360 doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7361 Only works on OSX 10.6 or later. */);
7362 ns_auto_hide_menu_bar = Qnil;
7364 DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
7365 doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
7366 Nil means use fullscreen the old (< 10.7) way. The old way works better with
7367 multiple monitors, but lacks tool bar. This variable is ignored on OSX < 10.7.
7368 Default is t for OSX >= 10.7, nil otherwise. */);
7369 #ifdef HAVE_NATIVE_FS
7370 ns_use_native_fullscreen = YES;
7372 ns_use_native_fullscreen = NO;
7374 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
7376 /* TODO: move to common code */
7377 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7378 doc: /* Which toolkit scroll bars Emacs uses, if any.
7379 A value of nil means Emacs doesn't use toolkit scroll bars.
7380 With the X Window system, the value is a symbol describing the
7381 X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
7382 With MS Windows or Nextstep, the value is t. */);
7383 Vx_toolkit_scroll_bars = Qt;
7385 DEFVAR_BOOL ("x-use-underline-position-properties",
7386 x_use_underline_position_properties,
7387 doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7388 A value of nil means ignore them. If you encounter fonts with bogus
7389 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7390 to 4.1, set this to nil. */);
7391 x_use_underline_position_properties = 0;
7393 DEFVAR_BOOL ("x-underline-at-descent-line",
7394 x_underline_at_descent_line,
7395 doc: /* Non-nil means to draw the underline at the same place as the descent line.
7396 A value of nil means to draw the underline according to the value of the
7397 variable `x-use-underline-position-properties', which is usually at the
7398 baseline level. The default value is nil. */);
7399 x_underline_at_descent_line = 0;
7401 /* Tell emacs about this window system. */
7402 Fprovide (intern ("ns"), Qnil);