1 /* NeXT/Open/GNUstep / MacOSX communication module.
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2015 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"
63 #ifdef NS_IMPL_GNUSTEP
68 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
75 int term_trace_num = 0;
76 #define NSTRACE(x) fprintf (stderr, "%s:%d: [%d] " #x "\n", \
77 __FILE__, __LINE__, ++term_trace_num)
82 /* Detailed tracing. "S" means "size" and "LL" stands for "lower left". */
84 int term_trace_num = 0;
85 #define NSTRACE_SIZE(str,size) fprintf (stderr, \
87 " (S:%.0f x %.0f)\n", \
88 __FILE__, __LINE__, ++term_trace_num,\
91 #define NSTRACE_RECT(s,r) fprintf (stderr, \
93 " (LL:%.0f x %.0f -> S:%.0f x %.0f)\n", \
94 __FILE__, __LINE__, ++term_trace_num,\
100 #define NSTRACE_SIZE(str,size)
101 #define NSTRACE_RECT(s,r)
104 extern NSString *NSMenuDidBeginTrackingNotification;
106 /* ==========================================================================
108 NSColor, EmacsColor category.
110 ========================================================================== */
111 @implementation NSColor (EmacsColor)
112 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
113 blue:(CGFloat)blue alpha:(CGFloat)alpha
116 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
117 if (ns_use_srgb_colorspace)
118 return [NSColor colorWithSRGBRed: red
124 return [NSColor colorWithCalibratedRed: red
130 - (NSColor *)colorUsingDefaultColorSpace
133 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
134 if (ns_use_srgb_colorspace)
135 return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
138 return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
143 /* ==========================================================================
147 ========================================================================== */
149 /* Convert a symbol indexed with an NSxxx value to a value as defined
150 in keyboard.c (lispy_function_key). I hope this is a correct way
151 of doing things... */
152 static unsigned convert_ns_to_X_keysym[] =
154 NSHomeFunctionKey, 0x50,
155 NSLeftArrowFunctionKey, 0x51,
156 NSUpArrowFunctionKey, 0x52,
157 NSRightArrowFunctionKey, 0x53,
158 NSDownArrowFunctionKey, 0x54,
159 NSPageUpFunctionKey, 0x55,
160 NSPageDownFunctionKey, 0x56,
161 NSEndFunctionKey, 0x57,
162 NSBeginFunctionKey, 0x58,
163 NSSelectFunctionKey, 0x60,
164 NSPrintFunctionKey, 0x61,
165 NSClearLineFunctionKey, 0x0B,
166 NSExecuteFunctionKey, 0x62,
167 NSInsertFunctionKey, 0x63,
168 NSUndoFunctionKey, 0x65,
169 NSRedoFunctionKey, 0x66,
170 NSMenuFunctionKey, 0x67,
171 NSFindFunctionKey, 0x68,
172 NSHelpFunctionKey, 0x6A,
173 NSBreakFunctionKey, 0x6B,
175 NSF1FunctionKey, 0xBE,
176 NSF2FunctionKey, 0xBF,
177 NSF3FunctionKey, 0xC0,
178 NSF4FunctionKey, 0xC1,
179 NSF5FunctionKey, 0xC2,
180 NSF6FunctionKey, 0xC3,
181 NSF7FunctionKey, 0xC4,
182 NSF8FunctionKey, 0xC5,
183 NSF9FunctionKey, 0xC6,
184 NSF10FunctionKey, 0xC7,
185 NSF11FunctionKey, 0xC8,
186 NSF12FunctionKey, 0xC9,
187 NSF13FunctionKey, 0xCA,
188 NSF14FunctionKey, 0xCB,
189 NSF15FunctionKey, 0xCC,
190 NSF16FunctionKey, 0xCD,
191 NSF17FunctionKey, 0xCE,
192 NSF18FunctionKey, 0xCF,
193 NSF19FunctionKey, 0xD0,
194 NSF20FunctionKey, 0xD1,
195 NSF21FunctionKey, 0xD2,
196 NSF22FunctionKey, 0xD3,
197 NSF23FunctionKey, 0xD4,
198 NSF24FunctionKey, 0xD5,
200 NSBackspaceCharacter, 0x08, /* 8: Not on some KBs. */
201 NSDeleteCharacter, 0xFF, /* 127: Big 'delete' key upper right. */
202 NSDeleteFunctionKey, 0x9F, /* 63272: Del forw key off main array. */
204 NSTabCharacter, 0x09,
205 0x19, 0x09, /* left tab->regular since pass shift */
206 NSCarriageReturnCharacter, 0x0D,
207 NSNewlineCharacter, 0x0D,
208 NSEnterCharacter, 0x8D,
210 0x41|NSNumericPadKeyMask, 0xAE, /* KP_Decimal */
211 0x43|NSNumericPadKeyMask, 0xAA, /* KP_Multiply */
212 0x45|NSNumericPadKeyMask, 0xAB, /* KP_Add */
213 0x4B|NSNumericPadKeyMask, 0xAF, /* KP_Divide */
214 0x4E|NSNumericPadKeyMask, 0xAD, /* KP_Subtract */
215 0x51|NSNumericPadKeyMask, 0xBD, /* KP_Equal */
216 0x52|NSNumericPadKeyMask, 0xB0, /* KP_0 */
217 0x53|NSNumericPadKeyMask, 0xB1, /* KP_1 */
218 0x54|NSNumericPadKeyMask, 0xB2, /* KP_2 */
219 0x55|NSNumericPadKeyMask, 0xB3, /* KP_3 */
220 0x56|NSNumericPadKeyMask, 0xB4, /* KP_4 */
221 0x57|NSNumericPadKeyMask, 0xB5, /* KP_5 */
222 0x58|NSNumericPadKeyMask, 0xB6, /* KP_6 */
223 0x59|NSNumericPadKeyMask, 0xB7, /* KP_7 */
224 0x5B|NSNumericPadKeyMask, 0xB8, /* KP_8 */
225 0x5C|NSNumericPadKeyMask, 0xB9, /* KP_9 */
227 0x1B, 0x1B /* escape */
230 static Lisp_Object Qmodifier_value;
231 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper;
232 extern Lisp_Object Qcursor_color, Qcursor_type, Qns, Qleft;
234 static Lisp_Object QUTF8_STRING;
235 static Lisp_Object Qcocoa, Qgnustep;
236 static Lisp_Object Qfile, Qurl;
238 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
239 the maximum font size to NOT antialias. On GNUstep there is currently
240 no way to control this behavior. */
241 float ns_antialias_threshold;
243 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
244 NSString *ns_app_name = @"Emacs"; /* default changed later */
246 /* Display variables */
247 struct ns_display_info *x_display_list; /* Chain of existing displays */
248 long context_menu_value = 0;
251 static struct frame *ns_updating_frame;
252 static NSView *focus_view = NULL;
253 static int ns_window_num = 0;
254 #ifdef NS_IMPL_GNUSTEP
257 static BOOL gsaved = NO;
258 static BOOL ns_fake_keydown = NO;
260 static BOOL ns_menu_bar_is_hidden = NO;
262 /*static int debug_lock = 0; */
265 static BOOL send_appdefined = YES;
266 #define NO_APPDEFINED_DATA (-8)
267 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
268 static NSTimer *timed_entry = 0;
269 static NSTimer *scroll_repeat_entry = nil;
270 static fd_set select_readfds, select_writefds;
271 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
272 static int select_nfds = 0, select_valid = 0;
273 static struct timespec select_timeout = { 0, 0 };
274 static int selfds[2] = { -1, -1 };
275 static pthread_mutex_t select_mutex;
276 static int apploopnr = 0;
277 static NSAutoreleasePool *outerpool;
278 static struct input_event *emacs_event = NULL;
279 static struct input_event *q_event_ptr = NULL;
280 static int n_emacs_events_pending = 0;
281 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
282 *ns_pending_service_args;
283 static BOOL ns_do_open_file = NO;
284 static BOOL ns_last_use_native_fullscreen;
287 struct input_event *q;
293 static NSString *represented_filename = nil;
294 static struct frame *represented_frame = 0;
298 * State for pending menu activation:
299 * MENU_NONE Normal state
300 * MENU_PENDING A menu has been clicked on, but has been canceled so we can
301 * run lisp to update the menu.
302 * MENU_OPENING Menu is up to date, and the click event is redone so the menu
306 #define MENU_PENDING 1
307 #define MENU_OPENING 2
308 static int menu_will_open_state = MENU_NONE;
310 /* Saved position for menu click. */
311 static CGPoint menu_mouse_point;
314 /* Convert modifiers in a NeXTstep event to emacs style modifiers. */
315 #define NS_FUNCTION_KEY_MASK 0x800000
316 #define NSLeftControlKeyMask (0x000001 | NSControlKeyMask)
317 #define NSRightControlKeyMask (0x002000 | NSControlKeyMask)
318 #define NSLeftCommandKeyMask (0x000008 | NSCommandKeyMask)
319 #define NSRightCommandKeyMask (0x000010 | NSCommandKeyMask)
320 #define NSLeftAlternateKeyMask (0x000020 | NSAlternateKeyMask)
321 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
322 #define EV_MODIFIERS2(flags) \
323 (((flags & NSHelpKeyMask) ? \
324 hyper_modifier : 0) \
325 | (!EQ (ns_right_alternate_modifier, Qleft) && \
326 ((flags & NSRightAlternateKeyMask) \
327 == NSRightAlternateKeyMask) ? \
328 parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
329 | ((flags & NSAlternateKeyMask) ? \
330 parse_solitary_modifier (ns_alternate_modifier) : 0) \
331 | ((flags & NSShiftKeyMask) ? \
332 shift_modifier : 0) \
333 | (!EQ (ns_right_control_modifier, Qleft) && \
334 ((flags & NSRightControlKeyMask) \
335 == NSRightControlKeyMask) ? \
336 parse_solitary_modifier (ns_right_control_modifier) : 0) \
337 | ((flags & NSControlKeyMask) ? \
338 parse_solitary_modifier (ns_control_modifier) : 0) \
339 | ((flags & NS_FUNCTION_KEY_MASK) ? \
340 parse_solitary_modifier (ns_function_modifier) : 0) \
341 | (!EQ (ns_right_command_modifier, Qleft) && \
342 ((flags & NSRightCommandKeyMask) \
343 == NSRightCommandKeyMask) ? \
344 parse_solitary_modifier (ns_right_command_modifier) : 0) \
345 | ((flags & NSCommandKeyMask) ? \
346 parse_solitary_modifier (ns_command_modifier):0))
347 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
349 #define EV_UDMODIFIERS(e) \
350 ((([e type] == NSLeftMouseDown) ? down_modifier : 0) \
351 | (([e type] == NSRightMouseDown) ? down_modifier : 0) \
352 | (([e type] == NSOtherMouseDown) ? down_modifier : 0) \
353 | (([e type] == NSLeftMouseDragged) ? down_modifier : 0) \
354 | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
355 | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
356 | (([e type] == NSLeftMouseUp) ? up_modifier : 0) \
357 | (([e type] == NSRightMouseUp) ? up_modifier : 0) \
358 | (([e type] == NSOtherMouseUp) ? up_modifier : 0))
360 #define EV_BUTTON(e) \
361 ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 : \
362 (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
363 [e buttonNumber] - 1)
365 /* Convert the time field to a timestamp in milliseconds. */
366 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
368 /* This is a piece of code which is common to all the event handling
369 methods. Maybe it should even be a function. */
370 #define EV_TRAILER(e) \
372 XSETFRAME (emacs_event->frame_or_window, emacsframe); \
376 #define EV_TRAILER2(e) \
378 if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \
381 n_emacs_events_pending++; \
382 kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \
385 hold_event (emacs_event); \
386 EVENT_INIT (*emacs_event); \
387 ns_send_appdefined (-1); \
390 /* TODO: get rid of need for these forward declarations */
391 static void ns_condemn_scroll_bars (struct frame *f);
392 static void ns_judge_scroll_bars (struct frame *f);
393 void x_set_frame_alpha (struct frame *f);
396 /* ==========================================================================
400 ========================================================================== */
403 ns_set_represented_filename (NSString* fstr, struct frame *f)
405 represented_filename = [fstr retain];
406 represented_frame = f;
411 hold_event (struct input_event *event)
413 if (hold_event_q.nr == hold_event_q.cap)
415 if (hold_event_q.cap == 0) hold_event_q.cap = 10;
416 else hold_event_q.cap *= 2;
418 xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
421 hold_event_q.q[hold_event_q.nr++] = *event;
422 /* Make sure ns_read_socket is called, i.e. we have input. */
424 send_appdefined = YES;
428 append2 (Lisp_Object list, Lisp_Object item)
429 /* --------------------------------------------------------------------------
430 Utility to append to a list
431 -------------------------------------------------------------------------- */
433 Lisp_Object array[2];
435 array[1] = list1 (item);
436 return Fnconc (2, &array[0]);
441 ns_etc_directory (void)
442 /* If running as a self-contained app bundle, return as a string the
443 filename of the etc directory, if present; else nil. */
445 NSBundle *bundle = [NSBundle mainBundle];
446 NSString *resourceDir = [bundle resourcePath];
447 NSString *resourcePath;
448 NSFileManager *fileManager = [NSFileManager defaultManager];
451 resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
452 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
454 if (isDir) return [resourcePath UTF8String];
462 /* If running as a self-contained app bundle, return as a path string
463 the filenames of the libexec and bin directories, ie libexec:bin.
464 Otherwise, return nil.
465 Normally, Emacs does not add its own bin/ directory to the PATH.
466 However, a self-contained NS build has a different layout, with
467 bin/ and libexec/ subdirectories in the directory that contains
469 We put libexec first, because init_callproc_1 uses the first
470 element to initialize exec-directory. An alternative would be
471 for init_callproc to check for invocation-directory/libexec.
474 NSBundle *bundle = [NSBundle mainBundle];
475 NSString *resourceDir = [bundle resourcePath];
476 NSString *binDir = [bundle bundlePath];
477 NSString *resourcePath, *resourcePaths;
479 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
480 NSFileManager *fileManager = [NSFileManager defaultManager];
482 NSEnumerator *pathEnum;
485 range = [resourceDir rangeOfString: @"Contents"];
486 if (range.location != NSNotFound)
488 binDir = [binDir stringByAppendingPathComponent: @"Contents"];
490 binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
494 paths = [binDir stringsByAppendingPaths:
495 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
496 pathEnum = [paths objectEnumerator];
499 while ((resourcePath = [pathEnum nextObject]))
501 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
504 if ([resourcePaths length] > 0)
506 = [resourcePaths stringByAppendingString: pathSeparator];
508 = [resourcePaths stringByAppendingString: resourcePath];
511 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
519 /* If running as a self-contained app bundle, return as a path string
520 the filenames of the site-lisp and lisp directories.
521 Ie, site-lisp:lisp. Otherwise, return nil. */
523 NSBundle *bundle = [NSBundle mainBundle];
524 NSString *resourceDir = [bundle resourcePath];
525 NSString *resourcePath, *resourcePaths;
526 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
527 NSFileManager *fileManager = [NSFileManager defaultManager];
529 NSArray *paths = [resourceDir stringsByAppendingPaths:
530 [NSArray arrayWithObjects:
531 @"site-lisp", @"lisp", nil]];
532 NSEnumerator *pathEnum = [paths objectEnumerator];
535 /* Hack to skip site-lisp. */
536 if (no_site_lisp) resourcePath = [pathEnum nextObject];
538 while ((resourcePath = [pathEnum nextObject]))
540 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
543 if ([resourcePaths length] > 0)
545 = [resourcePaths stringByAppendingString: pathSeparator];
547 = [resourcePaths stringByAppendingString: resourcePath];
550 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
556 ns_timeout (int usecs)
557 /* --------------------------------------------------------------------------
558 Blocking timer utility used by ns_ring_bell
559 -------------------------------------------------------------------------- */
561 struct timespec wakeup = timespec_add (current_timespec (),
562 make_timespec (0, usecs * 1000));
564 /* Keep waiting until past the time wakeup. */
567 struct timespec timeout, now = current_timespec ();
568 if (timespec_cmp (wakeup, now) <= 0)
570 timeout = timespec_sub (wakeup, now);
572 /* Try to wait that long--but we might wake up sooner. */
573 pselect (0, NULL, NULL, NULL, &timeout, NULL);
579 ns_release_object (void *obj)
580 /* --------------------------------------------------------------------------
581 Release an object (callable from C)
582 -------------------------------------------------------------------------- */
589 ns_retain_object (void *obj)
590 /* --------------------------------------------------------------------------
591 Retain an object (callable from C)
592 -------------------------------------------------------------------------- */
599 ns_alloc_autorelease_pool (void)
600 /* --------------------------------------------------------------------------
601 Allocate a pool for temporary objects (callable from C)
602 -------------------------------------------------------------------------- */
604 return [[NSAutoreleasePool alloc] init];
609 ns_release_autorelease_pool (void *pool)
610 /* --------------------------------------------------------------------------
611 Free a pool and temporary objects it refers to (callable from C)
612 -------------------------------------------------------------------------- */
614 ns_release_object (pool);
619 /* ==========================================================================
621 Focus (clipping) and screen update
623 ========================================================================== */
626 // Window constraining
627 // -------------------
629 // To ensure that the windows are not placed under the menu bar, they
630 // are typically moved by the call-back constrainFrameRect. However,
631 // by overriding it, it's possible to inhibit this, leaving the window
632 // in it's original position.
634 // It's possible to hide the menu bar. However, technically, it's only
635 // possible to hide it when the application is active. To ensure that
636 // this work properly, the menu bar and window constraining are
637 // deferred until the application becomes active.
639 // Even though it's not possible to manually move a window above the
640 // top of the screen, it is allowed if it's done programmatically,
641 // when the menu is hidden. This allows the editable area to cover the
642 // full screen height.
647 // Use the following extra files:
650 // ;; Hide menu and place frame slightly above the top of the screen.
651 // (setq ns-auto-hide-menu-bar t)
652 // (set-frame-position (selected-frame) 0 -20)
656 // emacs -Q -l init.el
658 // Result: No menu bar, and the title bar should be above the screen.
664 // Result: Menu bar visible, frame placed immediately below the menu.
668 ns_constrain_all_frames (void)
670 Lisp_Object tail, frame;
672 FOR_EACH_FRAME (tail, frame)
674 struct frame *f = XFRAME (frame);
677 NSView *view = FRAME_NS_VIEW (f);
678 /* This no-op will trigger the default window placing
679 * constraint system. */
680 [[view window] setFrameOrigin:[[view window] frame].origin];
686 /* True, if the menu bar should be hidden. */
689 ns_menu_bar_should_be_hidden (void)
691 return !NILP (ns_auto_hide_menu_bar)
692 && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
696 /* Show or hide the menu bar, based on user setting. */
699 ns_update_auto_hide_menu_bar (void)
702 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
705 NSTRACE (ns_update_auto_hide_menu_bar);
707 if (NSApp != nil && [NSApp isActive])
709 // Note, "setPresentationOptions" triggers an error unless the
710 // application is active.
711 BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
713 if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
715 NSApplicationPresentationOptions options
716 = NSApplicationPresentationDefault;
718 if (menu_bar_should_be_hidden)
719 options |= NSApplicationPresentationAutoHideMenuBar
720 | NSApplicationPresentationAutoHideDock;
722 [NSApp setPresentationOptions: options];
724 ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
726 if (!ns_menu_bar_is_hidden)
728 ns_constrain_all_frames ();
740 ns_update_begin (struct frame *f)
741 /* --------------------------------------------------------------------------
742 Prepare for a grouped sequence of drawing calls
743 external (RIF) call; whole frame, called before update_window_begin
744 -------------------------------------------------------------------------- */
746 EmacsView *view = FRAME_NS_VIEW (f);
747 NSTRACE (ns_update_begin);
749 ns_update_auto_hide_menu_bar ();
752 if ([view isFullscreen] && [view fsIsNative])
754 // Fix reappearing tool bar in fullscreen for OSX 10.7
755 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
756 NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
757 if (! tbar_visible != ! [toolbar isVisible])
758 [toolbar setVisible: tbar_visible];
762 ns_updating_frame = f;
765 /* drawRect may have been called for say the minibuffer, and then clip path
766 is for the minibuffer. But the display engine may draw more because
767 we have set the frame as garbaged. So reset clip path to the whole
772 NSRect r = [view frame];
773 NSRect cr = [[view window] frame];
774 /* If a large frame size is set, r may be larger than the window frame
775 before constrained. In that case don't change the clip path, as we
776 will clear in to the tool bar and title bar. */
778 + FRAME_NS_TITLEBAR_HEIGHT (f)
779 + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
781 bp = [[NSBezierPath bezierPathWithRect: r] retain];
788 #ifdef NS_IMPL_GNUSTEP
789 uRect = NSMakeRect (0, 0, 0, 0);
795 ns_update_window_begin (struct window *w)
796 /* --------------------------------------------------------------------------
797 Prepare for a grouped sequence of drawing calls
798 external (RIF) call; for one window, called after update_begin
799 -------------------------------------------------------------------------- */
801 struct frame *f = XFRAME (WINDOW_FRAME (w));
802 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
804 NSTRACE (ns_update_window_begin);
805 w->output_cursor = w->cursor;
809 if (f == hlinfo->mouse_face_mouse_frame)
811 /* Don't do highlighting for mouse motion during the update. */
812 hlinfo->mouse_face_defer = 1;
814 /* If the frame needs to be redrawn,
815 simply forget about any prior mouse highlighting. */
816 if (FRAME_GARBAGED_P (f))
817 hlinfo->mouse_face_window = Qnil;
819 /* (further code for mouse faces ifdef'd out in other terms elided) */
827 ns_update_window_end (struct window *w, bool cursor_on_p,
828 bool mouse_face_overwritten_p)
829 /* --------------------------------------------------------------------------
830 Finished a grouped sequence of drawing calls
831 external (RIF) call; for one window called before update_end
832 -------------------------------------------------------------------------- */
834 /* note: this fn is nearly identical in all terms */
835 if (!w->pseudo_window_p)
840 display_and_set_cursor (w, 1,
841 w->output_cursor.hpos, w->output_cursor.vpos,
842 w->output_cursor.x, w->output_cursor.y);
844 if (draw_window_fringes (w, 1))
846 if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
847 x_draw_right_divider (w);
849 x_draw_vertical_border (w);
855 /* If a row with mouse-face was overwritten, arrange for
856 frame_up_to_date to redisplay the mouse highlight. */
857 if (mouse_face_overwritten_p)
858 reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
860 NSTRACE (update_window_end);
865 ns_update_end (struct frame *f)
866 /* --------------------------------------------------------------------------
867 Finished a grouped sequence of drawing calls
868 external (RIF) call; for whole frame, called after update_window_end
869 -------------------------------------------------------------------------- */
871 EmacsView *view = FRAME_NS_VIEW (f);
873 /* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
874 MOUSE_HL_INFO (f)->mouse_face_defer = 0;
879 [[view window] flushWindow];
882 ns_updating_frame = NULL;
883 NSTRACE (ns_update_end);
887 ns_focus (struct frame *f, NSRect *r, int n)
888 /* --------------------------------------------------------------------------
889 Internal: Focus on given frame. During small local updates this is used to
890 draw, however during large updates, ns_update_begin and ns_update_end are
891 called to wrap the whole thing, in which case these calls are stubbed out.
892 Except, on GNUstep, we accumulate the rectangle being drawn into, because
893 the back end won't do this automatically, and will just end up flushing
895 -------------------------------------------------------------------------- */
897 // NSTRACE (ns_focus);
899 fprintf (stderr, "focus: %d", c++);
900 if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
901 fprintf (stderr, "\n"); */
903 if (f != ns_updating_frame)
905 NSView *view = FRAME_NS_VIEW (f);
906 if (view != focus_view)
908 if (focus_view != NULL)
910 [focus_view unlockFocus];
911 [[focus_view window] flushWindow];
918 /*if (view) debug_lock++; */
925 [[NSGraphicsContext currentContext] saveGraphicsState];
927 NSRectClipList (r, 2);
936 ns_unfocus (struct frame *f)
937 /* --------------------------------------------------------------------------
938 Internal: Remove focus on given frame
939 -------------------------------------------------------------------------- */
941 // NSTRACE (ns_unfocus);
945 [[NSGraphicsContext currentContext] restoreGraphicsState];
949 if (f != ns_updating_frame)
951 if (focus_view != NULL)
953 [focus_view unlockFocus];
954 [[focus_view window] flushWindow];
963 ns_clip_to_row (struct window *w, struct glyph_row *row,
964 enum glyph_row_area area, BOOL gc)
965 /* --------------------------------------------------------------------------
966 Internal (but parallels other terms): Focus drawing on given row
967 -------------------------------------------------------------------------- */
969 struct frame *f = XFRAME (WINDOW_FRAME (w));
971 int window_x, window_y, window_width;
973 window_box (w, area, &window_x, &window_y, &window_width, 0);
975 clip_rect.origin.x = window_x;
976 clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
977 clip_rect.origin.y = max (clip_rect.origin.y, window_y);
978 clip_rect.size.width = window_width;
979 clip_rect.size.height = row->visible_height;
981 ns_focus (f, &clip_rect, 1);
986 ns_ring_bell (struct frame *f)
987 /* --------------------------------------------------------------------------
989 -------------------------------------------------------------------------- */
991 NSTRACE (ns_ring_bell);
994 NSAutoreleasePool *pool;
995 struct frame *frame = SELECTED_FRAME ();
999 pool = [[NSAutoreleasePool alloc] init];
1001 view = FRAME_NS_VIEW (frame);
1005 NSPoint dim = NSMakePoint (128, 128);
1008 r.origin.x += (r.size.width - dim.x) / 2;
1009 r.origin.y += (r.size.height - dim.y) / 2;
1010 r.size.width = dim.x;
1011 r.size.height = dim.y;
1012 surr = NSInsetRect (r, -2, -2);
1013 ns_focus (frame, &surr, 1);
1014 [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
1015 [ns_lookup_indexed_color (NS_FACE_FOREGROUND
1016 (FRAME_DEFAULT_FACE (frame)), frame) set];
1018 [[view window] flushWindow];
1019 ns_timeout (150000);
1020 [[view window] restoreCachedImage];
1021 [[view window] flushWindow];
1033 /* ==========================================================================
1035 Frame / window manager related functions
1037 ========================================================================== */
1041 ns_raise_frame (struct frame *f)
1042 /* --------------------------------------------------------------------------
1043 Bring window to foreground and make it active
1044 -------------------------------------------------------------------------- */
1047 check_window_system (f);
1048 view = FRAME_NS_VIEW (f);
1050 if (FRAME_VISIBLE_P (f))
1051 [[view window] makeKeyAndOrderFront: NSApp];
1057 ns_lower_frame (struct frame *f)
1058 /* --------------------------------------------------------------------------
1060 -------------------------------------------------------------------------- */
1063 check_window_system (f);
1064 view = FRAME_NS_VIEW (f);
1066 [[view window] orderBack: NSApp];
1072 ns_frame_raise_lower (struct frame *f, int raise)
1073 /* --------------------------------------------------------------------------
1075 -------------------------------------------------------------------------- */
1077 NSTRACE (ns_frame_raise_lower);
1087 ns_frame_rehighlight (struct frame *frame)
1088 /* --------------------------------------------------------------------------
1089 External (hook): called on things like window switching within frame
1090 -------------------------------------------------------------------------- */
1092 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1093 struct frame *old_highlight = dpyinfo->x_highlight_frame;
1095 NSTRACE (ns_frame_rehighlight);
1096 if (dpyinfo->x_focus_frame)
1098 dpyinfo->x_highlight_frame
1099 = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1100 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1101 : dpyinfo->x_focus_frame);
1102 if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1104 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1105 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1109 dpyinfo->x_highlight_frame = 0;
1111 if (dpyinfo->x_highlight_frame &&
1112 dpyinfo->x_highlight_frame != old_highlight)
1116 x_update_cursor (old_highlight, 1);
1117 x_set_frame_alpha (old_highlight);
1119 if (dpyinfo->x_highlight_frame)
1121 x_update_cursor (dpyinfo->x_highlight_frame, 1);
1122 x_set_frame_alpha (dpyinfo->x_highlight_frame);
1129 x_make_frame_visible (struct frame *f)
1130 /* --------------------------------------------------------------------------
1131 External: Show the window (X11 semantics)
1132 -------------------------------------------------------------------------- */
1134 NSTRACE (x_make_frame_visible);
1135 /* XXX: at some points in past this was not needed, as the only place that
1136 called this (frame.c:Fraise_frame ()) also called raise_lower;
1137 if this ends up the case again, comment this out again. */
1138 if (!FRAME_VISIBLE_P (f))
1140 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1142 SET_FRAME_VISIBLE (f, 1);
1145 /* Making a new frame from a fullscreen frame will make the new frame
1146 fullscreen also. So skip handleFS as this will print an error. */
1147 if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1148 && [view isFullscreen])
1151 if (f->want_fullscreen != FULLSCREEN_NONE)
1162 x_make_frame_invisible (struct frame *f)
1163 /* --------------------------------------------------------------------------
1164 External: Hide the window (X11 semantics)
1165 -------------------------------------------------------------------------- */
1168 NSTRACE (x_make_frame_invisible);
1169 check_window_system (f);
1170 view = FRAME_NS_VIEW (f);
1171 [[view window] orderOut: NSApp];
1172 SET_FRAME_VISIBLE (f, 0);
1173 SET_FRAME_ICONIFIED (f, 0);
1178 x_iconify_frame (struct frame *f)
1179 /* --------------------------------------------------------------------------
1180 External: Iconify window
1181 -------------------------------------------------------------------------- */
1184 struct ns_display_info *dpyinfo;
1186 NSTRACE (x_iconify_frame);
1187 check_window_system (f);
1188 view = FRAME_NS_VIEW (f);
1189 dpyinfo = FRAME_DISPLAY_INFO (f);
1191 if (dpyinfo->x_highlight_frame == f)
1192 dpyinfo->x_highlight_frame = 0;
1194 if ([[view window] windowNumber] <= 0)
1196 /* the window is still deferred. Make it very small, bring it
1197 on screen and order it out. */
1198 NSRect s = { { 100, 100}, {0, 0} };
1200 t = [[view window] frame];
1201 [[view window] setFrame: s display: NO];
1202 [[view window] orderBack: NSApp];
1203 [[view window] orderOut: NSApp];
1204 [[view window] setFrame: t display: NO];
1206 [[view window] miniaturize: NSApp];
1209 /* Free X resources of frame F. */
1212 x_free_frame_resources (struct frame *f)
1215 struct ns_display_info *dpyinfo;
1216 Mouse_HLInfo *hlinfo;
1218 NSTRACE (x_free_frame_resources);
1219 check_window_system (f);
1220 view = FRAME_NS_VIEW (f);
1221 dpyinfo = FRAME_DISPLAY_INFO (f);
1222 hlinfo = MOUSE_HL_INFO (f);
1224 [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1228 free_frame_menubar (f);
1229 free_frame_faces (f);
1231 if (f == dpyinfo->x_focus_frame)
1232 dpyinfo->x_focus_frame = 0;
1233 if (f == dpyinfo->x_highlight_frame)
1234 dpyinfo->x_highlight_frame = 0;
1235 if (f == hlinfo->mouse_face_mouse_frame)
1236 reset_mouse_highlight (hlinfo);
1238 if (f->output_data.ns->miniimage != nil)
1239 [f->output_data.ns->miniimage release];
1241 [[view window] close];
1244 xfree (f->output_data.ns);
1250 x_destroy_window (struct frame *f)
1251 /* --------------------------------------------------------------------------
1252 External: Delete the window
1253 -------------------------------------------------------------------------- */
1255 NSTRACE (x_destroy_window);
1256 check_window_system (f);
1257 x_free_frame_resources (f);
1263 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1264 /* --------------------------------------------------------------------------
1265 External: Position the window
1266 -------------------------------------------------------------------------- */
1268 NSView *view = FRAME_NS_VIEW (f);
1269 NSArray *screens = [NSScreen screens];
1270 NSScreen *fscreen = [screens objectAtIndex: 0];
1271 NSScreen *screen = [[view window] screen];
1273 NSTRACE (x_set_offset);
1280 if (view != nil && screen && fscreen)
1282 f->left_pos = f->size_hint_flags & XNegative
1283 ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1285 /* We use visibleFrame here to take menu bar into account.
1286 Ideally we should also adjust left/top with visibleFrame.origin. */
1288 f->top_pos = f->size_hint_flags & YNegative
1289 ? ([screen visibleFrame].size.height + f->top_pos
1290 - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1291 - FRAME_TOOLBAR_HEIGHT (f))
1293 #ifdef NS_IMPL_GNUSTEP
1294 if (f->left_pos < 100)
1295 f->left_pos = 100; /* don't overlap menu */
1297 /* Constrain the setFrameTopLeftPoint so we don't move behind the
1299 [[view window] setFrameTopLeftPoint:
1300 NSMakePoint (SCREENMAXBOUND (f->left_pos),
1301 SCREENMAXBOUND ([fscreen frame].size.height
1302 - NS_TOP_POS (f)))];
1303 f->size_hint_flags &= ~(XNegative|YNegative);
1311 x_set_window_size (struct frame *f,
1316 /* --------------------------------------------------------------------------
1317 Adjust window pixel size based on given character grid size
1318 Impl is a bit more complex than other terms, need to do some
1320 -------------------------------------------------------------------------- */
1322 EmacsView *view = FRAME_NS_VIEW (f);
1323 NSWindow *window = [view window];
1324 NSRect wr = [window frame];
1325 int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1326 int pixelwidth, pixelheight;
1329 NSTRACE (x_set_window_size);
1334 /*fprintf (stderr, "\tsetWindowSize: %d x %d, pixelwise %d, font size %d x %d\n", width, height, pixelwise, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));*/
1338 check_frame_size (f, &width, &height, pixelwise);
1340 compute_fringe_widths (f, 0);
1344 pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1345 pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1346 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
1347 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
1351 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width);
1352 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1357 /* If we have a toolbar, take its height into account. */
1358 if (tb && ! [view isFullscreen])
1360 /* NOTE: previously this would generate wrong result if toolbar not
1361 yet displayed and fixing toolbar_height=32 helped, but
1362 now (200903) seems no longer needed */
1363 FRAME_TOOLBAR_HEIGHT (f) =
1364 NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1365 - FRAME_NS_TITLEBAR_HEIGHT (f);
1366 #ifdef NS_IMPL_GNUSTEP
1367 FRAME_TOOLBAR_HEIGHT (f) -= 3;
1371 FRAME_TOOLBAR_HEIGHT (f) = 0;
1373 wr.size.width = pixelwidth + f->border_width;
1374 wr.size.height = pixelheight;
1375 if (! [view isFullscreen])
1376 wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1377 + FRAME_TOOLBAR_HEIGHT (f);
1379 /* Do not try to constrain to this screen. We may have multiple
1380 screens, and want Emacs to span those. Constraining to screen
1381 prevents that, and that is not nice to the user. */
1382 if (f->output_data.ns->zooming)
1383 f->output_data.ns->zooming = 0;
1385 wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1387 [view setRows: rows andColumns: cols];
1388 [window setFrame: wr display: YES];
1390 /* This is a trick to compensate for Emacs' managing the scrollbar area
1391 as a fixed number of standard character columns. Instead of leaving
1392 blank space for the extra, we chopped it off above. Now for
1393 left-hand scrollbars, we shift all rendering to the left by the
1394 difference between the real width and Emacs' imagined one. For
1395 right-hand bars, don't worry about it since the extra is never used.
1396 (Obviously doesn't work for vertically split windows tho..) */
1398 NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1399 ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1400 - NS_SCROLL_BAR_WIDTH (f), 0)
1401 : NSMakePoint (0, 0);
1402 [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1403 [view setBoundsOrigin: origin];
1406 change_frame_size (f, width, height, 0, 1, 0, pixelwise);
1407 /* SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1409 mark_window_cursors_off (XWINDOW (f->root_window));
1410 cancel_mouse_face (f);
1417 ns_fullscreen_hook (struct frame *f)
1419 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1421 if (!FRAME_VISIBLE_P (f))
1424 if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1426 /* Old style fs don't initiate correctly if created from
1427 init/default-frame alist, so use a timer (not nice...).
1429 [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1430 selector: @selector (handleFS)
1431 userInfo: nil repeats: NO];
1440 /* ==========================================================================
1444 ========================================================================== */
1448 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1450 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1451 if (idx < 1 || idx >= color_table->avail)
1453 return color_table->colors[idx];
1458 ns_index_color (NSColor *color, struct frame *f)
1460 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1464 if (!color_table->colors)
1466 color_table->size = NS_COLOR_CAPACITY;
1467 color_table->avail = 1; /* skip idx=0 as marker */
1468 color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1469 color_table->colors[0] = nil;
1470 color_table->empty_indices = [[NSMutableSet alloc] init];
1473 /* Do we already have this color? */
1474 for (i = 1; i < color_table->avail; i++)
1475 if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1478 if ([color_table->empty_indices count] > 0)
1480 NSNumber *index = [color_table->empty_indices anyObject];
1481 [color_table->empty_indices removeObject: index];
1482 idx = [index unsignedLongValue];
1486 if (color_table->avail == color_table->size)
1487 color_table->colors =
1488 xpalloc (color_table->colors, &color_table->size, 1,
1489 min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1490 idx = color_table->avail++;
1493 color_table->colors[idx] = color;
1495 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1501 ns_free_indexed_color (unsigned long idx, struct frame *f)
1503 struct ns_color_table *color_table;
1510 color_table = FRAME_DISPLAY_INFO (f)->color_table;
1512 if (idx <= 0 || idx >= color_table->size) {
1513 message1 ("ns_free_indexed_color: Color index out of range.\n");
1517 index = [NSNumber numberWithUnsignedInt: idx];
1518 if ([color_table->empty_indices containsObject: index]) {
1519 message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1523 color = color_table->colors[idx];
1525 color_table->colors[idx] = nil;
1526 [color_table->empty_indices addObject: index];
1527 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1532 ns_get_color (const char *name, NSColor **col)
1533 /* --------------------------------------------------------------------------
1535 -------------------------------------------------------------------------- */
1536 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1537 X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1538 See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1541 static char hex[20];
1543 float r = -1.0, g, b;
1544 NSString *nsname = [NSString stringWithUTF8String: name];
1546 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1549 if ([nsname isEqualToString: @"ns_selection_bg_color"])
1551 #ifdef NS_IMPL_COCOA
1552 NSString *defname = [[NSUserDefaults standardUserDefaults]
1553 stringForKey: @"AppleHighlightColor"];
1558 if ((new = [NSColor selectedTextBackgroundColor]) != nil)
1560 *col = [new colorUsingDefaultColorSpace];
1565 nsname = NS_SELECTION_BG_COLOR_DEFAULT;
1567 name = [nsname UTF8String];
1569 else if ([nsname isEqualToString: @"ns_selection_fg_color"])
1571 /* NOTE: OSX applications normally don't set foreground selection, but
1572 text may be unreadable if we don't.
1574 if ((new = [NSColor selectedTextColor]) != nil)
1576 *col = [new colorUsingDefaultColorSpace];
1581 nsname = NS_SELECTION_FG_COLOR_DEFAULT;
1582 name = [nsname UTF8String];
1585 /* First, check for some sort of numeric specification. */
1588 if (name[0] == '0' || name[0] == '1' || name[0] == '.') /* RGB decimal */
1590 NSScanner *scanner = [NSScanner scannerWithString: nsname];
1591 [scanner scanFloat: &r];
1592 [scanner scanFloat: &g];
1593 [scanner scanFloat: &b];
1595 else if (!strncmp(name, "rgb:", 4)) /* A newer X11 format -- rgb:r/g/b */
1596 scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1597 else if (name[0] == '#') /* An old X11 format; convert to newer */
1599 int len = (strlen(name) - 1);
1600 int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1602 scaling = strlen(name+start) / 3;
1603 for (i = 0; i < 3; i++)
1604 sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1605 name + start + i * scaling);
1606 hex[3 * (scaling + 1) - 1] = '\0';
1612 float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1613 if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1623 *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
1628 /* Otherwise, color is expected to be from a list */
1630 NSEnumerator *lenum, *cenum;
1634 #ifdef NS_IMPL_GNUSTEP
1635 /* XXX: who is wrong, the requestor or the implementation? */
1636 if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1638 nsname = @"highlightColor";
1641 lenum = [[NSColorList availableColorLists] objectEnumerator];
1642 while ( (clist = [lenum nextObject]) && new == nil)
1644 cenum = [[clist allKeys] objectEnumerator];
1645 while ( (name = [cenum nextObject]) && new == nil )
1647 if ([name compare: nsname
1648 options: NSCaseInsensitiveSearch] == NSOrderedSame )
1649 new = [clist colorWithKey: name];
1655 *col = [new colorUsingDefaultColorSpace];
1662 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1663 /* --------------------------------------------------------------------------
1664 Convert a Lisp string object to a NS color
1665 -------------------------------------------------------------------------- */
1667 NSTRACE (ns_lisp_to_color);
1668 if (STRINGP (color))
1669 return ns_get_color (SSDATA (color), col);
1670 else if (SYMBOLP (color))
1671 return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1677 ns_color_to_lisp (NSColor *col)
1678 /* --------------------------------------------------------------------------
1679 Convert a color to a lisp string with the RGB equivalent
1680 -------------------------------------------------------------------------- */
1682 EmacsCGFloat red, green, blue, alpha, gray;
1685 NSTRACE (ns_color_to_lisp);
1688 if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1690 if ((str =[[col colorNameComponent] UTF8String]))
1693 return build_string ((char *)str);
1696 [[col colorUsingDefaultColorSpace]
1697 getRed: &red green: &green blue: &blue alpha: &alpha];
1698 if (red == green && red == blue)
1700 [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1701 getWhite: &gray alpha: &alpha];
1702 snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1703 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1705 return build_string (buf);
1708 snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1709 lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1712 return build_string (buf);
1717 ns_query_color(void *col, XColor *color_def, int setPixel)
1718 /* --------------------------------------------------------------------------
1719 Get ARGB values out of NSColor col and put them into color_def.
1720 If setPixel, set the pixel to a concatenated version.
1721 and set color_def pixel to the resulting index.
1722 -------------------------------------------------------------------------- */
1724 EmacsCGFloat r, g, b, a;
1726 [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1727 color_def->red = r * 65535;
1728 color_def->green = g * 65535;
1729 color_def->blue = b * 65535;
1731 if (setPixel == YES)
1733 = ARGB_TO_ULONG((int)(a*255),
1734 (int)(r*255), (int)(g*255), (int)(b*255));
1739 ns_defined_color (struct frame *f,
1744 /* --------------------------------------------------------------------------
1745 Return true if named color found, and set color_def rgb accordingly.
1746 If makeIndex and alloc are nonzero put the color in the color_table,
1747 and set color_def pixel to the resulting index.
1748 If makeIndex is zero, set color_def pixel to ARGB.
1749 Return false if not found
1750 -------------------------------------------------------------------------- */
1753 NSTRACE (ns_defined_color);
1756 if (ns_get_color (name, &col) != 0) /* Color not found */
1761 if (makeIndex && alloc)
1762 color_def->pixel = ns_index_color (col, f);
1763 ns_query_color (col, color_def, !makeIndex);
1770 x_set_frame_alpha (struct frame *f)
1771 /* --------------------------------------------------------------------------
1772 change the entire-frame transparency
1773 -------------------------------------------------------------------------- */
1775 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1777 double alpha_min = 1.0;
1779 if (dpyinfo->x_highlight_frame == f)
1780 alpha = f->alpha[0];
1782 alpha = f->alpha[1];
1784 if (FLOATP (Vframe_alpha_lower_limit))
1785 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1786 else if (INTEGERP (Vframe_alpha_lower_limit))
1787 alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1791 else if (1.0 < alpha)
1793 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1796 #ifdef NS_IMPL_COCOA
1798 EmacsView *view = FRAME_NS_VIEW (f);
1799 [[view window] setAlphaValue: alpha];
1805 /* ==========================================================================
1809 ========================================================================== */
1813 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1814 /* --------------------------------------------------------------------------
1815 Programmatically reposition mouse pointer in pixel coordinates
1816 -------------------------------------------------------------------------- */
1818 NSTRACE (x_set_mouse_pixel_position);
1821 /* FIXME: this does not work, and what about GNUstep? */
1822 #ifdef NS_IMPL_COCOA
1823 [FRAME_NS_VIEW (f) lockFocus];
1824 PSsetmouse ((float)pix_x, (float)pix_y);
1825 [FRAME_NS_VIEW (f) unlockFocus];
1832 x_set_mouse_position (struct frame *f, int h, int v)
1833 /* --------------------------------------------------------------------------
1834 Programmatically reposition mouse pointer in character coordinates
1835 -------------------------------------------------------------------------- */
1839 pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1840 pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1842 if (pix_x < 0) pix_x = 0;
1843 if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1845 if (pix_y < 0) pix_y = 0;
1846 if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1848 x_set_mouse_pixel_position (f, pix_x, pix_y);
1853 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
1854 /* ------------------------------------------------------------------------
1855 Called by EmacsView on mouseMovement events. Passes on
1856 to emacs mainstream code if we moved off of a rect of interest
1857 known as last_mouse_glyph.
1858 ------------------------------------------------------------------------ */
1860 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1863 // NSTRACE (note_mouse_movement);
1865 dpyinfo->last_mouse_motion_frame = frame;
1866 r = &dpyinfo->last_mouse_glyph;
1868 /* Note, this doesn't get called for enter/leave, since we don't have a
1869 position. Those are taken care of in the corresponding NSView methods. */
1871 /* has movement gone beyond last rect we were tracking? */
1872 if (x < r->origin.x || x >= r->origin.x + r->size.width
1873 || y < r->origin.y || y >= r->origin.y + r->size.height)
1875 ns_update_begin (frame);
1876 frame->mouse_moved = 1;
1877 note_mouse_highlight (frame, x, y);
1878 remember_mouse_glyph (frame, x, y, r);
1879 ns_update_end (frame);
1888 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1889 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1891 /* --------------------------------------------------------------------------
1892 External (hook): inform emacs about mouse position and hit parts.
1893 If a scrollbar is being dragged, set bar_window, part, x, y, time.
1894 x & y should be position in the scrollbar (the whole bar, not the handle)
1895 and length of scrollbar respectively
1896 -------------------------------------------------------------------------- */
1900 Lisp_Object frame, tail;
1902 struct ns_display_info *dpyinfo;
1904 NSTRACE (ns_mouse_position);
1908 fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1912 dpyinfo = FRAME_DISPLAY_INFO (*fp);
1916 /* Clear the mouse-moved flag for every frame on this display. */
1917 FOR_EACH_FRAME (tail, frame)
1918 if (FRAME_NS_P (XFRAME (frame))
1919 && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1920 XFRAME (frame)->mouse_moved = 0;
1922 dpyinfo->last_mouse_scroll_bar = nil;
1923 if (dpyinfo->last_mouse_frame
1924 && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
1925 f = dpyinfo->last_mouse_frame;
1927 f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
1929 if (f && FRAME_NS_P (f))
1931 view = FRAME_NS_VIEW (*fp);
1933 position = [[view window] mouseLocationOutsideOfEventStream];
1934 position = [view convertPoint: position fromView: nil];
1935 remember_mouse_glyph (f, position.x, position.y,
1936 &dpyinfo->last_mouse_glyph);
1937 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1939 if (bar_window) *bar_window = Qnil;
1940 if (part) *part = 0; /*scroll_bar_handle; */
1942 if (x) XSETINT (*x, lrint (position.x));
1943 if (y) XSETINT (*y, lrint (position.y));
1945 *time = dpyinfo->last_mouse_movement_time;
1954 ns_frame_up_to_date (struct frame *f)
1955 /* --------------------------------------------------------------------------
1956 External (hook): Fix up mouse highlighting right after a full update.
1957 Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
1958 -------------------------------------------------------------------------- */
1960 NSTRACE (ns_frame_up_to_date);
1964 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1965 if (f == hlinfo->mouse_face_mouse_frame)
1969 note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1970 hlinfo->mouse_face_mouse_x,
1971 hlinfo->mouse_face_mouse_y);
1980 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1981 /* --------------------------------------------------------------------------
1982 External (RIF): set frame mouse pointer type.
1983 -------------------------------------------------------------------------- */
1985 NSTRACE (ns_define_frame_cursor);
1986 if (FRAME_POINTER_TYPE (f) != cursor)
1988 EmacsView *view = FRAME_NS_VIEW (f);
1989 FRAME_POINTER_TYPE (f) = cursor;
1990 [[view window] invalidateCursorRectsForView: view];
1991 /* Redisplay assumes this function also draws the changed frame
1992 cursor, but this function doesn't, so do it explicitly. */
1993 x_update_cursor (f, 1);
1999 /* ==========================================================================
2003 ========================================================================== */
2007 ns_convert_key (unsigned code)
2008 /* --------------------------------------------------------------------------
2009 Internal call used by NSView-keyDown.
2010 -------------------------------------------------------------------------- */
2012 const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
2013 / sizeof (convert_ns_to_X_keysym[0]));
2015 /* An array would be faster, but less easy to read. */
2016 for (keysym = 0; keysym < last_keysym; keysym += 2)
2017 if (code == convert_ns_to_X_keysym[keysym])
2018 return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2020 /* if decide to use keyCode and Carbon table, use this line:
2021 return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2026 x_get_keysym_name (int keysym)
2027 /* --------------------------------------------------------------------------
2028 Called by keyboard.c. Not sure if the return val is important, except
2030 -------------------------------------------------------------------------- */
2032 static char value[16];
2033 NSTRACE (x_get_keysym_name);
2034 sprintf (value, "%d", keysym);
2040 /* ==========================================================================
2042 Block drawing operations
2044 ========================================================================== */
2048 ns_redraw_scroll_bars (struct frame *f)
2052 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2053 NSTRACE (ns_redraw_scroll_bars);
2054 for (i =[subviews count]-1; i >= 0; i--)
2056 view = [subviews objectAtIndex: i];
2057 if (![view isKindOfClass: [EmacsScroller class]]) continue;
2064 ns_clear_frame (struct frame *f)
2065 /* --------------------------------------------------------------------------
2066 External (hook): Erase the entire frame
2067 -------------------------------------------------------------------------- */
2069 NSView *view = FRAME_NS_VIEW (f);
2072 NSTRACE (ns_clear_frame);
2074 /* comes on initial frame because we have
2075 after-make-frame-functions = select-frame */
2076 if (!FRAME_DEFAULT_FACE (f))
2079 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2084 ns_focus (f, &r, 1);
2085 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2089 /* as of 2006/11 or so this is now needed */
2090 ns_redraw_scroll_bars (f);
2096 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2097 /* --------------------------------------------------------------------------
2098 External (RIF): Clear section of frame
2099 -------------------------------------------------------------------------- */
2101 NSRect r = NSMakeRect (x, y, width, height);
2102 NSView *view = FRAME_NS_VIEW (f);
2103 struct face *face = FRAME_DEFAULT_FACE (f);
2108 NSTRACE (ns_clear_frame_area);
2110 r = NSIntersectionRect (r, [view frame]);
2111 ns_focus (f, &r, 1);
2112 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2122 ns_scroll_run (struct window *w, struct run *run)
2123 /* --------------------------------------------------------------------------
2124 External (RIF): Insert or delete n lines at line vpos
2125 -------------------------------------------------------------------------- */
2127 struct frame *f = XFRAME (w->frame);
2128 int x, y, width, height, from_y, to_y, bottom_y;
2130 NSTRACE (ns_scroll_run);
2132 /* begin copy from other terms */
2133 /* Get frame-relative bounding box of the text display area of W,
2134 without mode lines. Include in this box the left and right
2136 window_box (w, ANY_AREA, &x, &y, &width, &height);
2138 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2139 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2140 bottom_y = y + height;
2144 /* Scrolling up. Make sure we don't copy part of the mode
2145 line at the bottom. */
2146 if (from_y + run->height > bottom_y)
2147 height = bottom_y - from_y;
2149 height = run->height;
2153 /* Scrolling down. Make sure we don't copy over the mode line.
2155 if (to_y + run->height > bottom_y)
2156 height = bottom_y - to_y;
2158 height = run->height;
2160 /* end copy from other terms */
2170 NSRect srcRect = NSMakeRect (x, from_y, width, height);
2171 NSRect dstRect = NSMakeRect (x, to_y, width, height);
2172 NSPoint dstOrigin = NSMakePoint (x, to_y);
2174 ns_focus (f, &dstRect, 1);
2175 NSCopyBits (0, srcRect , dstOrigin);
2184 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2185 /* --------------------------------------------------------------------------
2186 External (RIF): preparatory to fringe update after text was updated
2187 -------------------------------------------------------------------------- */
2192 NSTRACE (ns_after_update_window_line);
2194 /* begin copy from other terms */
2197 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2198 desired_row->redraw_fringe_bitmaps_p = 1;
2200 /* When a window has disappeared, make sure that no rest of
2201 full-width rows stays visible in the internal border. */
2202 if (windows_or_buffers_changed
2203 && desired_row->full_width_p
2204 && (f = XFRAME (w->frame),
2205 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2207 && (height = desired_row->visible_height,
2210 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2213 ns_clear_frame_area (f, 0, y, width, height);
2214 ns_clear_frame_area (f,
2215 FRAME_PIXEL_WIDTH (f) - width,
2223 ns_shift_glyphs_for_insert (struct frame *f,
2224 int x, int y, int width, int height,
2226 /* --------------------------------------------------------------------------
2227 External (RIF): copy an area horizontally, don't worry about clearing src
2228 -------------------------------------------------------------------------- */
2230 NSRect srcRect = NSMakeRect (x, y, width, height);
2231 NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2232 NSPoint dstOrigin = dstRect.origin;
2234 NSTRACE (ns_shift_glyphs_for_insert);
2236 ns_focus (f, &dstRect, 1);
2237 NSCopyBits (0, srcRect, dstOrigin);
2243 /* ==========================================================================
2245 Character encoding and metrics
2247 ========================================================================== */
2251 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2252 /* --------------------------------------------------------------------------
2253 External (RIF); compute left/right overhang of whole string and set in s
2254 -------------------------------------------------------------------------- */
2256 struct font *font = s->font;
2260 struct font_metrics metrics;
2261 unsigned int codes[2];
2262 codes[0] = *(s->char2b);
2263 codes[1] = *(s->char2b + s->nchars - 1);
2265 font->driver->text_extents (font, codes, 2, &metrics);
2266 s->left_overhang = -metrics.lbearing;
2268 = metrics.rbearing > metrics.width
2269 ? metrics.rbearing - metrics.width : 0;
2273 s->left_overhang = 0;
2274 if (EQ (font->driver->type, Qns))
2275 s->right_overhang = ((struct nsfont_info *)font)->ital ?
2276 FONT_HEIGHT (font) * 0.2 : 0;
2278 s->right_overhang = 0;
2284 /* ==========================================================================
2286 Fringe and cursor drawing
2288 ========================================================================== */
2291 extern int max_used_fringe_bitmap;
2293 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2294 struct draw_fringe_bitmap_params *p)
2295 /* --------------------------------------------------------------------------
2296 External (RIF); fringe-related
2297 -------------------------------------------------------------------------- */
2299 struct frame *f = XFRAME (WINDOW_FRAME (w));
2300 struct face *face = p->face;
2301 static EmacsImage **bimgs = NULL;
2302 static int nBimgs = 0;
2304 /* grow bimgs if needed */
2305 if (nBimgs < max_used_fringe_bitmap)
2307 bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2308 memset (bimgs + nBimgs, 0,
2309 (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2310 nBimgs = max_used_fringe_bitmap;
2313 /* Must clip because of partially visible lines. */
2314 ns_clip_to_row (w, row, ANY_AREA, YES);
2318 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2320 /* If the fringe is adjacent to the left (right) scroll bar of a
2321 leftmost (rightmost, respectively) window, then extend its
2322 background to the gap between the fringe and the bar. */
2323 if ((WINDOW_LEFTMOST_P (w)
2324 && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2325 || (WINDOW_RIGHTMOST_P (w)
2326 && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2328 int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2332 int bar_area_x = WINDOW_SCROLL_BAR_AREA_X (w);
2333 int bar_area_width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2334 * FRAME_COLUMN_WIDTH (f));
2338 /* Bitmap fills the fringe. */
2339 if (bar_area_x + bar_area_width == p->x)
2340 bx = bar_area_x + sb_width;
2341 else if (p->x + p->wd == bar_area_x)
2345 int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2347 nx = bar_area_width - sb_width;
2348 by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2350 ny = row->visible_height;
2355 if (bar_area_x + bar_area_width == bx)
2357 bx = bar_area_x + sb_width;
2358 nx += bar_area_width - sb_width;
2360 else if (bx + nx == bar_area_x)
2361 nx += bar_area_width - sb_width;
2366 if (bx >= 0 && nx > 0)
2368 NSRect r = NSMakeRect (bx, by, nx, ny);
2370 [ns_lookup_indexed_color (face->background, f) set];
2377 NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2378 EmacsImage *img = bimgs[p->which - 1];
2382 unsigned short *bits = p->bits + p->dh;
2385 unsigned char *cbits = xmalloc (len);
2387 for (i = 0; i < len; i++)
2388 cbits[i] = ~(bits[i] & 0xff);
2389 img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2391 bimgs[p->which - 1] = img;
2396 /* Since we composite the bitmap instead of just blitting it, we need
2397 to erase the whole background. */
2398 [ns_lookup_indexed_color(face->background, f) set];
2400 [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2401 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2403 fromRect: NSZeroRect
2404 operation: NSCompositeSourceOver
2410 NSPoint pt = r.origin;
2412 [img compositeToPoint: pt operation: NSCompositeSourceOver];
2421 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2422 int x, int y, enum text_cursor_kinds cursor_type,
2423 int cursor_width, bool on_p, bool active_p)
2424 /* --------------------------------------------------------------------------
2425 External call (RIF): draw cursor.
2426 Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2427 -------------------------------------------------------------------------- */
2430 int fx, fy, h, cursor_height;
2431 struct frame *f = WINDOW_XFRAME (w);
2432 struct glyph *phys_cursor_glyph;
2433 struct glyph *cursor_glyph;
2435 NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2437 /* If cursor is out of bounds, don't draw garbage. This can happen
2438 in mini-buffer windows when switching between echo area glyphs
2441 NSTRACE (dumpcursor);
2446 w->phys_cursor_type = cursor_type;
2447 w->phys_cursor_on_p = on_p;
2449 if (cursor_type == NO_CURSOR)
2451 w->phys_cursor_width = 0;
2455 if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2457 if (glyph_row->exact_window_width_line_p
2458 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2460 glyph_row->cursor_in_fringe_p = 1;
2461 draw_fringe_bitmap (w, glyph_row, 0);
2466 /* We draw the cursor (with NSRectFill), then draw the glyph on top
2467 (other terminals do it the other way round). We must set
2468 w->phys_cursor_width to the cursor width. For bar cursors, that
2469 is CURSOR_WIDTH; for box cursors, it is the glyph width. */
2470 get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2472 /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2473 to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2474 if (cursor_type == BAR_CURSOR)
2476 if (cursor_width < 1)
2477 cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2478 w->phys_cursor_width = cursor_width;
2480 /* If we have an HBAR, "cursor_width" MAY specify height. */
2481 else if (cursor_type == HBAR_CURSOR)
2483 cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2484 fy += h - cursor_height;
2488 r.origin.x = fx, r.origin.y = fy;
2490 r.size.width = w->phys_cursor_width;
2492 /* TODO: only needed in rare cases with last-resort font in HELLO..
2493 should we do this more efficiently? */
2494 ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2497 face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2498 if (face && NS_FACE_BACKGROUND (face)
2499 == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2501 [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2502 hollow_color = FRAME_CURSOR_COLOR (f);
2505 [FRAME_CURSOR_COLOR (f) set];
2507 #ifdef NS_IMPL_COCOA
2508 /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2509 atomic. Cleaner ways of doing this should be investigated.
2510 One way would be to set a global variable DRAWING_CURSOR
2511 when making the call to draw_phys..(), don't focus in that
2512 case, then move the ns_unfocus() here after that call. */
2513 NSDisableScreenUpdates ();
2516 switch (cursor_type)
2520 case FILLED_BOX_CURSOR:
2523 case HOLLOW_BOX_CURSOR:
2526 NSRectFill (NSInsetRect (r, 1, 1));
2527 [FRAME_CURSOR_COLOR (f) set];
2534 /* If the character under cursor is R2L, draw the bar cursor
2535 on the right of its glyph, rather than on the left. */
2536 cursor_glyph = get_phys_cursor_glyph (w);
2537 if ((cursor_glyph->resolved_level & 1) != 0)
2538 s.origin.x += cursor_glyph->pixel_width - s.size.width;
2545 /* draw the character under the cursor */
2546 if (cursor_type != NO_CURSOR)
2547 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2549 #ifdef NS_IMPL_COCOA
2550 NSEnableScreenUpdates ();
2557 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2558 /* --------------------------------------------------------------------------
2559 External (RIF): Draw a vertical line.
2560 -------------------------------------------------------------------------- */
2562 struct frame *f = XFRAME (WINDOW_FRAME (w));
2564 NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2566 NSTRACE (ns_draw_vertical_window_border);
2568 face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2570 [ns_lookup_indexed_color(face->foreground, f) set];
2572 ns_focus (f, &r, 1);
2579 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
2580 /* --------------------------------------------------------------------------
2581 External (RIF): Draw a window divider.
2582 -------------------------------------------------------------------------- */
2584 struct frame *f = XFRAME (WINDOW_FRAME (w));
2586 NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
2588 NSTRACE (ns_draw_window_divider);
2590 face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID);
2592 [ns_lookup_indexed_color(face->foreground, f) set];
2594 ns_focus (f, &r, 1);
2601 show_hourglass (struct atimer *timer)
2603 if (hourglass_shown_p)
2608 /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2610 hourglass_shown_p = 1;
2616 hide_hourglass (void)
2618 if (!hourglass_shown_p)
2623 /* TODO: remove NSProgressIndicator from all frames */
2625 hourglass_shown_p = 0;
2631 /* ==========================================================================
2633 Glyph drawing operations
2635 ========================================================================== */
2638 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2639 /* --------------------------------------------------------------------------
2640 Wrapper utility to account for internal border width on full-width lines,
2641 and allow top full-width rows to hit the frame top. nr should be pointer
2642 to two successive NSRects. Number of rects actually used is returned.
2643 -------------------------------------------------------------------------- */
2645 int n = get_glyph_string_clip_rects (s, nr, 2);
2649 /* --------------------------------------------------------------------
2650 Draw a wavy line under glyph string s. The wave fills wave_height
2657 wave_height = 3 | * * * *
2658 --------------------------------------------------------------------- */
2661 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
2663 int wave_height = 3, wave_length = 2;
2664 int y, dx, dy, odd, xmax;
2669 dy = wave_height - 1;
2670 y = s->ybase - wave_height + 3;
2673 /* Find and set clipping rectangle */
2674 waveClip = NSMakeRect (x, y, width, wave_height);
2675 [[NSGraphicsContext currentContext] saveGraphicsState];
2676 NSRectClip (waveClip);
2678 /* Draw the waves */
2679 a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
2681 odd = (int)(a.x/dx) % 2;
2682 a.y = b.y = y + 0.5;
2691 [NSBezierPath strokeLineFromPoint:a toPoint:b];
2692 a.x = b.x, a.y = b.y;
2693 b.x += dx, b.y = y + 0.5 + odd*dy;
2697 /* Restore previous clipping rectangle(s) */
2698 [[NSGraphicsContext currentContext] restoreGraphicsState];
2704 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2705 NSColor *defaultCol, CGFloat width, CGFloat x)
2706 /* --------------------------------------------------------------------------
2707 Draw underline, overline, and strike-through on glyph string s.
2708 -------------------------------------------------------------------------- */
2710 if (s->for_overlaps)
2714 if (face->underline_p)
2716 if (s->face->underline_type == FACE_UNDER_WAVE)
2718 if (face->underline_defaulted_p)
2721 [ns_lookup_indexed_color (face->underline_color, s->f) set];
2723 ns_draw_underwave (s, width, x);
2725 else if (s->face->underline_type == FACE_UNDER_LINE)
2729 unsigned long thickness, position;
2731 /* If the prev was underlined, match its appearance. */
2732 if (s->prev && s->prev->face->underline_p
2733 && s->prev->face->underline_type == FACE_UNDER_LINE
2734 && s->prev->underline_thickness > 0)
2736 thickness = s->prev->underline_thickness;
2737 position = s->prev->underline_position;
2742 unsigned long descent;
2745 descent = s->y + s->height - s->ybase;
2747 /* Use underline thickness of font, defaulting to 1. */
2748 thickness = (font && font->underline_thickness > 0)
2749 ? font->underline_thickness : 1;
2751 /* Determine the offset of underlining from the baseline. */
2752 if (x_underline_at_descent_line)
2753 position = descent - thickness;
2754 else if (x_use_underline_position_properties
2755 && font && font->underline_position >= 0)
2756 position = font->underline_position;
2758 position = lround (font->descent / 2);
2760 position = underline_minimum_offset;
2762 position = max (position, underline_minimum_offset);
2764 /* Ensure underlining is not cropped. */
2765 if (descent <= position)
2767 position = descent - 1;
2770 else if (descent < position + thickness)
2774 s->underline_thickness = thickness;
2775 s->underline_position = position;
2777 r = NSMakeRect (x, s->ybase + position, width, thickness);
2779 if (face->underline_defaulted_p)
2782 [ns_lookup_indexed_color (face->underline_color, s->f) set];
2786 /* Do overline. We follow other terms in using a thickness of 1
2787 and ignoring overline_margin. */
2788 if (face->overline_p)
2791 r = NSMakeRect (x, s->y, width, 1);
2793 if (face->overline_color_defaulted_p)
2796 [ns_lookup_indexed_color (face->overline_color, s->f) set];
2800 /* Do strike-through. We follow other terms for thickness and
2801 vertical position.*/
2802 if (face->strike_through_p)
2807 dy = lrint ((s->height - 1) / 2);
2808 r = NSMakeRect (x, s->y + dy, width, 1);
2810 if (face->strike_through_color_defaulted_p)
2813 [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2819 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
2820 char left_p, char right_p)
2821 /* --------------------------------------------------------------------------
2822 Draw an unfilled rect inside r, optionally leaving left and/or right open.
2823 Note we can't just use an NSDrawRect command, because of the possibility
2824 of some sides not being drawn, and because the rect will be filled.
2825 -------------------------------------------------------------------------- */
2831 s.size.height = thickness;
2833 s.origin.y += r.size.height - thickness;
2836 s.size.height = r.size.height;
2837 s.origin.y = r.origin.y;
2839 /* left, right (optional) */
2840 s.size.width = thickness;
2845 s.origin.x += r.size.width - thickness;
2852 ns_draw_relief (NSRect r, int thickness, char raised_p,
2853 char top_p, char bottom_p, char left_p, char right_p,
2854 struct glyph_string *s)
2855 /* --------------------------------------------------------------------------
2856 Draw a relief rect inside r, optionally leaving some sides open.
2857 Note we can't just use an NSDrawBezel command, because of the possibility
2858 of some sides not being drawn, and because the rect will be filled.
2859 -------------------------------------------------------------------------- */
2861 static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2862 NSColor *newBaseCol = nil;
2865 NSTRACE (ns_draw_relief);
2869 if (s->face->use_box_color_for_shadows_p)
2871 newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2873 /* else if (s->first_glyph->type == IMAGE_GLYPH
2875 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2877 newBaseCol = IMAGE_BACKGROUND (s->img, s->f, 0);
2881 newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2884 if (newBaseCol == nil)
2885 newBaseCol = [NSColor grayColor];
2887 if (newBaseCol != baseCol) /* TODO: better check */
2890 baseCol = [newBaseCol retain];
2892 lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2894 darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2897 [(raised_p ? lightCol : darkCol) set];
2899 /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2902 sr.size.height = thickness;
2903 if (top_p) NSRectFill (sr);
2906 sr.size.height = r.size.height;
2907 sr.size.width = thickness;
2908 if (left_p) NSRectFill (sr);
2910 [(raised_p ? darkCol : lightCol) set];
2913 sr.size.width = r.size.width;
2914 sr.size.height = thickness;
2915 sr.origin.y += r.size.height - thickness;
2916 if (bottom_p) NSRectFill (sr);
2919 sr.size.height = r.size.height;
2920 sr.origin.y = r.origin.y;
2921 sr.size.width = thickness;
2922 sr.origin.x += r.size.width - thickness;
2923 if (right_p) NSRectFill (sr);
2928 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2929 /* --------------------------------------------------------------------------
2930 Function modeled after x_draw_glyph_string_box ().
2931 Sets up parameters for drawing.
2932 -------------------------------------------------------------------------- */
2934 int right_x, last_x;
2935 char left_p, right_p;
2936 struct glyph *last_glyph;
2941 if (s->hl == DRAW_MOUSE_FACE)
2943 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2945 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2950 thickness = face->box_line_width;
2952 NSTRACE (ns_dumpglyphs_box_or_relief);
2954 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2955 ? WINDOW_RIGHT_EDGE_X (s->w)
2956 : window_box_right (s->w, s->area));
2957 last_glyph = (s->cmp || s->img
2958 ? s->first_glyph : s->first_glyph + s->nchars-1);
2960 right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2961 ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2963 left_p = (s->first_glyph->left_box_line_p
2964 || (s->hl == DRAW_MOUSE_FACE
2965 && (s->prev == NULL || s->prev->hl != s->hl)));
2966 right_p = (last_glyph->right_box_line_p
2967 || (s->hl == DRAW_MOUSE_FACE
2968 && (s->next == NULL || s->next->hl != s->hl)));
2970 r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2972 /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2973 if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2975 ns_draw_box (r, abs (thickness),
2976 ns_lookup_indexed_color (face->box_color, s->f),
2981 ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2982 1, 1, left_p, right_p, s);
2988 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2989 /* --------------------------------------------------------------------------
2990 Modeled after x_draw_glyph_string_background, which draws BG in
2991 certain cases. Others are left to the text rendering routine.
2992 -------------------------------------------------------------------------- */
2994 NSTRACE (ns_maybe_dumpglyphs_background);
2996 if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2998 int box_line_width = max (s->face->box_line_width, 0);
2999 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3000 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3003 if (s->hl == DRAW_MOUSE_FACE)
3005 face = FACE_FROM_ID (s->f,
3006 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3008 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3011 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3013 [(NS_FACE_BACKGROUND (face) != 0
3014 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3015 : FRAME_BACKGROUND_COLOR (s->f)) set];
3018 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3019 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3022 if (s->hl != DRAW_CURSOR)
3024 NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3025 s->background_width,
3026 s->height-2*box_line_width);
3030 s->background_filled_p = 1;
3037 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3038 /* --------------------------------------------------------------------------
3039 Renders an image and associated borders.
3040 -------------------------------------------------------------------------- */
3042 EmacsImage *img = s->img->pixmap;
3043 int box_line_vwidth = max (s->face->box_line_width, 0);
3044 int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3045 int bg_x, bg_y, bg_height;
3052 NSTRACE (ns_dumpglyphs_image);
3054 if (s->face->box != FACE_NO_BOX
3055 && s->first_glyph->left_box_line_p && s->slice.x == 0)
3056 x += abs (s->face->box_line_width);
3059 bg_y = s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3060 bg_height = s->height;
3061 /* other terms have this, but was causing problems w/tabbar mode */
3062 /* - 2 * box_line_vwidth; */
3064 if (s->slice.x == 0) x += s->img->hmargin;
3065 if (s->slice.y == 0) y += s->img->vmargin;
3067 /* Draw BG: if we need larger area than image itself cleared, do that,
3068 otherwise, since we composite the image under NS (instead of mucking
3069 with its background color), we must clear just the image area. */
3070 if (s->hl == DRAW_MOUSE_FACE)
3072 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3074 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3077 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3079 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3081 if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3082 || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3084 br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3085 s->background_filled_p = 1;
3089 br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3094 /* Draw the image.. do we need to draw placeholder if img ==nil? */
3097 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
3098 NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3099 NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3100 s->slice.width, s->slice.height);
3103 operation: NSCompositeSourceOver
3108 [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3109 operation: NSCompositeSourceOver];
3113 if (s->hl == DRAW_CURSOR)
3115 [FRAME_CURSOR_COLOR (s->f) set];
3116 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3117 tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3119 /* Currently on NS img->mask is always 0. Since
3120 get_window_cursor_type specifies a hollow box cursor when on
3121 a non-masked image we never reach this clause. But we put it
3122 in in anticipation of better support for image masks on
3124 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3128 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3131 /* Draw underline, overline, strike-through. */
3132 ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3134 /* Draw relief, if requested */
3135 if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3137 if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3139 th = tool_bar_button_relief >= 0 ?
3140 tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3141 raised_p = (s->hl == DRAW_IMAGE_RAISED);
3145 th = abs (s->img->relief);
3146 raised_p = (s->img->relief > 0);
3149 r.origin.x = x - th;
3150 r.origin.y = y - th;
3151 r.size.width = s->slice.width + 2*th-1;
3152 r.size.height = s->slice.height + 2*th-1;
3153 ns_draw_relief (r, th, raised_p,
3155 s->slice.y + s->slice.height == s->img->height,
3157 s->slice.x + s->slice.width == s->img->width, s);
3160 /* If there is no mask, the background won't be seen,
3161 so draw a rectangle on the image for the cursor.
3162 Do this for all images, getting transparency right is not reliable. */
3163 if (s->hl == DRAW_CURSOR)
3165 int thickness = abs (s->img->relief);
3166 if (thickness == 0) thickness = 1;
3167 ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3173 ns_dumpglyphs_stretch (struct glyph_string *s)
3178 NSColor *fgCol, *bgCol;
3180 if (!s->background_filled_p)
3182 n = ns_get_glyph_string_clip_rect (s, r);
3183 *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3185 ns_focus (s->f, r, n);
3187 if (s->hl == DRAW_MOUSE_FACE)
3189 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3191 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3194 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3196 bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3197 fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3199 for (i = 0; i < n; ++i)
3201 if (!s->row->full_width_p)
3203 int overrun, leftoverrun;
3205 /* truncate to avoid overwriting fringe and/or scrollbar */
3206 overrun = max (0, (s->x + s->background_width)
3207 - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3208 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3209 r[i].size.width -= overrun;
3211 /* truncate to avoid overwriting to left of the window box */
3212 leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3213 + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3215 if (leftoverrun > 0)
3217 r[i].origin.x += leftoverrun;
3218 r[i].size.width -= leftoverrun;
3221 /* XXX: Try to work between problem where a stretch glyph on
3222 a partially-visible bottom row will clear part of the
3223 modeline, and another where list-buffers headers and similar
3224 rows erroneously have visible_height set to 0. Not sure
3225 where this is coming from as other terms seem not to show. */
3226 r[i].size.height = min (s->height, s->row->visible_height);
3231 /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3232 overwriting cursor (usually when cursor on a tab) */
3233 if (s->hl == DRAW_CURSOR)
3238 width = s->w->phys_cursor_width;
3239 r[i].size.width -= width;
3240 r[i].origin.x += width;
3244 /* Draw overlining, etc. on the cursor. */
3245 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3246 ns_draw_text_decoration (s, face, bgCol, width, x);
3248 ns_draw_text_decoration (s, face, fgCol, width, x);
3255 /* Draw overlining, etc. on the stretch glyph (or the part
3256 of the stretch glyph after the cursor). */
3257 ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3261 s->background_filled_p = 1;
3267 ns_draw_glyph_string (struct glyph_string *s)
3268 /* --------------------------------------------------------------------------
3269 External (RIF): Main draw-text call.
3270 -------------------------------------------------------------------------- */
3272 /* TODO (optimize): focus for box and contents draw */
3275 char box_drawn_p = 0;
3276 struct font *font = s->face->font;
3277 if (! font) font = FRAME_FONT (s->f);
3279 NSTRACE (ns_draw_glyph_string);
3281 if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3284 struct glyph_string *next;
3286 for (width = 0, next = s->next;
3287 next && width < s->right_overhang;
3288 width += next->width, next = next->next)
3289 if (next->first_glyph->type != IMAGE_GLYPH)
3291 if (next->first_glyph->type != STRETCH_GLYPH)
3293 n = ns_get_glyph_string_clip_rect (s->next, r);
3294 ns_focus (s->f, r, n);
3295 ns_maybe_dumpglyphs_background (s->next, 1);
3300 ns_dumpglyphs_stretch (s->next);
3302 next->num_clips = 0;
3306 if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3307 && (s->first_glyph->type == CHAR_GLYPH
3308 || s->first_glyph->type == COMPOSITE_GLYPH))
3310 n = ns_get_glyph_string_clip_rect (s, r);
3311 ns_focus (s->f, r, n);
3312 ns_maybe_dumpglyphs_background (s, 1);
3313 ns_dumpglyphs_box_or_relief (s);
3318 switch (s->first_glyph->type)
3322 n = ns_get_glyph_string_clip_rect (s, r);
3323 ns_focus (s->f, r, n);
3324 ns_dumpglyphs_image (s, r[0]);
3329 ns_dumpglyphs_stretch (s);
3333 case COMPOSITE_GLYPH:
3334 n = ns_get_glyph_string_clip_rect (s, r);
3335 ns_focus (s->f, r, n);
3337 if (s->for_overlaps || (s->cmp_from > 0
3338 && ! s->first_glyph->u.cmp.automatic))
3339 s->background_filled_p = 1;
3341 ns_maybe_dumpglyphs_background
3342 (s, s->first_glyph->type == COMPOSITE_GLYPH);
3344 flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3345 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3346 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3347 NS_DUMPGLYPH_NORMAL));
3349 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3351 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3352 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3353 NS_FACE_FOREGROUND (s->face) = tmp;
3357 (s, 0, s->nchars, s->x, s->y,
3358 (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3359 || flags == NS_DUMPGLYPH_MOUSEFACE);
3362 NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3363 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3365 : FRAME_FOREGROUND_COLOR (s->f));
3368 /* Draw underline, overline, strike-through. */
3369 ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3372 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3374 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3375 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3376 NS_FACE_FOREGROUND (s->face) = tmp;
3382 case GLYPHLESS_GLYPH:
3383 n = ns_get_glyph_string_clip_rect (s, r);
3384 ns_focus (s->f, r, n);
3386 if (s->for_overlaps || (s->cmp_from > 0
3387 && ! s->first_glyph->u.cmp.automatic))
3388 s->background_filled_p = 1;
3390 ns_maybe_dumpglyphs_background
3391 (s, s->first_glyph->type == COMPOSITE_GLYPH);
3393 /* Not yet implemented. */
3402 /* Draw box if not done already. */
3403 if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3405 n = ns_get_glyph_string_clip_rect (s, r);
3406 ns_focus (s->f, r, n);
3407 ns_dumpglyphs_box_or_relief (s);
3416 /* ==========================================================================
3420 ========================================================================== */
3424 ns_send_appdefined (int value)
3425 /* --------------------------------------------------------------------------
3426 Internal: post an appdefined event which EmacsApp-sendEvent will
3427 recognize and take as a command to halt the event loop.
3428 -------------------------------------------------------------------------- */
3430 /*NSTRACE (ns_send_appdefined); */
3432 #ifdef NS_IMPL_GNUSTEP
3433 // GNUstep needs postEvent to happen on the main thread.
3434 if (! [[NSThread currentThread] isMainThread])
3436 EmacsApp *app = (EmacsApp *)NSApp;
3437 app->nextappdefined = value;
3438 [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3445 /* Only post this event if we haven't already posted one. This will end
3446 the [NXApp run] main loop after having processed all events queued at
3449 #ifdef NS_IMPL_COCOA
3450 if (! send_appdefined)
3452 /* OSX 10.10.1 swallows the AppDefined event we are sending ourselves
3453 in certain situations (rapid incoming events).
3454 So check if we have one, if not add one. */
3455 NSEvent *appev = [NSApp nextEventMatchingMask:NSApplicationDefinedMask
3456 untilDate:[NSDate distantPast]
3457 inMode:NSDefaultRunLoopMode
3459 if (! appev) send_appdefined = YES;
3463 if (send_appdefined)
3467 /* We only need one NX_APPDEFINED event to stop NXApp from running. */
3468 send_appdefined = NO;
3470 /* Don't need wakeup timer any more */
3473 [timed_entry invalidate];
3474 [timed_entry release];
3478 nxev = [NSEvent otherEventWithType: NSApplicationDefined
3479 location: NSMakePoint (0, 0)
3482 windowNumber: [[NSApp mainWindow] windowNumber]
3483 context: [NSApp context]
3488 /* Post an application defined event on the event queue. When this is
3489 received the [NXApp run] will return, thus having processed all
3490 events which are currently queued. */
3491 [NSApp postEvent: nxev atStart: NO];
3495 #ifdef HAVE_NATIVE_FS
3499 Lisp_Object frame, tail;
3501 if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3504 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3506 FOR_EACH_FRAME (tail, frame)
3508 struct frame *f = XFRAME (frame);
3511 EmacsView *view = FRAME_NS_VIEW (f);
3512 [view updateCollectionBehavior];
3518 /* GNUstep and OSX <= 10.4 does not have cancelTracking. */
3519 #if defined (NS_IMPL_COCOA) && \
3520 MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
3521 /* Check if menu open should be canceled or continued as normal. */
3523 ns_check_menu_open (NSMenu *menu)
3525 /* Click in menu bar? */
3526 NSArray *a = [[NSApp mainMenu] itemArray];
3530 if (menu == nil) // Menu tracking ended.
3532 if (menu_will_open_state == MENU_OPENING)
3533 menu_will_open_state = MENU_NONE;
3537 for (i = 0; ! found && i < [a count]; i++)
3538 found = menu == [[a objectAtIndex:i] submenu];
3541 if (menu_will_open_state == MENU_NONE && emacs_event)
3543 NSEvent *theEvent = [NSApp currentEvent];
3544 struct frame *emacsframe = SELECTED_FRAME ();
3546 [menu cancelTracking];
3547 menu_will_open_state = MENU_PENDING;
3548 emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3549 EV_TRAILER (theEvent);
3551 CGEventRef ourEvent = CGEventCreate (NULL);
3552 menu_mouse_point = CGEventGetLocation (ourEvent);
3553 CFRelease (ourEvent);
3555 else if (menu_will_open_state == MENU_OPENING)
3557 menu_will_open_state = MENU_NONE;
3562 /* Redo saved menu click if state is MENU_PENDING. */
3564 ns_check_pending_open_menu ()
3566 if (menu_will_open_state == MENU_PENDING)
3568 CGEventSourceRef source
3569 = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3571 CGEventRef event = CGEventCreateMouseEvent (source,
3572 kCGEventLeftMouseDown,
3574 kCGMouseButtonLeft);
3575 CGEventSetType (event, kCGEventLeftMouseDown);
3576 CGEventPost (kCGHIDEventTap, event);
3580 menu_will_open_state = MENU_OPENING;
3583 #endif /* NS_IMPL_COCOA) && >= MAC_OS_X_VERSION_10_5 */
3586 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3587 /* --------------------------------------------------------------------------
3588 External (hook): Post an event to ourself and keep reading events until
3589 we read it back again. In effect process all events which were waiting.
3590 From 21+ we have to manage the event buffer ourselves.
3591 -------------------------------------------------------------------------- */
3593 struct input_event ev;
3596 /* NSTRACE (ns_read_socket); */
3598 #ifdef HAVE_NATIVE_FS
3602 if ([NSApp modalWindow] != nil)
3605 if (hold_event_q.nr > 0)
3608 for (i = 0; i < hold_event_q.nr; ++i)
3609 kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3610 hold_event_q.nr = 0;
3615 n_emacs_events_pending = 0;
3618 q_event_ptr = hold_quit;
3620 /* we manage autorelease pools by allocate/reallocate each time around
3621 the loop; strict nesting is occasionally violated but seems not to
3622 matter.. earlier methods using full nesting caused major memory leaks */
3623 [outerpool release];
3624 outerpool = [[NSAutoreleasePool alloc] init];
3626 /* If have pending open-file requests, attend to the next one of those. */
3627 if (ns_pending_files && [ns_pending_files count] != 0
3628 && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3630 [ns_pending_files removeObjectAtIndex: 0];
3632 /* Deal with pending service requests. */
3633 else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3635 NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3636 withArg: [ns_pending_service_args objectAtIndex: 0]])
3638 [ns_pending_service_names removeObjectAtIndex: 0];
3639 [ns_pending_service_args removeObjectAtIndex: 0];
3643 /* Run and wait for events. We must always send one NX_APPDEFINED event
3644 to ourself, otherwise [NXApp run] will never exit. */
3645 send_appdefined = YES;
3646 ns_send_appdefined (-1);
3648 if (++apploopnr != 1)
3656 nevents = n_emacs_events_pending;
3657 n_emacs_events_pending = 0;
3658 emacs_event = q_event_ptr = NULL;
3666 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3667 fd_set *exceptfds, struct timespec const *timeout,
3668 sigset_t const *sigmask)
3669 /* --------------------------------------------------------------------------
3670 Replacement for select, checking for events
3671 -------------------------------------------------------------------------- */
3675 struct input_event event;
3678 /* NSTRACE (ns_select); */
3680 #ifdef HAVE_NATIVE_FS
3684 if (hold_event_q.nr > 0)
3686 /* We already have events pending. */
3692 for (k = 0; k < nfds+1; k++)
3694 if (readfds && FD_ISSET(k, readfds)) ++nr;
3695 if (writefds && FD_ISSET(k, writefds)) ++nr;
3699 || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3700 return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3702 [outerpool release];
3703 outerpool = [[NSAutoreleasePool alloc] init];
3706 send_appdefined = YES;
3709 pthread_mutex_lock (&select_mutex);
3714 select_readfds = *readfds;
3715 select_valid += SELECT_HAVE_READ;
3719 select_writefds = *writefds;
3720 select_valid += SELECT_HAVE_WRITE;
3725 select_timeout = *timeout;
3726 select_valid += SELECT_HAVE_TMO;
3729 pthread_mutex_unlock (&select_mutex);
3731 /* Inform fd_handler that select should be called */
3733 emacs_write_sig (selfds[1], &c, 1);
3735 else if (nr == 0 && timeout)
3737 /* No file descriptor, just a timeout, no need to wake fd_handler */
3738 double time = timespectod (*timeout);
3739 timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3742 @selector (timeout_handler:)
3747 else /* No timeout and no file descriptors, can this happen? */
3749 /* Send appdefined so we exit from the loop */
3750 ns_send_appdefined (-1);
3755 emacs_event = &event;
3756 if (++apploopnr != 1)
3763 if (nr > 0 && readfds)
3766 emacs_write_sig (selfds[1], &c, 1);
3770 t = last_appdefined_event_data;
3772 if (t != NO_APPDEFINED_DATA)
3774 last_appdefined_event_data = NO_APPDEFINED_DATA;
3778 /* The NX_APPDEFINED event we received was a timeout. */
3783 /* The NX_APPDEFINED event we received was the result of
3784 at least one real input event arriving. */
3790 /* Received back from select () in fd_handler; copy the results */
3791 pthread_mutex_lock (&select_mutex);
3792 if (readfds) *readfds = select_readfds;
3793 if (writefds) *writefds = select_writefds;
3794 pthread_mutex_unlock (&select_mutex);
3809 /* ==========================================================================
3813 ========================================================================== */
3817 ns_set_vertical_scroll_bar (struct window *window,
3818 int portion, int whole, int position)
3819 /* --------------------------------------------------------------------------
3820 External (hook): Update or add scrollbar
3821 -------------------------------------------------------------------------- */
3825 struct frame *f = XFRAME (WINDOW_FRAME (window));
3826 EmacsView *view = FRAME_NS_VIEW (f);
3827 int window_y, window_height;
3828 int top, left, height, width, sb_width, sb_left;
3830 BOOL fringe_extended_p;
3831 BOOL update_p = YES;
3833 /* optimization; display engine sends WAY too many of these.. */
3834 if (!NILP (window->vertical_scroll_bar))
3836 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3837 if ([bar checkSamePosition: position portion: portion whole: whole])
3839 if (view->scrollbarsNeedingUpdate == 0)
3841 if (!windows_or_buffers_changed)
3845 view->scrollbarsNeedingUpdate--;
3850 NSTRACE (ns_set_vertical_scroll_bar);
3852 /* Get dimensions. */
3853 window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
3855 height = window_height;
3856 width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3857 left = WINDOW_SCROLL_BAR_AREA_X (window);
3859 /* allow for displaying a skinnier scrollbar than char area allotted */
3860 sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3861 WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3864 r = NSMakeRect (sb_left, top, sb_width, height);
3865 /* the parent view is flipped, so we need to flip y value */
3867 r.origin.y = (v.size.height - r.size.height - r.origin.y);
3869 fringe_extended_p = WINDOW_FRINGE_EXTENDED_P (window);
3871 XSETWINDOW (win, window);
3874 /* we want at least 5 lines to display a scrollbar */
3875 if (WINDOW_TOTAL_LINES (window) < 5)
3877 if (!NILP (window->vertical_scroll_bar))
3879 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3880 [bar removeFromSuperview];
3881 wset_vertical_scroll_bar (window, Qnil);
3884 ns_clear_frame_area (f, sb_left, top, width, height);
3889 if (NILP (window->vertical_scroll_bar))
3891 if (width > 0 && height > 0)
3893 if (fringe_extended_p)
3894 ns_clear_frame_area (f, sb_left, top, sb_width, height);
3896 ns_clear_frame_area (f, left, top, width, height);
3899 bar = [[EmacsScroller alloc] initFrame: r window: win];
3900 wset_vertical_scroll_bar (window, make_save_ptr (bar));
3906 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3907 oldRect = [bar frame];
3908 r.size.width = oldRect.size.width;
3909 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3911 if (oldRect.origin.x != r.origin.x)
3912 ns_clear_frame_area (f, sb_left, top, width, height);
3919 [bar setPosition: position portion: portion whole: whole];
3925 ns_condemn_scroll_bars (struct frame *f)
3926 /* --------------------------------------------------------------------------
3927 External (hook): arrange for all frame's scrollbars to be removed
3928 at next call to judge_scroll_bars, except for those redeemed.
3929 -------------------------------------------------------------------------- */
3933 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3935 NSTRACE (ns_condemn_scroll_bars);
3937 for (i =[subviews count]-1; i >= 0; i--)
3939 view = [subviews objectAtIndex: i];
3940 if ([view isKindOfClass: [EmacsScroller class]])
3947 ns_redeem_scroll_bar (struct window *window)
3948 /* --------------------------------------------------------------------------
3949 External (hook): arrange to spare this window's scrollbar
3950 at next call to judge_scroll_bars.
3951 -------------------------------------------------------------------------- */
3954 NSTRACE (ns_redeem_scroll_bar);
3955 if (!NILP (window->vertical_scroll_bar))
3957 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3964 ns_judge_scroll_bars (struct frame *f)
3965 /* --------------------------------------------------------------------------
3966 External (hook): destroy all scrollbars on frame that weren't
3967 redeemed after call to condemn_scroll_bars.
3968 -------------------------------------------------------------------------- */
3972 EmacsView *eview = FRAME_NS_VIEW (f);
3973 NSArray *subviews = [[eview superview] subviews];
3976 NSTRACE (ns_judge_scroll_bars);
3977 for (i = [subviews count]-1; i >= 0; --i)
3979 view = [subviews objectAtIndex: i];
3980 if (![view isKindOfClass: [EmacsScroller class]]) continue;
3986 [eview updateFrameSize: NO];
3989 /* ==========================================================================
3993 ========================================================================== */
3996 x_display_pixel_height (struct ns_display_info *dpyinfo)
3998 NSArray *screens = [NSScreen screens];
3999 NSEnumerator *enumerator = [screens objectEnumerator];
4004 while ((screen = [enumerator nextObject]) != nil)
4005 frame = NSUnionRect (frame, [screen frame]);
4007 return NSHeight (frame);
4011 x_display_pixel_width (struct ns_display_info *dpyinfo)
4013 NSArray *screens = [NSScreen screens];
4014 NSEnumerator *enumerator = [screens objectEnumerator];
4019 while ((screen = [enumerator nextObject]) != nil)
4020 frame = NSUnionRect (frame, [screen frame]);
4022 return NSWidth (frame);
4026 static Lisp_Object ns_string_to_lispmod (const char *s)
4027 /* --------------------------------------------------------------------------
4028 Convert modifier name to lisp symbol
4029 -------------------------------------------------------------------------- */
4031 if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4033 else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4035 else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4037 else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4039 else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4041 else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4049 ns_default (const char *parameter, Lisp_Object *result,
4050 Lisp_Object yesval, Lisp_Object noval,
4051 BOOL is_float, BOOL is_modstring)
4052 /* --------------------------------------------------------------------------
4053 Check a parameter value in user's preferences
4054 -------------------------------------------------------------------------- */
4056 const char *value = ns_get_defaults_value (parameter);
4062 if (c_strcasecmp (value, "YES") == 0)
4064 else if (c_strcasecmp (value, "NO") == 0)
4066 else if (is_float && (f = strtod (value, &pos), pos != value))
4067 *result = make_float (f);
4068 else if (is_modstring && value)
4069 *result = ns_string_to_lispmod (value);
4070 else fprintf (stderr,
4071 "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4077 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4078 /* --------------------------------------------------------------------------
4079 Initialize global info and storage for display.
4080 -------------------------------------------------------------------------- */
4082 NSScreen *screen = [NSScreen mainScreen];
4083 NSWindowDepth depth = [screen depth];
4085 dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4086 dpyinfo->resy = 72.27;
4087 dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4088 NSColorSpaceFromDepth (depth)]
4089 && ![NSCalibratedWhiteColorSpace isEqualToString:
4090 NSColorSpaceFromDepth (depth)];
4091 dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4092 dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4093 dpyinfo->color_table->colors = NULL;
4094 dpyinfo->root_window = 42; /* a placeholder.. */
4095 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4096 dpyinfo->n_fonts = 0;
4097 dpyinfo->smallest_font_height = 1;
4098 dpyinfo->smallest_char_width = 1;
4100 reset_mouse_highlight (&dpyinfo->mouse_highlight);
4104 /* This and next define (many of the) public functions in this file. */
4105 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4106 with using despite presence in the "system dependent" redisplay
4107 interface. In addition, many of the ns_ methods have code that is
4108 shared with all terms, indicating need for further refactoring. */
4109 extern frame_parm_handler ns_frame_parm_handlers[];
4110 static struct redisplay_interface ns_redisplay_interface =
4112 ns_frame_parm_handlers,
4116 x_clear_end_of_line,
4118 ns_after_update_window_line,
4119 ns_update_window_begin,
4120 ns_update_window_end,
4121 0, /* flush_display */
4122 x_clear_window_mouse_face,
4123 x_get_glyph_overhangs,
4124 x_fix_overlapping_area,
4125 ns_draw_fringe_bitmap,
4126 0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4127 0, /* destroy_fringe_bitmap */
4128 ns_compute_glyph_string_overhangs,
4129 ns_draw_glyph_string,
4130 ns_define_frame_cursor,
4131 ns_clear_frame_area,
4132 ns_draw_window_cursor,
4133 ns_draw_vertical_window_border,
4134 ns_draw_window_divider,
4135 ns_shift_glyphs_for_insert
4140 ns_delete_display (struct ns_display_info *dpyinfo)
4146 /* This function is called when the last frame on a display is deleted. */
4148 ns_delete_terminal (struct terminal *terminal)
4150 struct ns_display_info *dpyinfo = terminal->display_info.ns;
4152 /* Protect against recursive calls. delete_frame in
4153 delete_terminal calls us back when it deletes our last frame. */
4154 if (!terminal->name)
4159 x_destroy_all_bitmaps (dpyinfo);
4160 ns_delete_display (dpyinfo);
4165 static struct terminal *
4166 ns_create_terminal (struct ns_display_info *dpyinfo)
4167 /* --------------------------------------------------------------------------
4168 Set up use of NS before we make the first connection.
4169 -------------------------------------------------------------------------- */
4171 struct terminal *terminal;
4173 NSTRACE (ns_create_terminal);
4175 terminal = create_terminal ();
4177 terminal->type = output_ns;
4178 terminal->display_info.ns = dpyinfo;
4179 dpyinfo->terminal = terminal;
4181 terminal->rif = &ns_redisplay_interface;
4183 terminal->clear_frame_hook = ns_clear_frame;
4184 terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
4185 terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
4186 terminal->ring_bell_hook = ns_ring_bell;
4187 terminal->reset_terminal_modes_hook = NULL;
4188 terminal->set_terminal_modes_hook = NULL;
4189 terminal->update_begin_hook = ns_update_begin;
4190 terminal->update_end_hook = ns_update_end;
4191 terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
4192 terminal->read_socket_hook = ns_read_socket;
4193 terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4194 terminal->mouse_position_hook = ns_mouse_position;
4195 terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4196 terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4198 terminal->fullscreen_hook = ns_fullscreen_hook;
4200 terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4201 terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4202 terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4203 terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4205 terminal->delete_frame_hook = x_destroy_window;
4206 terminal->delete_terminal_hook = ns_delete_terminal;
4212 struct ns_display_info *
4213 ns_term_init (Lisp_Object display_name)
4214 /* --------------------------------------------------------------------------
4215 Start the Application and get things rolling.
4216 -------------------------------------------------------------------------- */
4218 struct terminal *terminal;
4219 struct ns_display_info *dpyinfo;
4220 static int ns_initialized = 0;
4223 if (ns_initialized) return x_display_list;
4226 NSTRACE (ns_term_init);
4228 [outerpool release];
4229 outerpool = [[NSAutoreleasePool alloc] init];
4231 /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4232 /*GSDebugAllocationActive (YES); */
4236 Fset_input_interrupt_mode (Qnil);
4238 if (selfds[0] == -1)
4240 if (emacs_pipe (selfds) != 0)
4242 fprintf (stderr, "Failed to create pipe: %s\n",
4243 emacs_strerror (errno));
4247 fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4248 FD_ZERO (&select_readfds);
4249 FD_ZERO (&select_writefds);
4250 pthread_mutex_init (&select_mutex, NULL);
4253 ns_pending_files = [[NSMutableArray alloc] init];
4254 ns_pending_service_names = [[NSMutableArray alloc] init];
4255 ns_pending_service_args = [[NSMutableArray alloc] init];
4257 /* Start app and create the main menu, window, view.
4258 Needs to be here because ns_initialize_display_info () uses AppKit classes.
4259 The view will then ask the NSApp to stop and return to Emacs. */
4260 [EmacsApp sharedApplication];
4263 [NSApp setDelegate: NSApp];
4265 /* Start the select thread. */
4266 [NSThread detachNewThreadSelector:@selector (fd_handler:)
4270 /* debugging: log all notifications */
4271 /* [[NSNotificationCenter defaultCenter] addObserver: NSApp
4272 selector: @selector (logNotification:)
4273 name: nil object: nil]; */
4275 dpyinfo = xzalloc (sizeof *dpyinfo);
4277 ns_initialize_display_info (dpyinfo);
4278 terminal = ns_create_terminal (dpyinfo);
4280 terminal->kboard = allocate_kboard (Qns);
4281 /* Don't let the initial kboard remain current longer than necessary.
4282 That would cause problems if a file loaded on startup tries to
4283 prompt in the mini-buffer. */
4284 if (current_kboard == initial_kboard)
4285 current_kboard = terminal->kboard;
4286 terminal->kboard->reference_count++;
4288 dpyinfo->next = x_display_list;
4289 x_display_list = dpyinfo;
4291 dpyinfo->name_list_element = Fcons (display_name, Qnil);
4293 terminal->name = xstrdup (SSDATA (display_name));
4297 if (!inhibit_x_resources)
4299 ns_default ("GSFontAntiAlias", &ns_antialias_text,
4302 /* this is a standard variable */
4303 ns_default ("AppleAntiAliasingThreshold", &tmp,
4304 make_float (10.0), make_float (6.0), YES, NO);
4305 ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4309 NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4313 Lisp_Object color_file, color_map, color;
4317 color_file = Fexpand_file_name (build_string ("rgb.txt"),
4318 Fsymbol_value (intern ("data-directory")));
4320 color_map = Fx_load_color_file (color_file);
4321 if (NILP (color_map))
4322 fatal ("Could not read %s.\n", SDATA (color_file));
4324 cl = [[NSColorList alloc] initWithName: @"Emacs"];
4325 for ( ; CONSP (color_map); color_map = XCDR (color_map))
4327 color = XCAR (color_map);
4328 name = SSDATA (XCAR (color));
4329 c = XINT (XCDR (color));
4331 [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
4332 green: GREEN_FROM_ULONG (c) / 255.0
4333 blue: BLUE_FROM_ULONG (c) / 255.0
4335 forKey: [NSString stringWithUTF8String: name]];
4337 [cl writeToFile: nil];
4342 #ifdef NS_IMPL_GNUSTEP
4343 Vwindow_system_version = build_string (gnustep_base_version);
4345 /*PSnextrelease (128, c); */
4346 char c[DBL_BUFSIZE_BOUND];
4347 int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4348 Vwindow_system_version = make_unibyte_string (c, len);
4352 delete_keyboard_wait_descriptor (0);
4354 ns_app_name = [[NSProcessInfo processInfo] processName];
4356 /* Set up OS X app menu */
4357 #ifdef NS_IMPL_COCOA
4361 /* set up the application menu */
4362 svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4363 [svcsMenu setAutoenablesItems: NO];
4364 appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4365 [appMenu setAutoenablesItems: NO];
4366 mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4367 dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4369 [appMenu insertItemWithTitle: @"About Emacs"
4370 action: @selector (orderFrontStandardAboutPanel:)
4373 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4374 [appMenu insertItemWithTitle: @"Preferences..."
4375 action: @selector (showPreferencesWindow:)
4378 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4379 item = [appMenu insertItemWithTitle: @"Services"
4380 action: @selector (menuDown:)
4383 [appMenu setSubmenu: svcsMenu forItem: item];
4384 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4385 [appMenu insertItemWithTitle: @"Hide Emacs"
4386 action: @selector (hide:)
4389 item = [appMenu insertItemWithTitle: @"Hide Others"
4390 action: @selector (hideOtherApplications:)
4393 [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4394 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4395 [appMenu insertItemWithTitle: @"Quit Emacs"
4396 action: @selector (terminate:)
4400 item = [mainMenu insertItemWithTitle: ns_app_name
4401 action: @selector (menuDown:)
4404 [mainMenu setSubmenu: appMenu forItem: item];
4405 [dockMenu insertItemWithTitle: @"New Frame"
4406 action: @selector (newFrame:)
4410 [NSApp setMainMenu: mainMenu];
4411 [NSApp setAppleMenu: appMenu];
4412 [NSApp setServicesMenu: svcsMenu];
4413 /* Needed at least on Cocoa, to get dock menu to show windows */
4414 [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4416 [[NSNotificationCenter defaultCenter]
4417 addObserver: mainMenu
4418 selector: @selector (trackingNotification:)
4419 name: NSMenuDidBeginTrackingNotification object: mainMenu];
4420 [[NSNotificationCenter defaultCenter]
4421 addObserver: mainMenu
4422 selector: @selector (trackingNotification:)
4423 name: NSMenuDidEndTrackingNotification object: mainMenu];
4425 #endif /* MAC OS X menu setup */
4427 /* Register our external input/output types, used for determining
4428 applicable services and also drag/drop eligibility. */
4429 ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4430 ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4432 ns_drag_types = [[NSArray arrayWithObjects:
4434 NSTabularTextPboardType,
4435 NSFilenamesPboardType,
4436 NSURLPboardType, nil] retain];
4438 /* If fullscreen is in init/default-frame-alist, focus isn't set
4439 right for fullscreen windows, so set this. */
4440 [NSApp activateIgnoringOtherApps:YES];
4443 ns_do_open_file = YES;
4445 #ifdef NS_IMPL_GNUSTEP
4446 /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
4447 We must re-catch it so subprocess works. */
4448 catch_child_signal ();
4455 ns_term_shutdown (int sig)
4457 [[NSUserDefaults standardUserDefaults] synchronize];
4459 /* code not reached in emacs.c after this is called by shut_down_emacs: */
4460 if (STRINGP (Vauto_save_list_file_name))
4461 unlink (SSDATA (Vauto_save_list_file_name));
4463 if (sig == 0 || sig == SIGTERM)
4465 [NSApp terminate: NSApp];
4467 else // force a stack trace to happen
4474 /* ==========================================================================
4476 EmacsApp implementation
4478 ========================================================================== */
4481 @implementation EmacsApp
4485 if (self = [super init])
4487 #ifdef NS_IMPL_COCOA
4488 self->isFirst = YES;
4490 #ifdef NS_IMPL_GNUSTEP
4491 self->applicationDidFinishLaunchingCalled = NO;
4498 #ifdef NS_IMPL_COCOA
4501 #ifndef NSAppKitVersionNumber10_9
4502 #define NSAppKitVersionNumber10_9 1265
4505 if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
4511 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4513 if (isFirst) [self finishLaunching];
4516 shouldKeepRunning = YES;
4520 pool = [[NSAutoreleasePool alloc] init];
4523 [self nextEventMatchingMask:NSAnyEventMask
4524 untilDate:[NSDate distantFuture]
4525 inMode:NSDefaultRunLoopMode
4527 [self sendEvent:event];
4528 [self updateWindows];
4529 } while (shouldKeepRunning);
4534 - (void)stop: (id)sender
4536 shouldKeepRunning = NO;
4537 // Stop possible dialog also. Noop if no dialog present.
4538 // The file dialog still leaks 7k - 10k on 10.9 though.
4539 [super stop:sender];
4541 #endif /* NS_IMPL_COCOA */
4543 - (void)logNotification: (NSNotification *)notification
4545 const char *name = [[notification name] UTF8String];
4546 if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4547 && !strstr (name, "WindowNumber"))
4548 NSLog (@"notification: '%@'", [notification name]);
4552 - (void)sendEvent: (NSEvent *)theEvent
4553 /* --------------------------------------------------------------------------
4554 Called when NSApp is running for each event received. Used to stop
4555 the loop when we choose, since there's no way to just run one iteration.
4556 -------------------------------------------------------------------------- */
4558 int type = [theEvent type];
4559 NSWindow *window = [theEvent window];
4561 /* NSTRACE (sendEvent); */
4562 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4564 #ifdef NS_IMPL_GNUSTEP
4565 // Keyboard events aren't propagated to file dialogs for some reason.
4566 if ([NSApp modalWindow] != nil &&
4567 (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
4569 [[NSApp modalWindow] sendEvent: theEvent];
4574 if (represented_filename != nil && represented_frame)
4576 NSString *fstr = represented_filename;
4577 NSView *view = FRAME_NS_VIEW (represented_frame);
4578 #ifdef NS_IMPL_COCOA
4579 /* work around a bug observed on 10.3 and later where
4580 setTitleWithRepresentedFilename does not clear out previous state
4581 if given filename does not exist */
4582 if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
4583 [[view window] setRepresentedFilename: @""];
4585 [[view window] setRepresentedFilename: fstr];
4586 [represented_filename release];
4587 represented_filename = nil;
4588 represented_frame = NULL;
4591 if (type == NSApplicationDefined)
4593 switch ([theEvent data2])
4595 #ifdef NS_IMPL_COCOA
4596 case NSAPP_DATA2_RUNASSCRIPT:
4601 case NSAPP_DATA2_RUNFILEDIALOG:
4602 ns_run_file_dialog ();
4608 if (type == NSCursorUpdate && window == nil)
4610 fprintf (stderr, "Dropping external cursor update event.\n");
4614 if (type == NSApplicationDefined)
4616 /* Events posted by ns_send_appdefined interrupt the run loop here.
4617 But, if a modal window is up, an appdefined can still come through,
4618 (e.g., from a makeKeyWindow event) but stopping self also stops the
4619 modal loop. Just defer it until later. */
4620 if ([NSApp modalWindow] == nil)
4622 last_appdefined_event_data = [theEvent data1];
4627 send_appdefined = YES;
4632 #ifdef NS_IMPL_COCOA
4633 /* If no dialog and none of our frames have focus and it is a move, skip it.
4634 It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
4635 such as Wifi, sound, date or similar.
4636 This prevents "spooky" highlighting in the frame under the menu. */
4637 if (type == NSMouseMoved && [NSApp modalWindow] == nil)
4639 struct ns_display_info *di;
4640 BOOL has_focus = NO;
4641 for (di = x_display_list; ! has_focus && di; di = di->next)
4642 has_focus = di->x_focus_frame != 0;
4648 [super sendEvent: theEvent];
4652 - (void)showPreferencesWindow: (id)sender
4654 struct frame *emacsframe = SELECTED_FRAME ();
4655 NSEvent *theEvent = [NSApp currentEvent];
4659 emacs_event->kind = NS_NONKEY_EVENT;
4660 emacs_event->code = KEY_NS_SHOW_PREFS;
4661 emacs_event->modifiers = 0;
4662 EV_TRAILER (theEvent);
4666 - (void)newFrame: (id)sender
4668 struct frame *emacsframe = SELECTED_FRAME ();
4669 NSEvent *theEvent = [NSApp currentEvent];
4673 emacs_event->kind = NS_NONKEY_EVENT;
4674 emacs_event->code = KEY_NS_NEW_FRAME;
4675 emacs_event->modifiers = 0;
4676 EV_TRAILER (theEvent);
4680 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4681 - (BOOL) openFile: (NSString *)fileName
4683 struct frame *emacsframe = SELECTED_FRAME ();
4684 NSEvent *theEvent = [NSApp currentEvent];
4689 emacs_event->kind = NS_NONKEY_EVENT;
4690 emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4691 ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4692 ns_input_line = Qnil; /* can be start or cons start,end */
4693 emacs_event->modifiers =0;
4694 EV_TRAILER (theEvent);
4700 /* **************************************************************************
4702 EmacsApp delegate implementation
4704 ************************************************************************** */
4706 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4707 /* --------------------------------------------------------------------------
4708 When application is loaded, terminate event loop in ns_term_init
4709 -------------------------------------------------------------------------- */
4711 NSTRACE (applicationDidFinishLaunching);
4712 #ifdef NS_IMPL_GNUSTEP
4713 ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
4715 [NSApp setServicesProvider: NSApp];
4717 [self antialiasThresholdDidChange:nil];
4718 #ifdef NS_IMPL_COCOA
4719 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
4720 [[NSNotificationCenter defaultCenter]
4722 selector:@selector(antialiasThresholdDidChange:)
4723 name:NSAntialiasThresholdChangedNotification
4728 ns_send_appdefined (-2);
4731 - (void)antialiasThresholdDidChange:(NSNotification *)notification
4733 #ifdef NS_IMPL_COCOA
4734 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
4735 macfont_update_antialias_threshold ();
4741 /* Termination sequences:
4744 MenuBar | File | Exit:
4745 Select Quit from App menubar:
4747 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4750 Select Quit from Dock menu:
4753 Cancel -> Nothing else
4757 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4762 - (void) terminate: (id)sender
4764 struct frame *emacsframe = SELECTED_FRAME ();
4769 emacs_event->kind = NS_NONKEY_EVENT;
4770 emacs_event->code = KEY_NS_POWER_OFF;
4771 emacs_event->arg = Qt; /* mark as non-key event */
4772 EV_TRAILER ((id)nil);
4776 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4780 if (NILP (ns_confirm_quit)) // || ns_shutdown_properly --> TO DO
4781 return NSTerminateNow;
4783 ret = NSRunAlertPanel(ns_app_name,
4784 @"Exit requested. Would you like to Save Buffers and Exit, or Cancel the request?",
4785 @"Save Buffers and Exit", @"Cancel", nil);
4787 if (ret == NSAlertDefaultReturn)
4788 return NSTerminateNow;
4789 else if (ret == NSAlertAlternateReturn)
4790 return NSTerminateCancel;
4791 return NSTerminateNow; /* just in case */
4795 not_in_argv (NSString *arg)
4798 const char *a = [arg UTF8String];
4799 for (k = 1; k < initial_argc; ++k)
4800 if (strcmp (a, initial_argv[k]) == 0) return 0;
4804 /* Notification from the Workspace to open a file */
4805 - (BOOL)application: sender openFile: (NSString *)file
4807 if (ns_do_open_file || not_in_argv (file))
4808 [ns_pending_files addObject: file];
4813 /* Open a file as a temporary file */
4814 - (BOOL)application: sender openTempFile: (NSString *)file
4816 if (ns_do_open_file || not_in_argv (file))
4817 [ns_pending_files addObject: file];
4822 /* Notification from the Workspace to open a file noninteractively (?) */
4823 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4825 if (ns_do_open_file || not_in_argv (file))
4826 [ns_pending_files addObject: file];
4830 /* Notification from the Workspace to open multiple files */
4831 - (void)application: sender openFiles: (NSArray *)fileList
4833 NSEnumerator *files = [fileList objectEnumerator];
4835 /* Don't open files from the command line unconditionally,
4836 Cocoa parses the command line wrong, --option value tries to open value
4837 if --option is the last option. */
4838 while ((file = [files nextObject]) != nil)
4839 if (ns_do_open_file || not_in_argv (file))
4840 [ns_pending_files addObject: file];
4842 [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4847 /* Handle dock menu requests. */
4848 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4854 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4855 - (void)applicationWillBecomeActive: (NSNotification *)notification
4857 //ns_app_active=YES;
4859 - (void)applicationDidBecomeActive: (NSNotification *)notification
4861 NSTRACE (applicationDidBecomeActive);
4863 #ifdef NS_IMPL_GNUSTEP
4864 if (! applicationDidFinishLaunchingCalled)
4865 [self applicationDidFinishLaunching:notification];
4867 //ns_app_active=YES;
4869 ns_update_auto_hide_menu_bar ();
4870 // No constraining takes place when the application is not active.
4871 ns_constrain_all_frames ();
4873 - (void)applicationDidResignActive: (NSNotification *)notification
4876 ns_send_appdefined (-1);
4881 /* ==========================================================================
4883 EmacsApp aux handlers for managing event loop
4885 ========================================================================== */
4888 - (void)timeout_handler: (NSTimer *)timedEntry
4889 /* --------------------------------------------------------------------------
4890 The timeout specified to ns_select has passed.
4891 -------------------------------------------------------------------------- */
4893 /*NSTRACE (timeout_handler); */
4894 ns_send_appdefined (-2);
4897 #ifdef NS_IMPL_GNUSTEP
4898 - (void)sendFromMainThread:(id)unused
4900 ns_send_appdefined (nextappdefined);
4904 - (void)fd_handler:(id)unused
4905 /* --------------------------------------------------------------------------
4906 Check data waiting on file descriptors and terminate if so
4907 -------------------------------------------------------------------------- */
4910 int waiting = 1, nfds;
4913 fd_set readfds, writefds, *wfds;
4914 struct timespec timeout, *tmo;
4915 NSAutoreleasePool *pool = nil;
4917 /* NSTRACE (fd_handler); */
4922 pool = [[NSAutoreleasePool alloc] init];
4928 FD_SET (selfds[0], &fds);
4929 result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
4930 if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
4935 pthread_mutex_lock (&select_mutex);
4938 if (select_valid & SELECT_HAVE_READ)
4939 readfds = select_readfds;
4943 if (select_valid & SELECT_HAVE_WRITE)
4945 writefds = select_writefds;
4950 if (select_valid & SELECT_HAVE_TMO)
4952 timeout = select_timeout;
4958 pthread_mutex_unlock (&select_mutex);
4960 FD_SET (selfds[0], &readfds);
4961 if (selfds[0] >= nfds) nfds = selfds[0]+1;
4963 result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
4966 ns_send_appdefined (-2);
4967 else if (result > 0)
4969 if (FD_ISSET (selfds[0], &readfds))
4971 if (read (selfds[0], &c, 1) == 1 && c == 's')
4976 pthread_mutex_lock (&select_mutex);
4977 if (select_valid & SELECT_HAVE_READ)
4978 select_readfds = readfds;
4979 if (select_valid & SELECT_HAVE_WRITE)
4980 select_writefds = writefds;
4981 if (select_valid & SELECT_HAVE_TMO)
4982 select_timeout = timeout;
4983 pthread_mutex_unlock (&select_mutex);
4985 ns_send_appdefined (result);
4995 /* ==========================================================================
4999 ========================================================================== */
5001 /* called from system: queue for next pass through event loop */
5002 - (void)requestService: (NSPasteboard *)pboard
5003 userData: (NSString *)userData
5004 error: (NSString **)error
5006 [ns_pending_service_names addObject: userData];
5007 [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5008 SSDATA (ns_string_from_pasteboard (pboard))]];
5012 /* called from ns_read_socket to clear queue */
5013 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5015 struct frame *emacsframe = SELECTED_FRAME ();
5016 NSEvent *theEvent = [NSApp currentEvent];
5021 emacs_event->kind = NS_NONKEY_EVENT;
5022 emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5023 ns_input_spi_name = build_string ([name UTF8String]);
5024 ns_input_spi_arg = build_string ([arg UTF8String]);
5025 emacs_event->modifiers = EV_MODIFIERS (theEvent);
5026 EV_TRAILER (theEvent);
5036 /* ==========================================================================
5038 EmacsView implementation
5040 ========================================================================== */
5043 @implementation EmacsView
5045 /* needed to inform when window closed from LISP */
5046 - (void) setWindowClosing: (BOOL)closing
5048 windowClosing = closing;
5054 NSTRACE (EmacsView_dealloc);
5056 if (fs_state == FULLSCREEN_BOTH)
5057 [nonfs_window release];
5062 /* called on font panel selection */
5063 - (void)changeFont: (id)sender
5065 NSEvent *e = [[self window] currentEvent];
5066 struct face *face = FRAME_DEFAULT_FACE (emacsframe);
5067 struct font *font = face->font;
5072 NSTRACE (changeFont);
5077 if (EQ (font->driver->type, Qns))
5078 nsfont = ((struct nsfont_info *)font)->nsfont;
5079 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
5081 nsfont = (NSFont *) macfont_get_nsctfont (font);
5084 if ((newFont = [sender convertFont: nsfont]))
5086 SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5088 emacs_event->kind = NS_NONKEY_EVENT;
5089 emacs_event->modifiers = 0;
5090 emacs_event->code = KEY_NS_CHANGE_FONT;
5092 size = [newFont pointSize];
5093 ns_input_fontsize = make_number (lrint (size));
5094 ns_input_font = build_string ([[newFont familyName] UTF8String]);
5100 - (BOOL)acceptsFirstResponder
5102 NSTRACE (acceptsFirstResponder);
5107 - (void)resetCursorRects
5109 NSRect visible = [self visibleRect];
5110 NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5111 NSTRACE (resetCursorRects);
5113 if (currentCursor == nil)
5114 currentCursor = [NSCursor arrowCursor];
5116 if (!NSIsEmptyRect (visible))
5117 [self addCursorRect: visible cursor: currentCursor];
5118 [currentCursor setOnMouseEntered: YES];
5123 /*****************************************************************************/
5124 /* Keyboard handling. */
5127 - (void)keyDown: (NSEvent *)theEvent
5129 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5131 unsigned fnKeysym = 0;
5132 static NSMutableArray *nsEvArray;
5133 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
5134 static BOOL firstTime = YES;
5137 unsigned int flags = [theEvent modifierFlags];
5141 /* Rhapsody and OS X give up and down events for the arrow keys */
5142 if (ns_fake_keydown == YES)
5143 ns_fake_keydown = NO;
5144 else if ([theEvent type] != NSKeyDown)
5150 if (![[self window] isKeyWindow]
5151 && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5152 /* we must avoid an infinite loop here. */
5153 && (EmacsView *)[[theEvent window] delegate] != self)
5155 /* XXX: There is an occasional condition in which, when Emacs display
5156 updates a different frame from the current one, and temporarily
5157 selects it, then processes some interrupt-driven input
5158 (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5159 for some reason that window has its first responder set to the NSView
5160 most recently updated (I guess), which is not the correct one. */
5161 [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5165 if (nsEvArray == nil)
5166 nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5168 [NSCursor setHiddenUntilMouseMoves: YES];
5170 if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5172 clear_mouse_face (hlinfo);
5173 hlinfo->mouse_face_hidden = 1;
5176 if (!processingCompose)
5178 /* When using screen sharing, no left or right information is sent,
5179 so use Left key in those cases. */
5180 int is_left_key, is_right_key;
5182 code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5183 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5185 /* (Carbon way: [theEvent keyCode]) */
5187 /* is it a "function key"? */
5188 /* Note: Sometimes a plain key will have the NSNumericPadKeyMask
5189 flag set (this is probably a bug in the OS).
5191 if (code < 0x00ff && (flags&NSNumericPadKeyMask))
5193 fnKeysym = ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask);
5197 fnKeysym = ns_convert_key (code);
5202 /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5203 because Emacs treats Delete and KP-Delete same (in simple.el). */
5204 if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5205 #ifdef NS_IMPL_GNUSTEP
5206 /* GNUstep uses incompatible keycodes, even for those that are
5207 supposed to be hardware independent. Just check for delete.
5208 Keypad delete does not have keysym 0xFFFF.
5209 See http://savannah.gnu.org/bugs/?25395
5211 || (fnKeysym == 0xFFFF && code == 127)
5214 code = 0xFF08; /* backspace */
5219 /* are there modifiers? */
5220 emacs_event->modifiers = 0;
5222 if (flags & NSHelpKeyMask)
5223 emacs_event->modifiers |= hyper_modifier;
5225 if (flags & NSShiftKeyMask)
5226 emacs_event->modifiers |= shift_modifier;
5228 is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5229 is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5230 || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
5233 emacs_event->modifiers |= parse_solitary_modifier
5234 (EQ (ns_right_command_modifier, Qleft)
5235 ? ns_command_modifier
5236 : ns_right_command_modifier);
5240 emacs_event->modifiers |= parse_solitary_modifier
5241 (ns_command_modifier);
5243 /* if super (default), take input manager's word so things like
5244 dvorak / qwerty layout work */
5245 if (EQ (ns_command_modifier, Qsuper)
5247 && [[theEvent characters] length] != 0)
5249 /* XXX: the code we get will be unshifted, so if we have
5250 a shift modifier, must convert ourselves */
5251 if (!(flags & NSShiftKeyMask))
5252 code = [[theEvent characters] characterAtIndex: 0];
5254 /* this is ugly and also requires linking w/Carbon framework
5255 (for LMGetKbdType) so for now leave this rare (?) case
5256 undealt with.. in future look into CGEvent methods */
5259 long smv = GetScriptManagerVariable (smKeyScript);
5260 Handle uchrHandle = GetResource
5261 ('uchr', GetScriptVariable (smv, smScriptKeys));
5263 UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5264 [[theEvent characters] characterAtIndex: 0],
5265 kUCKeyActionDisplay,
5266 (flags & ~NSCommandKeyMask) >> 8,
5267 LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5268 &dummy, 1, &dummy, &code);
5275 is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5276 is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5277 || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5280 emacs_event->modifiers |= parse_solitary_modifier
5281 (EQ (ns_right_control_modifier, Qleft)
5282 ? ns_control_modifier
5283 : ns_right_control_modifier);
5286 emacs_event->modifiers |= parse_solitary_modifier
5287 (ns_control_modifier);
5289 if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5290 emacs_event->modifiers |=
5291 parse_solitary_modifier (ns_function_modifier);
5293 left_is_none = NILP (ns_alternate_modifier)
5294 || EQ (ns_alternate_modifier, Qnone);
5296 is_right_key = (flags & NSRightAlternateKeyMask)
5297 == NSRightAlternateKeyMask;
5298 is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5300 && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5304 if ((NILP (ns_right_alternate_modifier)
5305 || EQ (ns_right_alternate_modifier, Qnone)
5306 || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5308 { /* accept pre-interp alt comb */
5309 if ([[theEvent characters] length] > 0)
5310 code = [[theEvent characters] characterAtIndex: 0];
5311 /*HACK: clear lone shift modifier to stop next if from firing */
5312 if (emacs_event->modifiers == shift_modifier)
5313 emacs_event->modifiers = 0;
5316 emacs_event->modifiers |= parse_solitary_modifier
5317 (EQ (ns_right_alternate_modifier, Qleft)
5318 ? ns_alternate_modifier
5319 : ns_right_alternate_modifier);
5322 if (is_left_key) /* default = meta */
5324 if (left_is_none && !fnKeysym)
5325 { /* accept pre-interp alt comb */
5326 if ([[theEvent characters] length] > 0)
5327 code = [[theEvent characters] characterAtIndex: 0];
5328 /*HACK: clear lone shift modifier to stop next if from firing */
5329 if (emacs_event->modifiers == shift_modifier)
5330 emacs_event->modifiers = 0;
5333 emacs_event->modifiers |=
5334 parse_solitary_modifier (ns_alternate_modifier);
5338 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5339 code, fnKeysym, flags, emacs_event->modifiers);
5341 /* if it was a function key or had modifiers, pass it directly to emacs */
5342 if (fnKeysym || (emacs_event->modifiers
5343 && (emacs_event->modifiers != shift_modifier)
5344 && [[theEvent charactersIgnoringModifiers] length] > 0))
5345 /*[[theEvent characters] length] */
5347 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5349 code |= (1<<28)|(3<<16);
5350 else if (code == 0x7f)
5351 code |= (1<<28)|(3<<16);
5353 emacs_event->kind = code > 0xFF
5354 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5356 emacs_event->code = code;
5357 EV_TRAILER (theEvent);
5358 processingCompose = NO;
5364 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
5365 /* if we get here we should send the key for input manager processing */
5366 /* Disable warning, there is nothing a user can do about it anyway, and
5367 it does not seem to matter. */
5369 if (firstTime && [[NSInputManager currentInputManager]
5370 wantsToDelayTextChangeNotifications] == NO)
5372 "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
5376 if (NS_KEYLOG && !processingCompose)
5377 fprintf (stderr, "keyDown: Begin compose sequence.\n");
5379 processingCompose = YES;
5380 [nsEvArray addObject: theEvent];
5381 [self interpretKeyEvents: nsEvArray];
5382 [nsEvArray removeObject: theEvent];
5386 #ifdef NS_IMPL_COCOA
5387 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5388 decided not to send key-down for.
5389 See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5390 This only applies on Tiger and earlier.
5391 If it matches one of these, send it on to keyDown. */
5392 -(void)keyUp: (NSEvent *)theEvent
5394 int flags = [theEvent modifierFlags];
5395 int code = [theEvent keyCode];
5396 if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5397 code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5400 fprintf (stderr, "keyUp: passed test");
5401 ns_fake_keydown = YES;
5402 [self keyDown: theEvent];
5408 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5411 /* <NSTextInput>: called when done composing;
5412 NOTE: also called when we delete over working text, followed immed.
5413 by doCommandBySelector: deleteBackward: */
5414 - (void)insertText: (id)aString
5417 int len = [(NSString *)aString length];
5421 NSLog (@"insertText '%@'\tlen = %d", aString, len);
5422 processingCompose = NO;
5427 /* first, clear any working text */
5428 if (workingText != nil)
5429 [self deleteWorkingText];
5431 /* now insert the string as keystrokes */
5432 for (i =0; i<len; i++)
5434 code = [aString characterAtIndex: i];
5435 /* TODO: still need this? */
5437 code = '~'; /* 0x7E */
5438 if (code != 32) /* Space */
5439 emacs_event->modifiers = 0;
5441 = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5442 emacs_event->code = code;
5443 EV_TRAILER ((id)nil);
5448 /* <NSTextInput>: inserts display of composing characters */
5449 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5451 NSString *str = [aString respondsToSelector: @selector (string)] ?
5452 [aString string] : aString;
5454 NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
5455 str, (unsigned long)[str length],
5456 (unsigned long)selRange.length,
5457 (unsigned long)selRange.location);
5459 if (workingText != nil)
5460 [self deleteWorkingText];
5461 if ([str length] == 0)
5467 processingCompose = YES;
5468 workingText = [str copy];
5469 ns_working_text = build_string ([workingText UTF8String]);
5471 emacs_event->kind = NS_TEXT_EVENT;
5472 emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5473 EV_TRAILER ((id)nil);
5477 /* delete display of composing characters [not in <NSTextInput>] */
5478 - (void)deleteWorkingText
5480 if (workingText == nil)
5483 NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
5484 [workingText release];
5486 processingCompose = NO;
5491 emacs_event->kind = NS_TEXT_EVENT;
5492 emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5493 EV_TRAILER ((id)nil);
5497 - (BOOL)hasMarkedText
5499 return workingText != nil;
5503 - (NSRange)markedRange
5505 NSRange rng = workingText != nil
5506 ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5508 NSLog (@"markedRange request");
5516 NSLog (@"unmark (accept) text");
5517 [self deleteWorkingText];
5518 processingCompose = NO;
5522 /* used to position char selection windows, etc. */
5523 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5527 struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5529 NSLog (@"firstRectForCharRange request");
5531 rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5532 rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5533 pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5534 pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5535 +FRAME_LINE_HEIGHT (emacsframe));
5537 pt = [self convertPoint: pt toView: nil];
5538 pt = [[self window] convertBaseToScreen: pt];
5544 - (NSInteger)conversationIdentifier
5546 return (NSInteger)self;
5550 - (void)doCommandBySelector: (SEL)aSelector
5553 NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5555 processingCompose = NO;
5556 if (aSelector == @selector (deleteBackward:))
5558 /* happens when user backspaces over an ongoing composition:
5559 throw a 'delete' into the event queue */
5562 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5563 emacs_event->code = 0xFF08;
5564 EV_TRAILER ((id)nil);
5568 - (NSArray *)validAttributesForMarkedText
5570 static NSArray *arr = nil;
5571 if (arr == nil) arr = [NSArray new];
5572 /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5576 - (NSRange)selectedRange
5579 NSLog (@"selectedRange request");
5580 return NSMakeRange (NSNotFound, 0);
5583 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
5584 GNUSTEP_GUI_MINOR_VERSION > 22
5585 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5587 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
5591 NSLog (@"characterIndexForPoint request");
5595 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5597 static NSAttributedString *str = nil;
5598 if (str == nil) str = [NSAttributedString new];
5600 NSLog (@"attributedSubstringFromRange request");
5604 /* End <NSTextInput> impl. */
5605 /*****************************************************************************/
5608 /* This is what happens when the user presses a mouse button. */
5609 - (void)mouseDown: (NSEvent *)theEvent
5611 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5612 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5614 NSTRACE (mouseDown);
5616 [self deleteWorkingText];
5621 dpyinfo->last_mouse_frame = emacsframe;
5622 /* appears to be needed to prevent spurious movement events generated on
5624 emacsframe->mouse_moved = 0;
5626 if ([theEvent type] == NSScrollWheel)
5628 CGFloat delta = [theEvent deltaY];
5629 /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5632 delta = [theEvent deltaX];
5635 NSTRACE (deltaIsZero);
5638 emacs_event->kind = HORIZ_WHEEL_EVENT;
5641 emacs_event->kind = WHEEL_EVENT;
5643 emacs_event->code = 0;
5644 emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5645 ((delta > 0) ? up_modifier : down_modifier);
5649 emacs_event->kind = MOUSE_CLICK_EVENT;
5650 emacs_event->code = EV_BUTTON (theEvent);
5651 emacs_event->modifiers = EV_MODIFIERS (theEvent)
5652 | EV_UDMODIFIERS (theEvent);
5654 XSETINT (emacs_event->x, lrint (p.x));
5655 XSETINT (emacs_event->y, lrint (p.y));
5656 EV_TRAILER (theEvent);
5660 - (void)rightMouseDown: (NSEvent *)theEvent
5662 NSTRACE (rightMouseDown);
5663 [self mouseDown: theEvent];
5667 - (void)otherMouseDown: (NSEvent *)theEvent
5669 NSTRACE (otherMouseDown);
5670 [self mouseDown: theEvent];
5674 - (void)mouseUp: (NSEvent *)theEvent
5677 [self mouseDown: theEvent];
5681 - (void)rightMouseUp: (NSEvent *)theEvent
5683 NSTRACE (rightMouseUp);
5684 [self mouseDown: theEvent];
5688 - (void)otherMouseUp: (NSEvent *)theEvent
5690 NSTRACE (otherMouseUp);
5691 [self mouseDown: theEvent];
5695 - (void) scrollWheel: (NSEvent *)theEvent
5697 NSTRACE (scrollWheel);
5698 [self mouseDown: theEvent];
5702 /* Tell emacs the mouse has moved. */
5703 - (void)mouseMoved: (NSEvent *)e
5705 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5706 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5710 // NSTRACE (mouseMoved);
5712 dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
5713 pt = [self convertPoint: [e locationInWindow] fromView: nil];
5714 dpyinfo->last_mouse_motion_x = pt.x;
5715 dpyinfo->last_mouse_motion_y = pt.y;
5717 /* update any mouse face */
5718 if (hlinfo->mouse_face_hidden)
5720 hlinfo->mouse_face_hidden = 0;
5721 clear_mouse_face (hlinfo);
5724 /* tooltip handling */
5725 previous_help_echo_string = help_echo_string;
5726 help_echo_string = Qnil;
5728 if (!NILP (Vmouse_autoselect_window))
5730 NSTRACE (mouse_autoselect_window);
5731 static Lisp_Object last_mouse_window;
5733 = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
5735 if (WINDOWP (window)
5736 && !EQ (window, last_mouse_window)
5737 && !EQ (window, selected_window)
5738 && (focus_follows_mouse
5739 || (EQ (XWINDOW (window)->frame,
5740 XWINDOW (selected_window)->frame))))
5742 NSTRACE (in_window);
5743 emacs_event->kind = SELECT_WINDOW_EVENT;
5744 emacs_event->frame_or_window = window;
5747 /* Remember the last window where we saw the mouse. */
5748 last_mouse_window = window;
5751 if (!note_mouse_movement (emacsframe, pt.x, pt.y))
5752 help_echo_string = previous_help_echo_string;
5754 XSETFRAME (frame, emacsframe);
5755 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5757 /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5758 (note_mouse_highlight), which is called through the
5759 note_mouse_movement () call above */
5760 gen_help_event (help_echo_string, frame, help_echo_window,
5761 help_echo_object, help_echo_pos);
5765 help_echo_string = Qnil;
5766 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5769 if (emacsframe->mouse_moved && send_appdefined)
5770 ns_send_appdefined (-1);
5774 - (void)mouseDragged: (NSEvent *)e
5776 NSTRACE (mouseDragged);
5777 [self mouseMoved: e];
5781 - (void)rightMouseDragged: (NSEvent *)e
5783 NSTRACE (rightMouseDragged);
5784 [self mouseMoved: e];
5788 - (void)otherMouseDragged: (NSEvent *)e
5790 NSTRACE (otherMouseDragged);
5791 [self mouseMoved: e];
5795 - (BOOL)windowShouldClose: (id)sender
5797 NSEvent *e =[[self window] currentEvent];
5799 NSTRACE (windowShouldClose);
5800 windowClosing = YES;
5803 emacs_event->kind = DELETE_WINDOW_EVENT;
5804 emacs_event->modifiers = 0;
5805 emacs_event->code = 0;
5807 /* Don't close this window, let this be done from lisp code. */
5811 - (void) updateFrameSize: (BOOL) delay;
5813 NSWindow *window = [self window];
5814 NSRect wr = [window frame];
5816 int oldc = cols, oldr = rows;
5817 int oldw = FRAME_PIXEL_WIDTH (emacsframe);
5818 int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5821 NSTRACE (updateFrameSize);
5822 NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
5824 if (! [self isFullscreen])
5826 #ifdef NS_IMPL_GNUSTEP
5827 // GNUstep does not always update the tool bar height. Force it.
5828 if (toolbar) update_frame_tool_bar (emacsframe);
5831 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5832 + FRAME_TOOLBAR_HEIGHT (emacsframe);
5835 if (wait_for_tool_bar)
5837 if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0)
5839 wait_for_tool_bar = NO;
5842 neww = (int)wr.size.width - emacsframe->border_width;
5843 newh = (int)wr.size.height - extra;
5845 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
5846 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
5848 if (cols < MINWIDTH)
5851 if (rows < MINHEIGHT)
5854 if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5856 NSView *view = FRAME_NS_VIEW (emacsframe);
5857 NSWindow *win = [view window];
5858 NSSize sz = [win resizeIncrements];
5860 change_frame_size (emacsframe,
5861 FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
5862 FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
5864 SET_FRAME_GARBAGED (emacsframe);
5865 cancel_mouse_face (emacsframe);
5867 // Did resize increments change because of a font change?
5868 if (sz.width != FRAME_COLUMN_WIDTH (emacsframe) ||
5869 sz.height != FRAME_LINE_HEIGHT (emacsframe) ||
5870 (frame_resize_pixelwise && sz.width != 1))
5872 sz.width = frame_resize_pixelwise
5873 ? 1 : FRAME_COLUMN_WIDTH (emacsframe);
5874 sz.height = frame_resize_pixelwise
5875 ? 1 : FRAME_LINE_HEIGHT (emacsframe);
5876 [win setResizeIncrements: sz];
5878 NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
5881 [view setFrame: NSMakeRect (0, 0, neww, newh)];
5882 [self windowDidMove:nil]; // Update top/left.
5886 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5887 /* normalize frame to gridded text size */
5891 NSTRACE (windowWillResize);
5892 NSTRACE_SIZE ("Original size", frameSize);
5893 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5895 if (fs_state == FULLSCREEN_MAXIMIZED
5896 && (maximized_width != (int)frameSize.width
5897 || maximized_height != (int)frameSize.height))
5898 [self setFSValue: FULLSCREEN_NONE];
5899 else if (fs_state == FULLSCREEN_WIDTH
5900 && maximized_width != (int)frameSize.width)
5901 [self setFSValue: FULLSCREEN_NONE];
5902 else if (fs_state == FULLSCREEN_HEIGHT
5903 && maximized_height != (int)frameSize.height)
5904 [self setFSValue: FULLSCREEN_NONE];
5905 if (fs_state == FULLSCREEN_NONE)
5906 maximized_width = maximized_height = -1;
5908 if (! [self isFullscreen])
5910 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5911 + FRAME_TOOLBAR_HEIGHT (emacsframe);
5914 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
5915 if (cols < MINWIDTH)
5918 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
5919 frameSize.height - extra);
5920 if (rows < MINHEIGHT)
5922 #ifdef NS_IMPL_COCOA
5924 /* this sets window title to have size in it; the wm does this under GS */
5925 NSRect r = [[self window] frame];
5926 if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5934 else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
5937 NSWindow *window = [self window];
5940 char *t = strdup ([[[self window] title] UTF8String]);
5941 char *pos = strstr (t, " — ");
5946 size_title = xmalloc (strlen (old_title) + 40);
5947 esprintf (size_title, "%s — (%d x %d)", old_title, cols, rows);
5948 [window setTitle: [NSString stringWithUTF8String: size_title]];
5953 #endif /* NS_IMPL_COCOA */
5954 /*fprintf (stderr," ...size became %.0f x %.0f (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5960 - (void)windowDidResize: (NSNotification *)notification
5962 if (! [self fsIsNative])
5964 NSWindow *theWindow = [notification object];
5965 /* We can get notification on the non-FS window when in
5967 if ([self window] != theWindow) return;
5970 #ifdef NS_IMPL_GNUSTEP
5971 NSWindow *theWindow = [notification object];
5973 /* In GNUstep, at least currently, it's possible to get a didResize
5974 without getting a willResize.. therefore we need to act as if we got
5975 the willResize now */
5976 NSSize sz = [theWindow frame].size;
5977 sz = [self windowWillResize: theWindow toSize: sz];
5978 #endif /* NS_IMPL_GNUSTEP */
5980 NSTRACE (windowDidResize);
5981 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5983 if (cols > 0 && rows > 0)
5985 [self updateFrameSize: YES];
5988 ns_send_appdefined (-1);
5991 #ifdef NS_IMPL_COCOA
5992 - (void)viewDidEndLiveResize
5994 [super viewDidEndLiveResize];
5997 [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
6001 maximizing_resize = NO;
6003 #endif /* NS_IMPL_COCOA */
6006 - (void)windowDidBecomeKey: (NSNotification *)notification
6007 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6009 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6010 struct frame *old_focus = dpyinfo->x_focus_frame;
6012 NSTRACE (windowDidBecomeKey);
6014 if (emacsframe != old_focus)
6015 dpyinfo->x_focus_frame = emacsframe;
6017 ns_frame_rehighlight (emacsframe);
6021 emacs_event->kind = FOCUS_IN_EVENT;
6022 EV_TRAILER ((id)nil);
6027 - (void)windowDidResignKey: (NSNotification *)notification
6028 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6030 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6031 BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6032 NSTRACE (windowDidResignKey);
6035 dpyinfo->x_focus_frame = 0;
6037 emacsframe->mouse_moved = 0;
6038 ns_frame_rehighlight (emacsframe);
6040 /* FIXME: for some reason needed on second and subsequent clicks away
6041 from sole-frame Emacs to get hollow box to show */
6042 if (!windowClosing && [[self window] isVisible] == YES)
6044 x_update_cursor (emacsframe, 1);
6045 x_set_frame_alpha (emacsframe);
6048 if (emacs_event && is_focus_frame)
6050 [self deleteWorkingText];
6051 emacs_event->kind = FOCUS_OUT_EVENT;
6052 EV_TRAILER ((id)nil);
6057 - (void)windowWillMiniaturize: sender
6059 NSTRACE (windowWillMiniaturize);
6075 - initFrameFromEmacs: (struct frame *)f
6084 NSTRACE (initFrameFromEmacs);
6087 processingCompose = NO;
6088 scrollbarsNeedingUpdate = 0;
6089 fs_state = FULLSCREEN_NONE;
6090 fs_before_fs = next_maximized = -1;
6091 #ifdef HAVE_NATIVE_FS
6092 fs_is_native = ns_use_native_fullscreen;
6096 maximized_width = maximized_height = -1;
6099 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
6101 ns_userRect = NSMakeRect (0, 0, 0, 0);
6102 r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
6103 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
6104 [self initWithFrame: r];
6105 [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
6107 FRAME_NS_VIEW (f) = self;
6109 #ifdef NS_IMPL_COCOA
6111 maximizing_resize = NO;
6114 win = [[EmacsWindow alloc]
6115 initWithContentRect: r
6116 styleMask: (NSResizableWindowMask |
6117 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6118 NSTitledWindowMask |
6120 NSMiniaturizableWindowMask |
6121 NSClosableWindowMask)
6122 backing: NSBackingStoreBuffered
6125 #ifdef HAVE_NATIVE_FS
6126 [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
6130 bwidth = f->border_width = wr.size.width - r.size.width;
6131 tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
6133 [win setAcceptsMouseMovedEvents: YES];
6134 [win setDelegate: self];
6135 [win useOptimizedDrawing: YES];
6137 sz.width = frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f);
6138 sz.height = frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f);
6139 [win setResizeIncrements: sz];
6141 [[win contentView] addSubview: self];
6144 [self registerForDraggedTypes: ns_drag_types];
6147 name = [NSString stringWithUTF8String:
6148 NILP (tem) ? "Emacs" : SSDATA (tem)];
6149 [win setTitle: name];
6151 /* toolbar support */
6152 toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6153 [NSString stringWithFormat: @"Emacs Frame %d",
6155 [win setToolbar: toolbar];
6156 [toolbar setVisible: NO];
6158 /* Don't set frame garbaged until tool bar is up to date?
6159 This avoids an extra clear and redraw (flicker) at frame creation. */
6160 if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6161 else wait_for_tool_bar = NO;
6164 #ifdef NS_IMPL_COCOA
6166 NSButton *toggleButton;
6167 toggleButton = [win standardWindowButton: NSWindowToolbarButton];
6168 [toggleButton setTarget: self];
6169 [toggleButton setAction: @selector (toggleToolbar: )];
6172 FRAME_TOOLBAR_HEIGHT (f) = 0;
6176 [win setMiniwindowTitle:
6177 [NSString stringWithUTF8String: SSDATA (tem)]];
6180 NSScreen *screen = [win screen];
6183 [win setFrameTopLeftPoint: NSMakePoint
6184 (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
6185 IN_BOUND (-SCREENMAX,
6186 [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
6189 [win makeFirstResponder: self];
6191 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6192 (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
6193 [win setBackgroundColor: col];
6194 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6195 [win setOpaque: NO];
6197 [self allocateGState];
6199 [NSApp registerServicesMenuSendTypes: ns_send_types
6207 - (void)windowDidMove: sender
6209 NSWindow *win = [self window];
6210 NSRect r = [win frame];
6211 NSArray *screens = [NSScreen screens];
6212 NSScreen *screen = [screens objectAtIndex: 0];
6214 NSTRACE (windowDidMove);
6216 if (!emacsframe->output_data.ns)
6220 emacsframe->left_pos = r.origin.x;
6221 emacsframe->top_pos =
6222 [screen frame].size.height - (r.origin.y + r.size.height);
6227 /* Called AFTER method below, but before our windowWillResize call there leads
6228 to windowDidResize -> x_set_window_size. Update emacs' notion of frame
6229 location so set_window_size moves the frame. */
6230 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
6232 emacsframe->output_data.ns->zooming = 1;
6237 /* Override to do something slightly nonstandard, but nice. First click on
6238 zoom button will zoom vertically. Second will zoom completely. Third
6239 returns to original. */
6240 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
6241 defaultFrame:(NSRect)defaultFrame
6243 NSRect result = [sender frame];
6245 NSTRACE (windowWillUseStandardFrame);
6247 if (fs_before_fs != -1) /* Entering fullscreen */
6249 result = defaultFrame;
6251 else if (next_maximized == FULLSCREEN_HEIGHT
6252 || (next_maximized == -1
6253 && abs (defaultFrame.size.height - result.size.height)
6254 > FRAME_LINE_HEIGHT (emacsframe)))
6257 ns_userRect = result;
6258 maximized_height = result.size.height = defaultFrame.size.height;
6259 maximized_width = -1;
6260 result.origin.y = defaultFrame.origin.y;
6261 [self setFSValue: FULLSCREEN_HEIGHT];
6262 #ifdef NS_IMPL_COCOA
6263 maximizing_resize = YES;
6266 else if (next_maximized == FULLSCREEN_WIDTH)
6268 ns_userRect = result;
6269 maximized_width = result.size.width = defaultFrame.size.width;
6270 maximized_height = -1;
6271 result.origin.x = defaultFrame.origin.x;
6272 [self setFSValue: FULLSCREEN_WIDTH];
6274 else if (next_maximized == FULLSCREEN_MAXIMIZED
6275 || (next_maximized == -1
6276 && abs (defaultFrame.size.width - result.size.width)
6277 > FRAME_COLUMN_WIDTH (emacsframe)))
6279 result = defaultFrame; /* second click */
6280 maximized_width = result.size.width;
6281 maximized_height = result.size.height;
6282 [self setFSValue: FULLSCREEN_MAXIMIZED];
6283 #ifdef NS_IMPL_COCOA
6284 maximizing_resize = YES;
6290 result = ns_userRect.size.height ? ns_userRect : result;
6291 ns_userRect = NSMakeRect (0, 0, 0, 0);
6292 #ifdef NS_IMPL_COCOA
6293 maximizing_resize = fs_state != FULLSCREEN_NONE;
6295 [self setFSValue: FULLSCREEN_NONE];
6296 maximized_width = maximized_height = -1;
6299 if (fs_before_fs == -1) next_maximized = -1;
6300 [self windowWillResize: sender toSize: result.size];
6305 - (void)windowDidDeminiaturize: sender
6307 NSTRACE (windowDidDeminiaturize);
6308 if (!emacsframe->output_data.ns)
6311 SET_FRAME_ICONIFIED (emacsframe, 0);
6312 SET_FRAME_VISIBLE (emacsframe, 1);
6313 windows_or_buffers_changed = 63;
6317 emacs_event->kind = DEICONIFY_EVENT;
6318 EV_TRAILER ((id)nil);
6323 - (void)windowDidExpose: sender
6325 NSTRACE (windowDidExpose);
6326 if (!emacsframe->output_data.ns)
6329 SET_FRAME_VISIBLE (emacsframe, 1);
6330 SET_FRAME_GARBAGED (emacsframe);
6332 if (send_appdefined)
6333 ns_send_appdefined (-1);
6337 - (void)windowDidMiniaturize: sender
6339 NSTRACE (windowDidMiniaturize);
6340 if (!emacsframe->output_data.ns)
6343 SET_FRAME_ICONIFIED (emacsframe, 1);
6344 SET_FRAME_VISIBLE (emacsframe, 0);
6348 emacs_event->kind = ICONIFY_EVENT;
6349 EV_TRAILER ((id)nil);
6353 #ifdef HAVE_NATIVE_FS
6354 - (NSApplicationPresentationOptions)window:(NSWindow *)window
6355 willUseFullScreenPresentationOptions:
6356 (NSApplicationPresentationOptions)proposedOptions
6358 return proposedOptions|NSApplicationPresentationAutoHideToolbar;
6362 - (void)windowWillEnterFullScreen:(NSNotification *)notification
6364 fs_before_fs = fs_state;
6367 - (void)windowDidEnterFullScreen:(NSNotification *)notification
6369 [self setFSValue: FULLSCREEN_BOTH];
6370 if (! [self fsIsNative])
6372 [self windowDidBecomeKey:notification];
6373 [nonfs_window orderOut:self];
6377 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
6378 #ifdef NS_IMPL_COCOA
6379 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6380 unsigned val = (unsigned)[NSApp presentationOptions];
6382 // OSX 10.7 bug fix, the menu won't appear without this.
6383 // val is non-zero on other OSX versions.
6386 NSApplicationPresentationOptions options
6387 = NSApplicationPresentationAutoHideDock
6388 | NSApplicationPresentationAutoHideMenuBar
6389 | NSApplicationPresentationFullScreen
6390 | NSApplicationPresentationAutoHideToolbar;
6392 [NSApp setPresentationOptions: options];
6396 [toolbar setVisible:tbar_visible];
6400 - (void)windowWillExitFullScreen:(NSNotification *)notification
6402 if (next_maximized != -1)
6403 fs_before_fs = next_maximized;
6406 - (void)windowDidExitFullScreen:(NSNotification *)notification
6408 [self setFSValue: fs_before_fs];
6410 #ifdef HAVE_NATIVE_FS
6411 [self updateCollectionBehavior];
6413 if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6415 [toolbar setVisible:YES];
6416 update_frame_tool_bar (emacsframe);
6417 [self updateFrameSize:YES];
6418 [[self window] display];
6421 [toolbar setVisible:NO];
6423 if (next_maximized != -1)
6424 [[self window] performZoom:self];
6429 return fs_is_native;
6432 - (BOOL)isFullscreen
6434 if (! fs_is_native) return nonfs_window != nil;
6435 #ifdef HAVE_NATIVE_FS
6436 return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
6442 #ifdef HAVE_NATIVE_FS
6443 - (void)updateCollectionBehavior
6445 if (! [self isFullscreen])
6447 NSWindow *win = [self window];
6448 NSWindowCollectionBehavior b = [win collectionBehavior];
6449 if (ns_use_native_fullscreen)
6450 b |= NSWindowCollectionBehaviorFullScreenPrimary;
6452 b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
6454 [win setCollectionBehavior: b];
6455 fs_is_native = ns_use_native_fullscreen;
6460 - (void)toggleFullScreen: (id)sender
6471 #ifdef HAVE_NATIVE_FS
6472 [[self window] toggleFullScreen:sender];
6478 onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
6481 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6482 (FRAME_DEFAULT_FACE (f)),
6485 sz.width = frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f);
6486 sz.height = frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f);
6488 if (fs_state != FULLSCREEN_BOTH)
6490 NSScreen *screen = [w screen];
6492 #if defined (NS_IMPL_COCOA) && \
6493 MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
6494 /* Hide ghost menu bar on secondary monitor? */
6495 if (! onFirstScreen)
6496 onFirstScreen = [NSScreen screensHaveSeparateSpaces];
6498 /* Hide dock and menubar if we are on the primary screen. */
6501 #if defined (NS_IMPL_COCOA) && \
6502 MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6503 NSApplicationPresentationOptions options
6504 = NSApplicationPresentationAutoHideDock
6505 | NSApplicationPresentationAutoHideMenuBar;
6507 [NSApp setPresentationOptions: options];
6509 [NSMenu setMenuBarVisible:NO];
6513 fw = [[EmacsFSWindow alloc]
6514 initWithContentRect:[w contentRectForFrameRect:wr]
6515 styleMask:NSBorderlessWindowMask
6516 backing:NSBackingStoreBuffered
6520 [fw setContentView:[w contentView]];
6521 [fw setTitle:[w title]];
6522 [fw setDelegate:self];
6523 [fw setAcceptsMouseMovedEvents: YES];
6524 [fw useOptimizedDrawing: YES];
6525 [fw setResizeIncrements: sz];
6526 [fw setBackgroundColor: col];
6527 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6530 f->border_width = 0;
6531 FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
6532 tobar_height = FRAME_TOOLBAR_HEIGHT (f);
6533 FRAME_TOOLBAR_HEIGHT (f) = 0;
6537 [self windowWillEnterFullScreen:nil];
6538 [fw makeKeyAndOrderFront:NSApp];
6539 [fw makeFirstResponder:self];
6541 r = [fw frameRectForContentRect:[screen frame]];
6542 [fw setFrame: r display:YES animate:YES];
6543 [self windowDidEnterFullScreen:nil];
6554 #if defined (NS_IMPL_COCOA) && \
6555 MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6556 [NSApp setPresentationOptions: NSApplicationPresentationDefault];
6558 [NSMenu setMenuBarVisible:YES];
6562 [w setContentView:[fw contentView]];
6563 [w setResizeIncrements: sz];
6564 [w setBackgroundColor: col];
6565 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6568 f->border_width = bwidth;
6569 FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
6570 if (FRAME_EXTERNAL_TOOL_BAR (f))
6571 FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
6573 [self windowWillExitFullScreen:nil];
6574 [fw setFrame: [w frame] display:YES animate:YES];
6576 [w makeKeyAndOrderFront:NSApp];
6577 [self windowDidExitFullScreen:nil];
6578 [self updateFrameSize:YES];
6584 if (fs_state != emacsframe->want_fullscreen)
6586 if (fs_state == FULLSCREEN_BOTH)
6588 [self toggleFullScreen:self];
6591 switch (emacsframe->want_fullscreen)
6593 case FULLSCREEN_BOTH:
6594 [self toggleFullScreen:self];
6596 case FULLSCREEN_WIDTH:
6597 next_maximized = FULLSCREEN_WIDTH;
6598 if (fs_state != FULLSCREEN_BOTH)
6599 [[self window] performZoom:self];
6601 case FULLSCREEN_HEIGHT:
6602 next_maximized = FULLSCREEN_HEIGHT;
6603 if (fs_state != FULLSCREEN_BOTH)
6604 [[self window] performZoom:self];
6606 case FULLSCREEN_MAXIMIZED:
6607 next_maximized = FULLSCREEN_MAXIMIZED;
6608 if (fs_state != FULLSCREEN_BOTH)
6609 [[self window] performZoom:self];
6611 case FULLSCREEN_NONE:
6612 if (fs_state != FULLSCREEN_BOTH)
6614 next_maximized = FULLSCREEN_NONE;
6615 [[self window] performZoom:self];
6620 emacsframe->want_fullscreen = FULLSCREEN_NONE;
6625 - (void) setFSValue: (int)value
6627 Lisp_Object lval = Qnil;
6630 case FULLSCREEN_BOTH:
6633 case FULLSCREEN_WIDTH:
6636 case FULLSCREEN_HEIGHT:
6639 case FULLSCREEN_MAXIMIZED:
6643 store_frame_param (emacsframe, Qfullscreen, lval);
6647 - (void)mouseEntered: (NSEvent *)theEvent
6649 NSTRACE (mouseEntered);
6651 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6652 = EV_TIMESTAMP (theEvent);
6656 - (void)mouseExited: (NSEvent *)theEvent
6658 Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6660 NSTRACE (mouseExited);
6665 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6666 = EV_TIMESTAMP (theEvent);
6668 if (emacsframe == hlinfo->mouse_face_mouse_frame)
6670 clear_mouse_face (hlinfo);
6671 hlinfo->mouse_face_mouse_frame = 0;
6679 if (context_menu_value == -1)
6680 context_menu_value = [sender tag];
6683 NSInteger tag = [sender tag];
6684 find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6685 emacsframe->menu_bar_vector,
6689 ns_send_appdefined (-1);
6694 - (EmacsToolbar *)toolbar
6700 /* this gets called on toolbar button click */
6701 - toolbarClicked: (id)item
6704 int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6706 NSTRACE (toolbarClicked);
6711 /* send first event (for some reason two needed) */
6712 theEvent = [[self window] currentEvent];
6713 emacs_event->kind = TOOL_BAR_EVENT;
6714 XSETFRAME (emacs_event->arg, emacsframe);
6715 EV_TRAILER (theEvent);
6717 emacs_event->kind = TOOL_BAR_EVENT;
6718 /* XSETINT (emacs_event->code, 0); */
6719 emacs_event->arg = AREF (emacsframe->tool_bar_items,
6720 idx + TOOL_BAR_ITEM_KEY);
6721 emacs_event->modifiers = EV_MODIFIERS (theEvent);
6722 EV_TRAILER (theEvent);
6727 - toggleToolbar: (id)sender
6732 emacs_event->kind = NS_NONKEY_EVENT;
6733 emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6734 EV_TRAILER ((id)nil);
6739 - (void)drawRect: (NSRect)rect
6741 int x = NSMinX (rect), y = NSMinY (rect);
6742 int width = NSWidth (rect), height = NSHeight (rect);
6746 if (!emacsframe || !emacsframe->output_data.ns)
6749 ns_clear_frame_area (emacsframe, x, y, width, height);
6750 expose_frame (emacsframe, x, y, width, height);
6753 drawRect: may be called (at least in OS X 10.5) for invisible
6754 views as well for some reason. Thus, do not infer visibility
6757 emacsframe->async_visible = 1;
6758 emacsframe->async_iconified = 0;
6763 /* NSDraggingDestination protocol methods. Actually this is not really a
6764 protocol, but a category of Object. O well... */
6766 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
6768 NSTRACE (draggingEntered);
6769 return NSDragOperationGeneric;
6773 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6779 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6784 NSEvent *theEvent = [[self window] currentEvent];
6786 NSDragOperation op = [sender draggingSourceOperationMask];
6789 NSTRACE (performDragOperation);
6794 position = [self convertPoint: [sender draggingLocation] fromView: nil];
6795 x = lrint (position.x); y = lrint (position.y);
6797 pb = [sender draggingPasteboard];
6798 type = [pb availableTypeFromArray: ns_drag_types];
6800 if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
6801 // URL drags contain all operations (0xf), don't allow all to be set.
6804 if (op & NSDragOperationLink)
6805 modifiers |= NSControlKeyMask;
6806 if (op & NSDragOperationCopy)
6807 modifiers |= NSAlternateKeyMask;
6808 if (op & NSDragOperationGeneric)
6809 modifiers |= NSCommandKeyMask;
6812 modifiers = EV_MODIFIERS2 (modifiers);
6817 else if ([type isEqualToString: NSFilenamesPboardType])
6820 NSEnumerator *fenum;
6823 if (!(files = [pb propertyListForType: type]))
6826 fenum = [files objectEnumerator];
6827 while ( (file = [fenum nextObject]) )
6829 emacs_event->kind = DRAG_N_DROP_EVENT;
6830 XSETINT (emacs_event->x, x);
6831 XSETINT (emacs_event->y, y);
6832 ns_input_file = append2 (ns_input_file,
6833 build_string ([file UTF8String]));
6834 emacs_event->modifiers = modifiers;
6835 emacs_event->arg = list2 (Qfile, build_string ([file UTF8String]));
6836 EV_TRAILER (theEvent);
6840 else if ([type isEqualToString: NSURLPboardType])
6842 NSURL *url = [NSURL URLFromPasteboard: pb];
6843 if (url == nil) return NO;
6845 emacs_event->kind = DRAG_N_DROP_EVENT;
6846 XSETINT (emacs_event->x, x);
6847 XSETINT (emacs_event->y, y);
6848 emacs_event->modifiers = modifiers;
6849 emacs_event->arg = list2 (Qurl,
6850 build_string ([[url absoluteString]
6852 EV_TRAILER (theEvent);
6854 if ([url isFileURL] != NO)
6856 NSString *file = [url path];
6857 ns_input_file = append2 (ns_input_file,
6858 build_string ([file UTF8String]));
6862 else if ([type isEqualToString: NSStringPboardType]
6863 || [type isEqualToString: NSTabularTextPboardType])
6867 if (! (data = [pb stringForType: type]))
6870 emacs_event->kind = DRAG_N_DROP_EVENT;
6871 XSETINT (emacs_event->x, x);
6872 XSETINT (emacs_event->y, y);
6873 emacs_event->modifiers = modifiers;
6874 emacs_event->arg = list2 (Qnil, build_string ([data UTF8String]));
6875 EV_TRAILER (theEvent);
6880 error ("Invalid data type in dragging pasteboard");
6886 - (id) validRequestorForSendType: (NSString *)typeSent
6887 returnType: (NSString *)typeReturned
6889 NSTRACE (validRequestorForSendType);
6890 if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6891 && typeReturned == nil)
6893 if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6897 return [super validRequestorForSendType: typeSent
6898 returnType: typeReturned];
6902 /* The next two methods are part of NSServicesRequests informal protocol,
6903 supposedly called when a services menu item is chosen from this app.
6904 But this should not happen because we override the services menu with our
6905 own entries which call ns-perform-service.
6906 Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6907 So let's at least stub them out until further investigation can be done. */
6909 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6911 /* we could call ns_string_from_pasteboard(pboard) here but then it should
6912 be written into the buffer in place of the existing selection..
6913 ordinary service calls go through functions defined in ns-win.el */
6917 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6919 NSArray *typesDeclared;
6922 /* We only support NSStringPboardType */
6923 if ([types containsObject:NSStringPboardType] == NO) {
6927 val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6928 if (CONSP (val) && SYMBOLP (XCAR (val)))
6931 if (CONSP (val) && NILP (XCDR (val)))
6934 if (! STRINGP (val))
6937 typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6938 [pb declareTypes:typesDeclared owner:nil];
6939 ns_string_to_pasteboard (pb, val);
6944 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6945 (gives a miniaturized version of the window); currently we use the latter for
6946 frames whose active buffer doesn't correspond to any file
6947 (e.g., '*scratch*') */
6948 - setMiniwindowImage: (BOOL) setMini
6950 id image = [[self window] miniwindowImage];
6951 NSTRACE (setMiniwindowImage);
6953 /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6954 about "AppleDockIconEnabled" notwithstanding, however the set message
6955 below has its effect nonetheless. */
6956 if (image != emacsframe->output_data.ns->miniimage)
6958 if (image && [image isKindOfClass: [EmacsImage class]])
6960 [[self window] setMiniwindowImage:
6961 setMini ? emacsframe->output_data.ns->miniimage : nil];
6968 - (void) setRows: (int) r andColumns: (int) c
6974 @end /* EmacsView */
6978 /* ==========================================================================
6980 EmacsWindow implementation
6982 ========================================================================== */
6984 @implementation EmacsWindow
6986 #ifdef NS_IMPL_COCOA
6987 - (id)accessibilityAttributeValue:(NSString *)attribute
6989 Lisp_Object str = Qnil;
6990 struct frame *f = SELECTED_FRAME ();
6991 struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
6993 if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6994 return NSAccessibilityTextFieldRole;
6996 if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6997 && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6999 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7001 else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
7003 if (! NILP (BVAR (curbuf, mark_active)))
7004 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7008 ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
7009 ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
7010 ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
7012 if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
7013 str = make_uninit_multibyte_string (range, byte_range);
7015 str = make_uninit_string (range);
7016 /* To check: This returns emacs-utf-8, which is a superset of utf-8.
7017 Is this a problem? */
7018 memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
7025 if (CONSP (str) && SYMBOLP (XCAR (str)))
7028 if (CONSP (str) && NILP (XCDR (str)))
7033 const char *utfStr = SSDATA (str);
7034 NSString *nsStr = [NSString stringWithUTF8String: utfStr];
7039 return [super accessibilityAttributeValue:attribute];
7041 #endif /* NS_IMPL_COCOA */
7043 /* If we have multiple monitors, one above the other, we don't want to
7044 restrict the height to just one monitor. So we override this. */
7045 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
7047 /* When making the frame visible for the first time or if there is just
7048 one screen, we want to constrain. Other times not. */
7049 NSArray *screens = [NSScreen screens];
7050 NSUInteger nr_screens = [screens count], nr_eff_screens = 0, i;
7051 struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
7052 NSTRACE (constrainFrameRect);
7053 NSTRACE_RECT ("input", frameRect);
7055 if (ns_menu_bar_should_be_hidden ())
7058 if (nr_screens == 1)
7059 return [super constrainFrameRect:frameRect toScreen:screen];
7061 #ifdef NS_IMPL_COCOA
7062 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7063 // If separate spaces is on, it is like each screen is independent. There is
7064 // no spanning of frames across screens.
7065 if ([NSScreen screensHaveSeparateSpaces])
7066 return [super constrainFrameRect:frameRect toScreen:screen];
7070 for (i = 0; i < nr_screens; ++i)
7072 NSScreen *s = [screens objectAtIndex: i];
7073 NSRect scrrect = [s frame];
7074 NSRect intersect = NSIntersectionRect (frameRect, scrrect);
7076 if (intersect.size.width > 0 || intersect.size.height > 0)
7080 if (nr_eff_screens == 1)
7081 return [super constrainFrameRect:frameRect toScreen:screen];
7083 /* The default implementation does two things 1) ensure that the top
7084 of the rectangle is below the menu bar (or below the top of the
7085 screen) and 2) resizes windows larger than the screen. As we
7086 don't want the latter, a smaller rectangle is used. */
7087 #define FAKE_HEIGHT 64
7088 float old_top = frameRect.origin.y + frameRect.size.height;
7090 r.size.height = FAKE_HEIGHT;
7091 r.size.width = frameRect.size.width;
7092 r.origin.x = frameRect.origin.x;
7093 r.origin.y = old_top - FAKE_HEIGHT;
7095 NSTRACE_RECT ("input to super", r);
7097 r = [super constrainFrameRect:r toScreen:screen];
7099 NSTRACE_RECT ("output from super", r);
7101 float new_top = r.origin.y + FAKE_HEIGHT;
7102 if (new_top < old_top)
7104 frameRect.origin.y = new_top - frameRect.size.height;
7107 NSTRACE_RECT ("output", frameRect);
7113 @end /* EmacsWindow */
7116 @implementation EmacsFSWindow
7118 - (BOOL)canBecomeKeyWindow
7123 - (BOOL)canBecomeMainWindow
7130 /* ==========================================================================
7132 EmacsScroller implementation
7134 ========================================================================== */
7137 @implementation EmacsScroller
7139 /* for repeat button push */
7140 #define SCROLL_BAR_FIRST_DELAY 0.5
7141 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
7143 + (CGFloat) scrollerWidth
7145 /* TODO: if we want to allow variable widths, this is the place to do it,
7146 however neither GNUstep nor Cocoa support it very well */
7147 return [NSScroller scrollerWidth];
7151 - initFrame: (NSRect )r window: (Lisp_Object)nwin
7153 NSTRACE (EmacsScroller_initFrame);
7155 r.size.width = [EmacsScroller scrollerWidth];
7156 [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
7157 [self setContinuous: YES];
7158 [self setEnabled: YES];
7160 /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
7161 locked against the top and bottom edges, and right edge on OS X, where
7162 scrollers are on right. */
7163 #ifdef NS_IMPL_GNUSTEP
7164 [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
7166 [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
7169 window = XWINDOW (nwin);
7171 pixel_height = NSHeight (r);
7172 if (pixel_height == 0) pixel_height = 1;
7173 min_portion = 20 / pixel_height;
7175 frame = XFRAME (window->frame);
7176 if (FRAME_LIVE_P (frame))
7179 EmacsView *view = FRAME_NS_VIEW (frame);
7180 NSView *sview = [[view window] contentView];
7181 NSArray *subs = [sview subviews];
7183 /* disable optimization stopping redraw of other scrollbars */
7184 view->scrollbarsNeedingUpdate = 0;
7185 for (i =[subs count]-1; i >= 0; i--)
7186 if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
7187 view->scrollbarsNeedingUpdate++;
7188 [sview addSubview: self];
7191 /* [self setFrame: r]; */
7197 - (void)setFrame: (NSRect)newRect
7199 NSTRACE (EmacsScroller_setFrame);
7200 /* block_input (); */
7201 pixel_height = NSHeight (newRect);
7202 if (pixel_height == 0) pixel_height = 1;
7203 min_portion = 20 / pixel_height;
7204 [super setFrame: newRect];
7205 /* unblock_input (); */
7211 NSTRACE (EmacsScroller_dealloc);
7213 wset_vertical_scroll_bar (window, Qnil);
7238 bool ret = condemned;
7243 /* ensure other scrollbar updates after deletion */
7244 view = (EmacsView *)FRAME_NS_VIEW (frame);
7246 view->scrollbarsNeedingUpdate++;
7248 wset_vertical_scroll_bar (window, Qnil);
7250 [self removeFromSuperview];
7258 - (void)resetCursorRects
7260 NSRect visible = [self visibleRect];
7261 NSTRACE (resetCursorRects);
7263 if (!NSIsEmptyRect (visible))
7264 [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
7265 [[NSCursor arrowCursor] setOnMouseEntered: YES];
7269 - (int) checkSamePosition: (int) position portion: (int) portion
7272 return em_position ==position && em_portion ==portion && em_whole ==whole
7273 && portion != whole; /* needed for resize empty buf */
7277 - setPosition: (int)position portion: (int)portion whole: (int)whole
7279 NSTRACE (setPosition);
7281 em_position = position;
7282 em_portion = portion;
7285 if (portion >= whole)
7287 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
7288 [self setKnobProportion: 1.0];
7289 [self setDoubleValue: 1.0];
7291 [self setFloatValue: 0.0 knobProportion: 1.0];
7298 portion = max ((float)whole*min_portion/pixel_height, portion);
7299 pos = (float)position / (whole - portion);
7300 por = (CGFloat)portion/whole;
7301 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
7302 [self setKnobProportion: por];
7303 [self setDoubleValue: pos];
7305 [self setFloatValue: pos knobProportion: por];
7312 /* set up emacs_event */
7313 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
7319 emacs_event->part = last_hit_part;
7320 emacs_event->code = 0;
7321 emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
7322 XSETWINDOW (win, window);
7323 emacs_event->frame_or_window = win;
7324 emacs_event->timestamp = EV_TIMESTAMP (e);
7325 emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
7326 emacs_event->arg = Qnil;
7327 XSETINT (emacs_event->x, loc * pixel_height);
7328 XSETINT (emacs_event->y, pixel_height-20);
7332 n_emacs_events_pending++;
7333 kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
7336 hold_event (emacs_event);
7337 EVENT_INIT (*emacs_event);
7338 ns_send_appdefined (-1);
7342 /* called manually thru timer to implement repeated button action w/hold-down */
7343 - repeatScroll: (NSTimer *)scrollEntry
7345 NSEvent *e = [[self window] currentEvent];
7346 NSPoint p = [[self window] mouseLocationOutsideOfEventStream];
7347 BOOL inKnob = [self testPart: p] == NSScrollerKnob;
7349 /* clear timer if need be */
7350 if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
7352 [scroll_repeat_entry invalidate];
7353 [scroll_repeat_entry release];
7354 scroll_repeat_entry = nil;
7360 = [[NSTimer scheduledTimerWithTimeInterval:
7361 SCROLL_BAR_CONTINUOUS_DELAY
7363 selector: @selector (repeatScroll:)
7369 [self sendScrollEventAtLoc: 0 fromEvent: e];
7374 /* Asynchronous mouse tracking for scroller. This allows us to dispatch
7375 mouseDragged events without going into a modal loop. */
7376 - (void)mouseDown: (NSEvent *)e
7379 /* hitPart is only updated AFTER event is passed on */
7380 NSScrollerPart part = [self testPart: [e locationInWindow]];
7381 CGFloat inc = 0.0, loc, kloc, pos;
7384 NSTRACE (EmacsScroller_mouseDown);
7388 case NSScrollerDecrementPage:
7389 last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
7390 case NSScrollerIncrementPage:
7391 last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
7392 case NSScrollerDecrementLine:
7393 last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
7394 case NSScrollerIncrementLine:
7395 last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
7396 case NSScrollerKnob:
7397 last_hit_part = scroll_bar_handle; break;
7398 case NSScrollerKnobSlot: /* GNUstep-only */
7399 last_hit_part = scroll_bar_move_ratio; break;
7400 default: /* NSScrollerNoPart? */
7401 fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
7408 pos = 0; /* ignored */
7410 /* set a timer to repeat, as we can't let superclass do this modally */
7412 = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
7414 selector: @selector (repeatScroll:)
7421 /* handle, or on GNUstep possibly slot */
7422 NSEvent *fake_event;
7424 /* compute float loc in slot and mouse offset on knob */
7425 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7427 loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7433 else if (loc >= NSHeight (sr))
7435 loc = NSHeight (sr);
7443 kr = [self convertRect: [self rectForPart: NSScrollerKnob]
7445 kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
7447 last_mouse_offset = kloc;
7449 /* if knob, tell emacs a location offset by knob pos
7450 (to indicate top of handle) */
7451 if (part == NSScrollerKnob)
7452 pos = (loc - last_mouse_offset) / NSHeight (sr);
7454 /* else this is a slot click on GNUstep: go straight there */
7455 pos = loc / NSHeight (sr);
7457 /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
7458 fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
7459 location: [e locationInWindow]
7460 modifierFlags: [e modifierFlags]
7461 timestamp: [e timestamp]
7462 windowNumber: [e windowNumber]
7463 context: [e context]
7464 eventNumber: [e eventNumber]
7465 clickCount: [e clickCount]
7466 pressure: [e pressure]];
7467 [super mouseUp: fake_event];
7470 if (part != NSScrollerKnob)
7471 [self sendScrollEventAtLoc: pos fromEvent: e];
7475 /* Called as we manually track scroller drags, rather than superclass. */
7476 - (void)mouseDragged: (NSEvent *)e
7481 NSTRACE (EmacsScroller_mouseDragged);
7483 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7485 loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7491 else if (loc >= NSHeight (sr) + last_mouse_offset)
7493 loc = NSHeight (sr) + last_mouse_offset;
7496 pos = (loc - last_mouse_offset) / NSHeight (sr);
7497 [self sendScrollEventAtLoc: pos fromEvent: e];
7501 - (void)mouseUp: (NSEvent *)e
7503 if (scroll_repeat_entry)
7505 [scroll_repeat_entry invalidate];
7506 [scroll_repeat_entry release];
7507 scroll_repeat_entry = nil;
7513 /* treat scrollwheel events in the bar as though they were in the main window */
7514 - (void) scrollWheel: (NSEvent *)theEvent
7516 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
7517 [view mouseDown: theEvent];
7520 @end /* EmacsScroller */
7523 #ifdef NS_IMPL_GNUSTEP
7524 /* Dummy class to get rid of startup warnings. */
7525 @implementation EmacsDocument
7531 /* ==========================================================================
7533 Font-related functions; these used to be in nsfaces.m
7535 ========================================================================== */
7539 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
7541 struct font *font = XFONT_OBJECT (font_object);
7542 EmacsView *view = FRAME_NS_VIEW (f);
7545 fontset = fontset_from_font (font_object);
7546 FRAME_FONTSET (f) = fontset;
7548 if (FRAME_FONT (f) == font)
7549 /* This font is already set in frame F. There's nothing more to
7553 FRAME_FONT (f) = font;
7555 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
7556 FRAME_COLUMN_WIDTH (f) = font->average_width;
7557 FRAME_LINE_HEIGHT (f) = font->height;
7559 compute_fringe_widths (f, 1);
7561 /* Compute the scroll bar width in character columns. */
7562 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
7564 int wid = FRAME_COLUMN_WIDTH (f);
7565 FRAME_CONFIG_SCROLL_BAR_COLS (f)
7566 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
7570 int wid = FRAME_COLUMN_WIDTH (f);
7571 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
7574 /* Now make the frame display the given font. */
7575 if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
7576 x_set_window_size (f, 0, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
7577 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 1);
7583 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
7584 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
7588 ns_xlfd_to_fontname (const char *xlfd)
7589 /* --------------------------------------------------------------------------
7590 Convert an X font name (XLFD) to an NS font name.
7591 Only family is used.
7592 The string returned is temporarily allocated.
7593 -------------------------------------------------------------------------- */
7595 char *name = xmalloc (180);
7599 if (!strncmp (xlfd, "--", 2))
7600 sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7602 sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7604 /* stopgap for malformed XLFD input */
7605 if (strlen (name) == 0)
7606 strcpy (name, "Monaco");
7608 /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7609 also uppercase after '-' or ' ' */
7610 name[0] = c_toupper (name[0]);
7611 for (len =strlen (name), i =0; i<len; i++)
7617 name[i+1] = c_toupper (name[i+1]);
7619 else if (name[i] == '_')
7623 name[i+1] = c_toupper (name[i+1]);
7626 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name); */
7627 ret = [[NSString stringWithUTF8String: name] UTF8String];
7634 syms_of_nsterm (void)
7636 NSTRACE (syms_of_nsterm);
7638 ns_antialias_threshold = 10.0;
7640 /* from 23+ we need to tell emacs what modifiers there are.. */
7641 DEFSYM (Qmodifier_value, "modifier-value");
7642 DEFSYM (Qalt, "alt");
7643 DEFSYM (Qhyper, "hyper");
7644 DEFSYM (Qmeta, "meta");
7645 DEFSYM (Qsuper, "super");
7646 DEFSYM (Qcontrol, "control");
7647 DEFSYM (QUTF8_STRING, "UTF8_STRING");
7649 DEFSYM (Qfile, "file");
7650 DEFSYM (Qurl, "url");
7652 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7653 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7654 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7655 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7656 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7658 DEFVAR_LISP ("ns-input-file", ns_input_file,
7659 "The file specified in the last NS event.");
7660 ns_input_file =Qnil;
7662 DEFVAR_LISP ("ns-working-text", ns_working_text,
7663 "String for visualizing working composition sequence.");
7664 ns_working_text =Qnil;
7666 DEFVAR_LISP ("ns-input-font", ns_input_font,
7667 "The font specified in the last NS event.");
7668 ns_input_font =Qnil;
7670 DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7671 "The fontsize specified in the last NS event.");
7672 ns_input_fontsize =Qnil;
7674 DEFVAR_LISP ("ns-input-line", ns_input_line,
7675 "The line specified in the last NS event.");
7676 ns_input_line =Qnil;
7678 DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7679 "The service name specified in the last NS event.");
7680 ns_input_spi_name =Qnil;
7682 DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7683 "The service argument specified in the last NS event.");
7684 ns_input_spi_arg =Qnil;
7686 DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7687 "This variable describes the behavior of the alternate or option key.\n\
7688 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7689 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7690 at all, allowing it to be used at a lower level for accented character entry.");
7691 ns_alternate_modifier = Qmeta;
7693 DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7694 "This variable describes the behavior of the right alternate or option key.\n\
7695 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7696 Set to left means be the same key as `ns-alternate-modifier'.\n\
7697 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7698 at all, allowing it to be used at a lower level for accented character entry.");
7699 ns_right_alternate_modifier = Qleft;
7701 DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7702 "This variable describes the behavior of the command key.\n\
7703 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7704 ns_command_modifier = Qsuper;
7706 DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7707 "This variable describes the behavior of the right command key.\n\
7708 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7709 Set to left means be the same key as `ns-command-modifier'.\n\
7710 Set to none means that the command / option key is not interpreted by Emacs\n\
7711 at all, allowing it to be used at a lower level for accented character entry.");
7712 ns_right_command_modifier = Qleft;
7714 DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7715 "This variable describes the behavior of the control key.\n\
7716 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7717 ns_control_modifier = Qcontrol;
7719 DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7720 "This variable describes the behavior of the right control key.\n\
7721 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7722 Set to left means be the same key as `ns-control-modifier'.\n\
7723 Set to none means that the control / option key is not interpreted by Emacs\n\
7724 at all, allowing it to be used at a lower level for accented character entry.");
7725 ns_right_control_modifier = Qleft;
7727 DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7728 "This variable describes the behavior of the function key (on laptops).\n\
7729 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7730 Set to none means that the function key is not interpreted by Emacs at all,\n\
7731 allowing it to be used at a lower level for accented character entry.");
7732 ns_function_modifier = Qnone;
7734 DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7735 "Non-nil (the default) means to render text antialiased.");
7736 ns_antialias_text = Qt;
7738 DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7739 "Whether to confirm application quit using dialog.");
7740 ns_confirm_quit = Qnil;
7742 DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7743 doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7744 Only works on OSX 10.6 or later. */);
7745 ns_auto_hide_menu_bar = Qnil;
7747 DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
7748 doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
7749 Nil means use fullscreen the old (< 10.7) way. The old way works better with
7750 multiple monitors, but lacks tool bar. This variable is ignored on OSX < 10.7.
7751 Default is t for OSX >= 10.7, nil otherwise. */);
7752 #ifdef HAVE_NATIVE_FS
7753 ns_use_native_fullscreen = YES;
7755 ns_use_native_fullscreen = NO;
7757 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
7759 DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
7760 doc: /*Non-nil means to use sRGB colorspace on OSX >= 10.7.
7761 Note that this does not apply to images.
7762 This variable is ignored on OSX < 10.7 and GNUstep. */);
7763 ns_use_srgb_colorspace = YES;
7765 /* TODO: move to common code */
7766 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7767 doc: /* Which toolkit scroll bars Emacs uses, if any.
7768 A value of nil means Emacs doesn't use toolkit scroll bars.
7769 With the X Window system, the value is a symbol describing the
7770 X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
7771 With MS Windows or Nextstep, the value is t. */);
7772 Vx_toolkit_scroll_bars = Qt;
7774 DEFVAR_BOOL ("x-use-underline-position-properties",
7775 x_use_underline_position_properties,
7776 doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7777 A value of nil means ignore them. If you encounter fonts with bogus
7778 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7779 to 4.1, set this to nil. */);
7780 x_use_underline_position_properties = 0;
7782 DEFVAR_BOOL ("x-underline-at-descent-line",
7783 x_underline_at_descent_line,
7784 doc: /* Non-nil means to draw the underline at the same place as the descent line.
7785 A value of nil means to draw the underline according to the value of the
7786 variable `x-use-underline-position-properties', which is usually at the
7787 baseline level. The default value is nil. */);
7788 x_underline_at_descent_line = 0;
7790 /* Tell Emacs about this window system. */
7791 Fprovide (Qns, Qnil);
7793 DEFSYM (Qcocoa, "cocoa");
7794 DEFSYM (Qgnustep, "gnustep");
7797 #ifdef NS_IMPL_COCOA
7798 Fprovide (Qcocoa, Qnil);
7799 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
7803 Fprovide (Qgnustep, Qnil);