1 /* NeXT/Open/GNUstep / MacOSX communication module.
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2014 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
73 int term_trace_num = 0;
74 #define NSTRACE(x) fprintf (stderr, "%s:%d: [%d] " #x "\n", \
75 __FILE__, __LINE__, ++term_trace_num)
80 /* Detailed tracing. "S" means "size" and "LL" stands for "lower left". */
82 int term_trace_num = 0;
83 #define NSTRACE_SIZE(str,size) fprintf (stderr, \
85 " (S:%.0f x %.0f)\n", \
86 __FILE__, __LINE__, ++term_trace_num,\
89 #define NSTRACE_RECT(s,r) fprintf (stderr, \
91 " (LL:%.0f x %.0f -> S:%.0f x %.0f)\n", \
92 __FILE__, __LINE__, ++term_trace_num,\
98 #define NSTRACE_SIZE(str,size)
99 #define NSTRACE_RECT(s,r)
102 extern NSString *NSMenuDidBeginTrackingNotification;
104 /* ==========================================================================
106 NSColor, EmacsColor category.
108 ========================================================================== */
109 @implementation NSColor (EmacsColor)
110 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
111 blue:(CGFloat)blue alpha:(CGFloat)alpha
114 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
115 if (ns_use_srgb_colorspace)
116 return [NSColor colorWithSRGBRed: red
122 return [NSColor colorWithCalibratedRed: red
128 - (NSColor *)colorUsingDefaultColorSpace
131 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
132 if (ns_use_srgb_colorspace)
133 return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
136 return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
141 /* ==========================================================================
145 ========================================================================== */
147 /* Convert a symbol indexed with an NSxxx value to a value as defined
148 in keyboard.c (lispy_function_key). I hope this is a correct way
149 of doing things... */
150 static unsigned convert_ns_to_X_keysym[] =
152 NSHomeFunctionKey, 0x50,
153 NSLeftArrowFunctionKey, 0x51,
154 NSUpArrowFunctionKey, 0x52,
155 NSRightArrowFunctionKey, 0x53,
156 NSDownArrowFunctionKey, 0x54,
157 NSPageUpFunctionKey, 0x55,
158 NSPageDownFunctionKey, 0x56,
159 NSEndFunctionKey, 0x57,
160 NSBeginFunctionKey, 0x58,
161 NSSelectFunctionKey, 0x60,
162 NSPrintFunctionKey, 0x61,
163 NSClearLineFunctionKey, 0x0B,
164 NSExecuteFunctionKey, 0x62,
165 NSInsertFunctionKey, 0x63,
166 NSUndoFunctionKey, 0x65,
167 NSRedoFunctionKey, 0x66,
168 NSMenuFunctionKey, 0x67,
169 NSFindFunctionKey, 0x68,
170 NSHelpFunctionKey, 0x6A,
171 NSBreakFunctionKey, 0x6B,
173 NSF1FunctionKey, 0xBE,
174 NSF2FunctionKey, 0xBF,
175 NSF3FunctionKey, 0xC0,
176 NSF4FunctionKey, 0xC1,
177 NSF5FunctionKey, 0xC2,
178 NSF6FunctionKey, 0xC3,
179 NSF7FunctionKey, 0xC4,
180 NSF8FunctionKey, 0xC5,
181 NSF9FunctionKey, 0xC6,
182 NSF10FunctionKey, 0xC7,
183 NSF11FunctionKey, 0xC8,
184 NSF12FunctionKey, 0xC9,
185 NSF13FunctionKey, 0xCA,
186 NSF14FunctionKey, 0xCB,
187 NSF15FunctionKey, 0xCC,
188 NSF16FunctionKey, 0xCD,
189 NSF17FunctionKey, 0xCE,
190 NSF18FunctionKey, 0xCF,
191 NSF19FunctionKey, 0xD0,
192 NSF20FunctionKey, 0xD1,
193 NSF21FunctionKey, 0xD2,
194 NSF22FunctionKey, 0xD3,
195 NSF23FunctionKey, 0xD4,
196 NSF24FunctionKey, 0xD5,
198 NSBackspaceCharacter, 0x08, /* 8: Not on some KBs. */
199 NSDeleteCharacter, 0xFF, /* 127: Big 'delete' key upper right. */
200 NSDeleteFunctionKey, 0x9F, /* 63272: Del forw key off main array. */
202 NSTabCharacter, 0x09,
203 0x19, 0x09, /* left tab->regular since pass shift */
204 NSCarriageReturnCharacter, 0x0D,
205 NSNewlineCharacter, 0x0D,
206 NSEnterCharacter, 0x8D,
208 0x41|NSNumericPadKeyMask, 0xAE, /* KP_Decimal */
209 0x43|NSNumericPadKeyMask, 0xAA, /* KP_Multiply */
210 0x45|NSNumericPadKeyMask, 0xAB, /* KP_Add */
211 0x4B|NSNumericPadKeyMask, 0xAF, /* KP_Divide */
212 0x4E|NSNumericPadKeyMask, 0xAD, /* KP_Subtract */
213 0x51|NSNumericPadKeyMask, 0xBD, /* KP_Equal */
214 0x52|NSNumericPadKeyMask, 0xB0, /* KP_0 */
215 0x53|NSNumericPadKeyMask, 0xB1, /* KP_1 */
216 0x54|NSNumericPadKeyMask, 0xB2, /* KP_2 */
217 0x55|NSNumericPadKeyMask, 0xB3, /* KP_3 */
218 0x56|NSNumericPadKeyMask, 0xB4, /* KP_4 */
219 0x57|NSNumericPadKeyMask, 0xB5, /* KP_5 */
220 0x58|NSNumericPadKeyMask, 0xB6, /* KP_6 */
221 0x59|NSNumericPadKeyMask, 0xB7, /* KP_7 */
222 0x5B|NSNumericPadKeyMask, 0xB8, /* KP_8 */
223 0x5C|NSNumericPadKeyMask, 0xB9, /* KP_9 */
225 0x1B, 0x1B /* escape */
228 static Lisp_Object Qmodifier_value;
229 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper;
230 extern Lisp_Object Qcursor_color, Qcursor_type, Qns;
232 static Lisp_Object QUTF8_STRING;
233 static Lisp_Object Qcocoa, Qgnustep;
234 static Lisp_Object Qfile, Qurl;
236 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
237 the maximum font size to NOT antialias. On GNUstep there is currently
238 no way to control this behavior. */
239 float ns_antialias_threshold;
241 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
242 NSString *ns_app_name = @"Emacs"; /* default changed later */
244 /* Display variables */
245 struct ns_display_info *x_display_list; /* Chain of existing displays */
246 long context_menu_value = 0;
249 static struct frame *ns_updating_frame;
250 static NSView *focus_view = NULL;
251 static int ns_window_num = 0;
252 #ifdef NS_IMPL_GNUSTEP
255 static BOOL gsaved = NO;
256 static BOOL ns_fake_keydown = NO;
258 static BOOL ns_menu_bar_is_hidden = NO;
260 /*static int debug_lock = 0; */
263 static BOOL send_appdefined = YES;
264 #define NO_APPDEFINED_DATA (-8)
265 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
266 static NSTimer *timed_entry = 0;
267 static NSTimer *scroll_repeat_entry = nil;
268 static fd_set select_readfds, select_writefds;
269 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
270 static int select_nfds = 0, select_valid = 0;
271 static struct timespec select_timeout = { 0, 0 };
272 static int selfds[2] = { -1, -1 };
273 static pthread_mutex_t select_mutex;
274 static int apploopnr = 0;
275 static NSAutoreleasePool *outerpool;
276 static struct input_event *emacs_event = NULL;
277 static struct input_event *q_event_ptr = NULL;
278 static int n_emacs_events_pending = 0;
279 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
280 *ns_pending_service_args;
281 static BOOL ns_do_open_file = NO;
282 static BOOL ns_last_use_native_fullscreen;
284 /* Non-zero means that a HELP_EVENT has been generated since Emacs
287 static BOOL any_help_event_p = NO;
290 struct input_event *q;
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_init_events (struct input_event* ev)
416 hold_event (struct input_event *event)
418 if (hold_event_q.nr == hold_event_q.cap)
420 if (hold_event_q.cap == 0) hold_event_q.cap = 10;
421 else hold_event_q.cap *= 2;
423 xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
426 hold_event_q.q[hold_event_q.nr++] = *event;
427 /* Make sure ns_read_socket is called, i.e. we have input. */
429 send_appdefined = YES;
433 append2 (Lisp_Object list, Lisp_Object item)
434 /* --------------------------------------------------------------------------
435 Utility to append to a list
436 -------------------------------------------------------------------------- */
438 Lisp_Object array[2];
440 array[1] = list1 (item);
441 return Fnconc (2, &array[0]);
446 ns_etc_directory (void)
447 /* If running as a self-contained app bundle, return as a string the
448 filename of the etc directory, if present; else nil. */
450 NSBundle *bundle = [NSBundle mainBundle];
451 NSString *resourceDir = [bundle resourcePath];
452 NSString *resourcePath;
453 NSFileManager *fileManager = [NSFileManager defaultManager];
456 resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
457 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
459 if (isDir) return [resourcePath UTF8String];
467 /* If running as a self-contained app bundle, return as a path string
468 the filenames of the libexec and bin directories, ie libexec:bin.
469 Otherwise, return nil.
470 Normally, Emacs does not add its own bin/ directory to the PATH.
471 However, a self-contained NS build has a different layout, with
472 bin/ and libexec/ subdirectories in the directory that contains
474 We put libexec first, because init_callproc_1 uses the first
475 element to initialize exec-directory. An alternative would be
476 for init_callproc to check for invocation-directory/libexec.
479 NSBundle *bundle = [NSBundle mainBundle];
480 NSString *resourceDir = [bundle resourcePath];
481 NSString *binDir = [bundle bundlePath];
482 NSString *resourcePath, *resourcePaths;
484 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
485 NSFileManager *fileManager = [NSFileManager defaultManager];
487 NSEnumerator *pathEnum;
490 range = [resourceDir rangeOfString: @"Contents"];
491 if (range.location != NSNotFound)
493 binDir = [binDir stringByAppendingPathComponent: @"Contents"];
495 binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
499 paths = [binDir stringsByAppendingPaths:
500 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
501 pathEnum = [paths objectEnumerator];
504 while ((resourcePath = [pathEnum nextObject]))
506 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
509 if ([resourcePaths length] > 0)
511 = [resourcePaths stringByAppendingString: pathSeparator];
513 = [resourcePaths stringByAppendingString: resourcePath];
516 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
524 /* If running as a self-contained app bundle, return as a path string
525 the filenames of the site-lisp and lisp directories.
526 Ie, site-lisp:lisp. Otherwise, return nil. */
528 NSBundle *bundle = [NSBundle mainBundle];
529 NSString *resourceDir = [bundle resourcePath];
530 NSString *resourcePath, *resourcePaths;
531 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
532 NSFileManager *fileManager = [NSFileManager defaultManager];
534 NSArray *paths = [resourceDir stringsByAppendingPaths:
535 [NSArray arrayWithObjects:
536 @"site-lisp", @"lisp", nil]];
537 NSEnumerator *pathEnum = [paths objectEnumerator];
540 /* Hack to skip site-lisp. */
541 if (no_site_lisp) resourcePath = [pathEnum nextObject];
543 while ((resourcePath = [pathEnum nextObject]))
545 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
548 if ([resourcePaths length] > 0)
550 = [resourcePaths stringByAppendingString: pathSeparator];
552 = [resourcePaths stringByAppendingString: resourcePath];
555 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
561 ns_timeout (int usecs)
562 /* --------------------------------------------------------------------------
563 Blocking timer utility used by ns_ring_bell
564 -------------------------------------------------------------------------- */
566 struct timespec wakeup = timespec_add (current_timespec (),
567 make_timespec (0, usecs * 1000));
569 /* Keep waiting until past the time wakeup. */
572 struct timespec timeout, now = current_timespec ();
573 if (timespec_cmp (wakeup, now) <= 0)
575 timeout = timespec_sub (wakeup, now);
577 /* Try to wait that long--but we might wake up sooner. */
578 pselect (0, NULL, NULL, NULL, &timeout, NULL);
584 ns_release_object (void *obj)
585 /* --------------------------------------------------------------------------
586 Release an object (callable from C)
587 -------------------------------------------------------------------------- */
594 ns_retain_object (void *obj)
595 /* --------------------------------------------------------------------------
596 Retain an object (callable from C)
597 -------------------------------------------------------------------------- */
604 ns_alloc_autorelease_pool (void)
605 /* --------------------------------------------------------------------------
606 Allocate a pool for temporary objects (callable from C)
607 -------------------------------------------------------------------------- */
609 return [[NSAutoreleasePool alloc] init];
614 ns_release_autorelease_pool (void *pool)
615 /* --------------------------------------------------------------------------
616 Free a pool and temporary objects it refers to (callable from C)
617 -------------------------------------------------------------------------- */
619 ns_release_object (pool);
624 /* ==========================================================================
626 Focus (clipping) and screen update
628 ========================================================================== */
631 // Window constraining
632 // -------------------
634 // To ensure that the windows are not placed under the menu bar, they
635 // are typically moved by the call-back constrainFrameRect. However,
636 // by overriding it, it's possible to inhibit this, leaving the window
637 // in it's original position.
639 // It's possible to hide the menu bar. However, technically, it's only
640 // possible to hide it when the application is active. To ensure that
641 // this work properly, the menu bar and window constraining are
642 // deferred until the application becomes active.
644 // Even though it's not possible to manually move a window above the
645 // top of the screen, it is allowed if it's done programmatically,
646 // when the menu is hidden. This allows the editable area to cover the
647 // full screen height.
652 // Use the following extra files:
655 // ;; Hide menu and place frame slightly above the top of the screen.
656 // (setq ns-auto-hide-menu-bar t)
657 // (set-frame-position (selected-frame) 0 -20)
661 // emacs -Q -l init.el
663 // Result: No menu bar, and the title bar should be above the screen.
669 // Result: Menu bar visible, frame placed immediately below the menu.
673 ns_constrain_all_frames (void)
675 Lisp_Object tail, frame;
677 FOR_EACH_FRAME (tail, frame)
679 struct frame *f = XFRAME (frame);
682 NSView *view = FRAME_NS_VIEW (f);
683 /* This no-op will trigger the default window placing
684 * constraint system. */
685 [[view window] setFrameOrigin:[[view window] frame].origin];
691 /* True, if the menu bar should be hidden. */
694 ns_menu_bar_should_be_hidden (void)
696 return !NILP (ns_auto_hide_menu_bar)
697 && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
701 /* Show or hide the menu bar, based on user setting. */
704 ns_update_auto_hide_menu_bar (void)
709 NSTRACE (ns_update_auto_hide_menu_bar);
711 if (NSApp != nil && [NSApp isActive])
713 // Note, "setPresentationOptions" triggers an error unless the
714 // application is active.
715 BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
717 if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
719 NSApplicationPresentationOptions options
720 = NSApplicationPresentationDefault;
722 if (menu_bar_should_be_hidden)
723 options |= NSApplicationPresentationAutoHideMenuBar
724 | NSApplicationPresentationAutoHideDock;
726 [NSApp setPresentationOptions: options];
728 ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
730 if (!ns_menu_bar_is_hidden)
732 ns_constrain_all_frames ();
743 ns_update_begin (struct frame *f)
744 /* --------------------------------------------------------------------------
745 Prepare for a grouped sequence of drawing calls
746 external (RIF) call; whole frame, called before update_window_begin
747 -------------------------------------------------------------------------- */
749 EmacsView *view = FRAME_NS_VIEW (f);
750 NSTRACE (ns_update_begin);
752 ns_update_auto_hide_menu_bar ();
755 if ([view isFullscreen] && [view fsIsNative])
757 // Fix reappearing tool bar in fullscreen for OSX 10.7
758 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
759 NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
760 if (! tbar_visible != ! [toolbar isVisible])
761 [toolbar setVisible: tbar_visible];
765 ns_updating_frame = f;
768 /* drawRect may have been called for say the minibuffer, and then clip path
769 is for the minibuffer. But the display engine may draw more because
770 we have set the frame as garbaged. So reset clip path to the whole
775 NSRect r = [view frame];
776 NSRect cr = [[view window] frame];
777 /* If a large frame size is set, r may be larger than the window frame
778 before constrained. In that case don't change the clip path, as we
779 will clear in to the tool bar and title bar. */
781 + FRAME_NS_TITLEBAR_HEIGHT (f)
782 + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
784 bp = [[NSBezierPath bezierPathWithRect: r] retain];
791 #ifdef NS_IMPL_GNUSTEP
792 uRect = NSMakeRect (0, 0, 0, 0);
798 ns_update_window_begin (struct window *w)
799 /* --------------------------------------------------------------------------
800 Prepare for a grouped sequence of drawing calls
801 external (RIF) call; for one window, called after update_begin
802 -------------------------------------------------------------------------- */
804 struct frame *f = XFRAME (WINDOW_FRAME (w));
805 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
807 NSTRACE (ns_update_window_begin);
808 w->output_cursor = w->cursor;
812 if (f == hlinfo->mouse_face_mouse_frame)
814 /* Don't do highlighting for mouse motion during the update. */
815 hlinfo->mouse_face_defer = 1;
817 /* If the frame needs to be redrawn,
818 simply forget about any prior mouse highlighting. */
819 if (FRAME_GARBAGED_P (f))
820 hlinfo->mouse_face_window = Qnil;
822 /* (further code for mouse faces ifdef'd out in other terms elided) */
830 ns_update_window_end (struct window *w, bool cursor_on_p,
831 bool mouse_face_overwritten_p)
832 /* --------------------------------------------------------------------------
833 Finished a grouped sequence of drawing calls
834 external (RIF) call; for one window called before update_end
835 -------------------------------------------------------------------------- */
837 /* note: this fn is nearly identical in all terms */
838 if (!w->pseudo_window_p)
843 display_and_set_cursor (w, 1,
844 w->output_cursor.hpos, w->output_cursor.vpos,
845 w->output_cursor.x, w->output_cursor.y);
847 if (draw_window_fringes (w, 1))
849 if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
850 x_draw_right_divider (w);
852 x_draw_vertical_border (w);
858 /* If a row with mouse-face was overwritten, arrange for
859 frame_up_to_date to redisplay the mouse highlight. */
860 if (mouse_face_overwritten_p)
861 reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
863 NSTRACE (update_window_end);
868 ns_update_end (struct frame *f)
869 /* --------------------------------------------------------------------------
870 Finished a grouped sequence of drawing calls
871 external (RIF) call; for whole frame, called after update_window_end
872 -------------------------------------------------------------------------- */
874 EmacsView *view = FRAME_NS_VIEW (f);
876 /* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
877 MOUSE_HL_INFO (f)->mouse_face_defer = 0;
882 [[view window] flushWindow];
885 ns_updating_frame = NULL;
886 NSTRACE (ns_update_end);
890 ns_focus (struct frame *f, NSRect *r, int n)
891 /* --------------------------------------------------------------------------
892 Internal: Focus on given frame. During small local updates this is used to
893 draw, however during large updates, ns_update_begin and ns_update_end are
894 called to wrap the whole thing, in which case these calls are stubbed out.
895 Except, on GNUstep, we accumulate the rectangle being drawn into, because
896 the back end won't do this automatically, and will just end up flushing
898 -------------------------------------------------------------------------- */
900 // NSTRACE (ns_focus);
902 fprintf (stderr, "focus: %d", c++);
903 if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
904 fprintf (stderr, "\n"); */
906 if (f != ns_updating_frame)
908 NSView *view = FRAME_NS_VIEW (f);
909 if (view != focus_view)
911 if (focus_view != NULL)
913 [focus_view unlockFocus];
914 [[focus_view window] flushWindow];
921 /*if (view) debug_lock++; */
928 [[NSGraphicsContext currentContext] saveGraphicsState];
930 NSRectClipList (r, 2);
939 ns_unfocus (struct frame *f)
940 /* --------------------------------------------------------------------------
941 Internal: Remove focus on given frame
942 -------------------------------------------------------------------------- */
944 // NSTRACE (ns_unfocus);
948 [[NSGraphicsContext currentContext] restoreGraphicsState];
952 if (f != ns_updating_frame)
954 if (focus_view != NULL)
956 [focus_view unlockFocus];
957 [[focus_view window] flushWindow];
966 ns_clip_to_row (struct window *w, struct glyph_row *row,
967 enum glyph_row_area area, BOOL gc)
968 /* --------------------------------------------------------------------------
969 Internal (but parallels other terms): Focus drawing on given row
970 -------------------------------------------------------------------------- */
972 struct frame *f = XFRAME (WINDOW_FRAME (w));
974 int window_x, window_y, window_width;
976 window_box (w, area, &window_x, &window_y, &window_width, 0);
978 clip_rect.origin.x = window_x;
979 clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
980 clip_rect.origin.y = max (clip_rect.origin.y, window_y);
981 clip_rect.size.width = window_width;
982 clip_rect.size.height = row->visible_height;
984 ns_focus (f, &clip_rect, 1);
989 ns_ring_bell (struct frame *f)
990 /* --------------------------------------------------------------------------
992 -------------------------------------------------------------------------- */
994 NSTRACE (ns_ring_bell);
997 NSAutoreleasePool *pool;
998 struct frame *frame = SELECTED_FRAME ();
1002 pool = [[NSAutoreleasePool alloc] init];
1004 view = FRAME_NS_VIEW (frame);
1008 NSPoint dim = NSMakePoint (128, 128);
1011 r.origin.x += (r.size.width - dim.x) / 2;
1012 r.origin.y += (r.size.height - dim.y) / 2;
1013 r.size.width = dim.x;
1014 r.size.height = dim.y;
1015 surr = NSInsetRect (r, -2, -2);
1016 ns_focus (frame, &surr, 1);
1017 [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
1018 [ns_lookup_indexed_color (NS_FACE_FOREGROUND
1019 (FRAME_DEFAULT_FACE (frame)), frame) set];
1021 [[view window] flushWindow];
1022 ns_timeout (150000);
1023 [[view window] restoreCachedImage];
1024 [[view window] flushWindow];
1036 /* ==========================================================================
1038 Frame / window manager related functions
1040 ========================================================================== */
1044 ns_raise_frame (struct frame *f)
1045 /* --------------------------------------------------------------------------
1046 Bring window to foreground and make it active
1047 -------------------------------------------------------------------------- */
1050 check_window_system (f);
1051 view = FRAME_NS_VIEW (f);
1053 if (FRAME_VISIBLE_P (f))
1054 [[view window] makeKeyAndOrderFront: NSApp];
1060 ns_lower_frame (struct frame *f)
1061 /* --------------------------------------------------------------------------
1063 -------------------------------------------------------------------------- */
1066 check_window_system (f);
1067 view = FRAME_NS_VIEW (f);
1069 [[view window] orderBack: NSApp];
1075 ns_frame_raise_lower (struct frame *f, int raise)
1076 /* --------------------------------------------------------------------------
1078 -------------------------------------------------------------------------- */
1080 NSTRACE (ns_frame_raise_lower);
1090 ns_frame_rehighlight (struct frame *frame)
1091 /* --------------------------------------------------------------------------
1092 External (hook): called on things like window switching within frame
1093 -------------------------------------------------------------------------- */
1095 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1096 struct frame *old_highlight = dpyinfo->x_highlight_frame;
1098 NSTRACE (ns_frame_rehighlight);
1099 if (dpyinfo->x_focus_frame)
1101 dpyinfo->x_highlight_frame
1102 = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1103 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1104 : dpyinfo->x_focus_frame);
1105 if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1107 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1108 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1112 dpyinfo->x_highlight_frame = 0;
1114 if (dpyinfo->x_highlight_frame &&
1115 dpyinfo->x_highlight_frame != old_highlight)
1119 x_update_cursor (old_highlight, 1);
1120 x_set_frame_alpha (old_highlight);
1122 if (dpyinfo->x_highlight_frame)
1124 x_update_cursor (dpyinfo->x_highlight_frame, 1);
1125 x_set_frame_alpha (dpyinfo->x_highlight_frame);
1132 x_make_frame_visible (struct frame *f)
1133 /* --------------------------------------------------------------------------
1134 External: Show the window (X11 semantics)
1135 -------------------------------------------------------------------------- */
1137 NSTRACE (x_make_frame_visible);
1138 /* XXX: at some points in past this was not needed, as the only place that
1139 called this (frame.c:Fraise_frame ()) also called raise_lower;
1140 if this ends up the case again, comment this out again. */
1141 if (!FRAME_VISIBLE_P (f))
1143 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1145 SET_FRAME_VISIBLE (f, 1);
1148 /* Making a new frame from a fullscreen frame will make the new frame
1149 fullscreen also. So skip handleFS as this will print an error. */
1150 if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1151 && [view isFullscreen])
1154 if (f->want_fullscreen != FULLSCREEN_NONE)
1165 x_make_frame_invisible (struct frame *f)
1166 /* --------------------------------------------------------------------------
1167 External: Hide the window (X11 semantics)
1168 -------------------------------------------------------------------------- */
1171 NSTRACE (x_make_frame_invisible);
1172 check_window_system (f);
1173 view = FRAME_NS_VIEW (f);
1174 [[view window] orderOut: NSApp];
1175 SET_FRAME_VISIBLE (f, 0);
1176 SET_FRAME_ICONIFIED (f, 0);
1181 x_iconify_frame (struct frame *f)
1182 /* --------------------------------------------------------------------------
1183 External: Iconify window
1184 -------------------------------------------------------------------------- */
1187 struct ns_display_info *dpyinfo;
1189 NSTRACE (x_iconify_frame);
1190 check_window_system (f);
1191 view = FRAME_NS_VIEW (f);
1192 dpyinfo = FRAME_DISPLAY_INFO (f);
1194 if (dpyinfo->x_highlight_frame == f)
1195 dpyinfo->x_highlight_frame = 0;
1197 if ([[view window] windowNumber] <= 0)
1199 /* the window is still deferred. Make it very small, bring it
1200 on screen and order it out. */
1201 NSRect s = { { 100, 100}, {0, 0} };
1203 t = [[view window] frame];
1204 [[view window] setFrame: s display: NO];
1205 [[view window] orderBack: NSApp];
1206 [[view window] orderOut: NSApp];
1207 [[view window] setFrame: t display: NO];
1209 [[view window] miniaturize: NSApp];
1212 /* Free X resources of frame F. */
1215 x_free_frame_resources (struct frame *f)
1218 struct ns_display_info *dpyinfo;
1219 Mouse_HLInfo *hlinfo;
1221 NSTRACE (x_free_frame_resources);
1222 check_window_system (f);
1223 view = FRAME_NS_VIEW (f);
1224 dpyinfo = FRAME_DISPLAY_INFO (f);
1225 hlinfo = MOUSE_HL_INFO (f);
1227 [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1231 free_frame_menubar (f);
1232 free_frame_faces (f);
1234 if (f == dpyinfo->x_focus_frame)
1235 dpyinfo->x_focus_frame = 0;
1236 if (f == dpyinfo->x_highlight_frame)
1237 dpyinfo->x_highlight_frame = 0;
1238 if (f == hlinfo->mouse_face_mouse_frame)
1239 reset_mouse_highlight (hlinfo);
1241 if (f->output_data.ns->miniimage != nil)
1242 [f->output_data.ns->miniimage release];
1244 [[view window] close];
1247 xfree (f->output_data.ns);
1253 x_destroy_window (struct frame *f)
1254 /* --------------------------------------------------------------------------
1255 External: Delete the window
1256 -------------------------------------------------------------------------- */
1258 NSTRACE (x_destroy_window);
1259 check_window_system (f);
1260 x_free_frame_resources (f);
1266 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1267 /* --------------------------------------------------------------------------
1268 External: Position the window
1269 -------------------------------------------------------------------------- */
1271 NSView *view = FRAME_NS_VIEW (f);
1272 NSArray *screens = [NSScreen screens];
1273 NSScreen *fscreen = [screens objectAtIndex: 0];
1274 NSScreen *screen = [[view window] screen];
1276 NSTRACE (x_set_offset);
1283 if (view != nil && screen && fscreen)
1285 f->left_pos = f->size_hint_flags & XNegative
1286 ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1288 /* We use visibleFrame here to take menu bar into account.
1289 Ideally we should also adjust left/top with visibleFrame.origin. */
1291 f->top_pos = f->size_hint_flags & YNegative
1292 ? ([screen visibleFrame].size.height + f->top_pos
1293 - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1294 - FRAME_TOOLBAR_HEIGHT (f))
1296 #ifdef NS_IMPL_GNUSTEP
1297 if (f->left_pos < 100)
1298 f->left_pos = 100; /* don't overlap menu */
1300 /* Constrain the setFrameTopLeftPoint so we don't move behind the
1302 [[view window] setFrameTopLeftPoint:
1303 NSMakePoint (SCREENMAXBOUND (f->left_pos),
1304 SCREENMAXBOUND ([fscreen frame].size.height
1305 - NS_TOP_POS (f)))];
1306 f->size_hint_flags &= ~(XNegative|YNegative);
1314 x_set_window_size (struct frame *f,
1319 /* --------------------------------------------------------------------------
1320 Adjust window pixel size based on given character grid size
1321 Impl is a bit more complex than other terms, need to do some
1323 -------------------------------------------------------------------------- */
1325 EmacsView *view = FRAME_NS_VIEW (f);
1326 NSWindow *window = [view window];
1327 NSRect wr = [window frame];
1328 int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1329 int pixelwidth, pixelheight;
1332 NSTRACE (x_set_window_size);
1337 /*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));*/
1343 pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1344 pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1345 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
1346 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
1350 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width);
1351 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1356 /* If we have a toolbar, take its height into account. */
1357 if (tb && ! [view isFullscreen])
1359 /* NOTE: previously this would generate wrong result if toolbar not
1360 yet displayed and fixing toolbar_height=32 helped, but
1361 now (200903) seems no longer needed */
1362 FRAME_TOOLBAR_HEIGHT (f) =
1363 NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1364 - FRAME_NS_TITLEBAR_HEIGHT (f);
1365 #ifdef NS_IMPL_GNUSTEP
1366 FRAME_TOOLBAR_HEIGHT (f) -= 3;
1370 FRAME_TOOLBAR_HEIGHT (f) = 0;
1372 wr.size.width = pixelwidth + f->border_width;
1373 wr.size.height = pixelheight;
1374 if (! [view isFullscreen])
1375 wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1376 + FRAME_TOOLBAR_HEIGHT (f);
1378 /* Do not try to constrain to this screen. We may have multiple
1379 screens, and want Emacs to span those. Constraining to screen
1380 prevents that, and that is not nice to the user. */
1381 if (f->output_data.ns->zooming)
1382 f->output_data.ns->zooming = 0;
1384 wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1386 [view setRows: rows andColumns: cols];
1387 [window setFrame: wr display: YES];
1389 /* This is a trick to compensate for Emacs' managing the scrollbar area
1390 as a fixed number of standard character columns. Instead of leaving
1391 blank space for the extra, we chopped it off above. Now for
1392 left-hand scrollbars, we shift all rendering to the left by the
1393 difference between the real width and Emacs' imagined one. For
1394 right-hand bars, don't worry about it since the extra is never used.
1395 (Obviously doesn't work for vertically split windows tho..) */
1397 NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1398 ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1399 - NS_SCROLL_BAR_WIDTH (f), 0)
1400 : NSMakePoint (0, 0);
1401 [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1402 [view setBoundsOrigin: origin];
1405 change_frame_size (f, width, height, 0, 1, 0, pixelwise);
1406 /* SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1408 mark_window_cursors_off (XWINDOW (f->root_window));
1409 cancel_mouse_face (f);
1413 do_pending_window_change (0);
1418 ns_fullscreen_hook (struct frame *f)
1420 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1422 if (!FRAME_VISIBLE_P (f))
1425 if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1427 /* Old style fs don't initiate correctly if created from
1428 init/default-frame alist, so use a timer (not nice...).
1430 [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1431 selector: @selector (handleFS)
1432 userInfo: nil repeats: NO];
1441 /* ==========================================================================
1445 ========================================================================== */
1449 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1451 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1452 if (idx < 1 || idx >= color_table->avail)
1454 return color_table->colors[idx];
1459 ns_index_color (NSColor *color, struct frame *f)
1461 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1465 if (!color_table->colors)
1467 color_table->size = NS_COLOR_CAPACITY;
1468 color_table->avail = 1; /* skip idx=0 as marker */
1469 color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1470 color_table->colors[0] = nil;
1471 color_table->empty_indices = [[NSMutableSet alloc] init];
1474 /* Do we already have this color? */
1475 for (i = 1; i < color_table->avail; i++)
1476 if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1479 if ([color_table->empty_indices count] > 0)
1481 NSNumber *index = [color_table->empty_indices anyObject];
1482 [color_table->empty_indices removeObject: index];
1483 idx = [index unsignedLongValue];
1487 if (color_table->avail == color_table->size)
1488 color_table->colors =
1489 xpalloc (color_table->colors, &color_table->size, 1,
1490 min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1491 idx = color_table->avail++;
1494 color_table->colors[idx] = color;
1496 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1502 ns_free_indexed_color (unsigned long idx, struct frame *f)
1504 struct ns_color_table *color_table;
1511 color_table = FRAME_DISPLAY_INFO (f)->color_table;
1513 if (idx <= 0 || idx >= color_table->size) {
1514 message1 ("ns_free_indexed_color: Color index out of range.\n");
1518 index = [NSNumber numberWithUnsignedInt: idx];
1519 if ([color_table->empty_indices containsObject: index]) {
1520 message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1524 color = color_table->colors[idx];
1526 color_table->colors[idx] = nil;
1527 [color_table->empty_indices addObject: index];
1528 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1533 ns_get_color (const char *name, NSColor **col)
1534 /* --------------------------------------------------------------------------
1536 -------------------------------------------------------------------------- */
1537 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1538 X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1539 See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1542 static char hex[20];
1544 float r = -1.0, g, b;
1545 NSString *nsname = [NSString stringWithUTF8String: name];
1547 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1550 if ([nsname isEqualToString: @"ns_selection_bg_color"])
1552 #ifdef NS_IMPL_COCOA
1553 NSString *defname = [[NSUserDefaults standardUserDefaults]
1554 stringForKey: @"AppleHighlightColor"];
1559 if ((new = [NSColor selectedTextBackgroundColor]) != nil)
1561 *col = [new colorUsingDefaultColorSpace];
1566 nsname = NS_SELECTION_BG_COLOR_DEFAULT;
1568 name = [nsname UTF8String];
1570 else if ([nsname isEqualToString: @"ns_selection_fg_color"])
1572 /* NOTE: OSX applications normally don't set foreground selection, but
1573 text may be unreadable if we don't.
1575 if ((new = [NSColor selectedTextColor]) != nil)
1577 *col = [new colorUsingDefaultColorSpace];
1582 nsname = NS_SELECTION_FG_COLOR_DEFAULT;
1583 name = [nsname UTF8String];
1586 /* First, check for some sort of numeric specification. */
1589 if (name[0] == '0' || name[0] == '1' || name[0] == '.') /* RGB decimal */
1591 NSScanner *scanner = [NSScanner scannerWithString: nsname];
1592 [scanner scanFloat: &r];
1593 [scanner scanFloat: &g];
1594 [scanner scanFloat: &b];
1596 else if (!strncmp(name, "rgb:", 4)) /* A newer X11 format -- rgb:r/g/b */
1597 scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1598 else if (name[0] == '#') /* An old X11 format; convert to newer */
1600 int len = (strlen(name) - 1);
1601 int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1603 scaling = strlen(name+start) / 3;
1604 for (i = 0; i < 3; i++)
1605 sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1606 name + start + i * scaling);
1607 hex[3 * (scaling + 1) - 1] = '\0';
1613 float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1614 if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1624 *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
1629 /* Otherwise, color is expected to be from a list */
1631 NSEnumerator *lenum, *cenum;
1635 #ifdef NS_IMPL_GNUSTEP
1636 /* XXX: who is wrong, the requestor or the implementation? */
1637 if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1639 nsname = @"highlightColor";
1642 lenum = [[NSColorList availableColorLists] objectEnumerator];
1643 while ( (clist = [lenum nextObject]) && new == nil)
1645 cenum = [[clist allKeys] objectEnumerator];
1646 while ( (name = [cenum nextObject]) && new == nil )
1648 if ([name compare: nsname
1649 options: NSCaseInsensitiveSearch] == NSOrderedSame )
1650 new = [clist colorWithKey: name];
1656 *col = [new colorUsingDefaultColorSpace];
1663 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1664 /* --------------------------------------------------------------------------
1665 Convert a Lisp string object to a NS color
1666 -------------------------------------------------------------------------- */
1668 NSTRACE (ns_lisp_to_color);
1669 if (STRINGP (color))
1670 return ns_get_color (SSDATA (color), col);
1671 else if (SYMBOLP (color))
1672 return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1678 ns_color_to_lisp (NSColor *col)
1679 /* --------------------------------------------------------------------------
1680 Convert a color to a lisp string with the RGB equivalent
1681 -------------------------------------------------------------------------- */
1683 EmacsCGFloat red, green, blue, alpha, gray;
1686 NSTRACE (ns_color_to_lisp);
1689 if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1691 if ((str =[[col colorNameComponent] UTF8String]))
1694 return build_string ((char *)str);
1697 [[col colorUsingDefaultColorSpace]
1698 getRed: &red green: &green blue: &blue alpha: &alpha];
1699 if (red == green && red == blue)
1701 [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1702 getWhite: &gray alpha: &alpha];
1703 snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1704 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1706 return build_string (buf);
1709 snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1710 lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1713 return build_string (buf);
1718 ns_query_color(void *col, XColor *color_def, int setPixel)
1719 /* --------------------------------------------------------------------------
1720 Get ARGB values out of NSColor col and put them into color_def.
1721 If setPixel, set the pixel to a concatenated version.
1722 and set color_def pixel to the resulting index.
1723 -------------------------------------------------------------------------- */
1725 EmacsCGFloat r, g, b, a;
1727 [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1728 color_def->red = r * 65535;
1729 color_def->green = g * 65535;
1730 color_def->blue = b * 65535;
1732 if (setPixel == YES)
1734 = ARGB_TO_ULONG((int)(a*255),
1735 (int)(r*255), (int)(g*255), (int)(b*255));
1740 ns_defined_color (struct frame *f,
1745 /* --------------------------------------------------------------------------
1746 Return true if named color found, and set color_def rgb accordingly.
1747 If makeIndex and alloc are nonzero put the color in the color_table,
1748 and set color_def pixel to the resulting index.
1749 If makeIndex is zero, set color_def pixel to ARGB.
1750 Return false if not found
1751 -------------------------------------------------------------------------- */
1754 NSTRACE (ns_defined_color);
1757 if (ns_get_color (name, &col) != 0) /* Color not found */
1762 if (makeIndex && alloc)
1763 color_def->pixel = ns_index_color (col, f);
1764 ns_query_color (col, color_def, !makeIndex);
1771 x_set_frame_alpha (struct frame *f)
1772 /* --------------------------------------------------------------------------
1773 change the entire-frame transparency
1774 -------------------------------------------------------------------------- */
1776 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1778 double alpha_min = 1.0;
1780 if (dpyinfo->x_highlight_frame == f)
1781 alpha = f->alpha[0];
1783 alpha = f->alpha[1];
1785 if (FLOATP (Vframe_alpha_lower_limit))
1786 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1787 else if (INTEGERP (Vframe_alpha_lower_limit))
1788 alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1792 else if (1.0 < alpha)
1794 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1797 #ifdef NS_IMPL_COCOA
1799 EmacsView *view = FRAME_NS_VIEW (f);
1800 [[view window] setAlphaValue: alpha];
1806 /* ==========================================================================
1810 ========================================================================== */
1814 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1815 /* --------------------------------------------------------------------------
1816 Programmatically reposition mouse pointer in pixel coordinates
1817 -------------------------------------------------------------------------- */
1819 NSTRACE (frame_set_mouse_pixel_position);
1822 /* FIXME: this does not work, and what about GNUstep? */
1823 #ifdef NS_IMPL_COCOA
1824 [FRAME_NS_VIEW (f) lockFocus];
1825 PSsetmouse ((float)pix_x, (float)pix_y);
1826 [FRAME_NS_VIEW (f) unlockFocus];
1832 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
1833 /* ------------------------------------------------------------------------
1834 Called by EmacsView on mouseMovement events. Passes on
1835 to emacs mainstream code if we moved off of a rect of interest
1836 known as last_mouse_glyph.
1837 ------------------------------------------------------------------------ */
1839 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1842 // NSTRACE (note_mouse_movement);
1844 dpyinfo->last_mouse_motion_frame = frame;
1845 r = &dpyinfo->last_mouse_glyph;
1847 /* Note, this doesn't get called for enter/leave, since we don't have a
1848 position. Those are taken care of in the corresponding NSView methods. */
1850 /* has movement gone beyond last rect we were tracking? */
1851 if (x < r->origin.x || x >= r->origin.x + r->size.width
1852 || y < r->origin.y || y >= r->origin.y + r->size.height)
1854 ns_update_begin (frame);
1855 frame->mouse_moved = 1;
1856 note_mouse_highlight (frame, x, y);
1857 remember_mouse_glyph (frame, x, y, r);
1858 ns_update_end (frame);
1867 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1868 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1870 /* --------------------------------------------------------------------------
1871 External (hook): inform emacs about mouse position and hit parts.
1872 If a scrollbar is being dragged, set bar_window, part, x, y, time.
1873 x & y should be position in the scrollbar (the whole bar, not the handle)
1874 and length of scrollbar respectively
1875 -------------------------------------------------------------------------- */
1879 Lisp_Object frame, tail;
1881 struct ns_display_info *dpyinfo;
1883 NSTRACE (ns_mouse_position);
1887 fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1891 dpyinfo = FRAME_DISPLAY_INFO (*fp);
1895 if (dpyinfo->last_mouse_scroll_bar != nil && insist == 0)
1897 /* TODO: we do not use this path at the moment because drag events will
1898 go directly to the EmacsScroller. Leaving code in for now. */
1899 [dpyinfo->last_mouse_scroll_bar
1900 getMouseMotionPart: (int *)part window: bar_window x: x y: y];
1902 *time = dpyinfo->last_mouse_movement_time;
1903 dpyinfo->last_mouse_scroll_bar = nil;
1907 /* Clear the mouse-moved flag for every frame on this display. */
1908 FOR_EACH_FRAME (tail, frame)
1909 if (FRAME_NS_P (XFRAME (frame))
1910 && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1911 XFRAME (frame)->mouse_moved = 0;
1913 dpyinfo->last_mouse_scroll_bar = nil;
1914 if (dpyinfo->last_mouse_frame
1915 && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
1916 f = dpyinfo->last_mouse_frame;
1918 f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1919 : SELECTED_FRAME ();
1921 if (f && FRAME_NS_P (f))
1923 view = FRAME_NS_VIEW (*fp);
1925 position = [[view window] mouseLocationOutsideOfEventStream];
1926 position = [view convertPoint: position fromView: nil];
1927 remember_mouse_glyph (f, position.x, position.y,
1928 &dpyinfo->last_mouse_glyph);
1930 if (bar_window) *bar_window = Qnil;
1931 if (part) *part = scroll_bar_above_handle;
1933 if (x) XSETINT (*x, lrint (position.x));
1934 if (y) XSETINT (*y, lrint (position.y));
1936 *time = dpyinfo->last_mouse_movement_time;
1946 ns_frame_up_to_date (struct frame *f)
1947 /* --------------------------------------------------------------------------
1948 External (hook): Fix up mouse highlighting right after a full update.
1949 Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
1950 -------------------------------------------------------------------------- */
1952 NSTRACE (ns_frame_up_to_date);
1956 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1957 if (f == hlinfo->mouse_face_mouse_frame)
1961 note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1962 hlinfo->mouse_face_mouse_x,
1963 hlinfo->mouse_face_mouse_y);
1972 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1973 /* --------------------------------------------------------------------------
1974 External (RIF): set frame mouse pointer type.
1975 -------------------------------------------------------------------------- */
1977 NSTRACE (ns_define_frame_cursor);
1978 if (FRAME_POINTER_TYPE (f) != cursor)
1980 EmacsView *view = FRAME_NS_VIEW (f);
1981 FRAME_POINTER_TYPE (f) = cursor;
1982 [[view window] invalidateCursorRectsForView: view];
1983 /* Redisplay assumes this function also draws the changed frame
1984 cursor, but this function doesn't, so do it explicitly. */
1985 x_update_cursor (f, 1);
1991 /* ==========================================================================
1995 ========================================================================== */
1999 ns_convert_key (unsigned code)
2000 /* --------------------------------------------------------------------------
2001 Internal call used by NSView-keyDown.
2002 -------------------------------------------------------------------------- */
2004 const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2006 /* An array would be faster, but less easy to read. */
2007 for (keysym = 0; keysym < last_keysym; keysym += 2)
2008 if (code == convert_ns_to_X_keysym[keysym])
2009 return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2011 /* if decide to use keyCode and Carbon table, use this line:
2012 return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2017 x_get_keysym_name (int keysym)
2018 /* --------------------------------------------------------------------------
2019 Called by keyboard.c. Not sure if the return val is important, except
2021 -------------------------------------------------------------------------- */
2023 static char value[16];
2024 NSTRACE (x_get_keysym_name);
2025 sprintf (value, "%d", keysym);
2031 /* ==========================================================================
2033 Block drawing operations
2035 ========================================================================== */
2039 ns_redraw_scroll_bars (struct frame *f)
2043 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2044 NSTRACE (ns_redraw_scroll_bars);
2045 for (i =[subviews count]-1; i >= 0; i--)
2047 view = [subviews objectAtIndex: i];
2048 if (![view isKindOfClass: [EmacsScroller class]]) continue;
2055 ns_clear_frame (struct frame *f)
2056 /* --------------------------------------------------------------------------
2057 External (hook): Erase the entire frame
2058 -------------------------------------------------------------------------- */
2060 NSView *view = FRAME_NS_VIEW (f);
2063 NSTRACE (ns_clear_frame);
2065 /* comes on initial frame because we have
2066 after-make-frame-functions = select-frame */
2067 if (!FRAME_DEFAULT_FACE (f))
2070 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2075 ns_focus (f, &r, 1);
2076 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2080 /* as of 2006/11 or so this is now needed */
2081 ns_redraw_scroll_bars (f);
2087 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2088 /* --------------------------------------------------------------------------
2089 External (RIF): Clear section of frame
2090 -------------------------------------------------------------------------- */
2092 NSRect r = NSMakeRect (x, y, width, height);
2093 NSView *view = FRAME_NS_VIEW (f);
2094 struct face *face = FRAME_DEFAULT_FACE (f);
2099 NSTRACE (ns_clear_frame_area);
2101 r = NSIntersectionRect (r, [view frame]);
2102 ns_focus (f, &r, 1);
2103 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2113 ns_scroll_run (struct window *w, struct run *run)
2114 /* --------------------------------------------------------------------------
2115 External (RIF): Insert or delete n lines at line vpos
2116 -------------------------------------------------------------------------- */
2118 struct frame *f = XFRAME (w->frame);
2119 int x, y, width, height, from_y, to_y, bottom_y;
2121 NSTRACE (ns_scroll_run);
2123 /* begin copy from other terms */
2124 /* Get frame-relative bounding box of the text display area of W,
2125 without mode lines. Include in this box the left and right
2127 window_box (w, ANY_AREA, &x, &y, &width, &height);
2129 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2130 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2131 bottom_y = y + height;
2135 /* Scrolling up. Make sure we don't copy part of the mode
2136 line at the bottom. */
2137 if (from_y + run->height > bottom_y)
2138 height = bottom_y - from_y;
2140 height = run->height;
2144 /* Scrolling down. Make sure we don't copy over the mode line.
2146 if (to_y + run->height > bottom_y)
2147 height = bottom_y - to_y;
2149 height = run->height;
2151 /* end copy from other terms */
2161 NSRect srcRect = NSMakeRect (x, from_y, width, height);
2162 NSRect dstRect = NSMakeRect (x, to_y, width, height);
2163 NSPoint dstOrigin = NSMakePoint (x, to_y);
2165 ns_focus (f, &dstRect, 1);
2166 NSCopyBits (0, srcRect , dstOrigin);
2175 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2176 /* --------------------------------------------------------------------------
2177 External (RIF): preparatory to fringe update after text was updated
2178 -------------------------------------------------------------------------- */
2183 NSTRACE (ns_after_update_window_line);
2185 /* begin copy from other terms */
2188 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2189 desired_row->redraw_fringe_bitmaps_p = 1;
2191 /* When a window has disappeared, make sure that no rest of
2192 full-width rows stays visible in the internal border. */
2193 if (windows_or_buffers_changed
2194 && desired_row->full_width_p
2195 && (f = XFRAME (w->frame),
2196 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2198 && (height = desired_row->visible_height,
2201 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2204 ns_clear_frame_area (f, 0, y, width, height);
2205 ns_clear_frame_area (f,
2206 FRAME_PIXEL_WIDTH (f) - width,
2214 ns_shift_glyphs_for_insert (struct frame *f,
2215 int x, int y, int width, int height,
2217 /* --------------------------------------------------------------------------
2218 External (RIF): copy an area horizontally, don't worry about clearing src
2219 -------------------------------------------------------------------------- */
2221 NSRect srcRect = NSMakeRect (x, y, width, height);
2222 NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2223 NSPoint dstOrigin = dstRect.origin;
2225 NSTRACE (ns_shift_glyphs_for_insert);
2227 ns_focus (f, &dstRect, 1);
2228 NSCopyBits (0, srcRect, dstOrigin);
2234 /* ==========================================================================
2236 Character encoding and metrics
2238 ========================================================================== */
2242 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2243 /* --------------------------------------------------------------------------
2244 External (RIF); compute left/right overhang of whole string and set in s
2245 -------------------------------------------------------------------------- */
2247 struct font *font = s->font;
2251 struct font_metrics metrics;
2252 unsigned int codes[2];
2253 codes[0] = *(s->char2b);
2254 codes[1] = *(s->char2b + s->nchars - 1);
2256 font->driver->text_extents (font, codes, 2, &metrics);
2257 s->left_overhang = -metrics.lbearing;
2259 = metrics.rbearing > metrics.width
2260 ? metrics.rbearing - metrics.width : 0;
2264 s->left_overhang = 0;
2265 if (EQ (font->driver->type, Qns))
2266 s->right_overhang = ((struct nsfont_info *)font)->ital ?
2267 FONT_HEIGHT (font) * 0.2 : 0;
2269 s->right_overhang = 0;
2275 /* ==========================================================================
2277 Fringe and cursor drawing
2279 ========================================================================== */
2282 extern int max_used_fringe_bitmap;
2284 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2285 struct draw_fringe_bitmap_params *p)
2286 /* --------------------------------------------------------------------------
2287 External (RIF); fringe-related
2288 -------------------------------------------------------------------------- */
2290 struct frame *f = XFRAME (WINDOW_FRAME (w));
2291 struct face *face = p->face;
2292 static EmacsImage **bimgs = NULL;
2293 static int nBimgs = 0;
2295 /* grow bimgs if needed */
2296 if (nBimgs < max_used_fringe_bitmap)
2298 bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2299 memset (bimgs + nBimgs, 0,
2300 (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2301 nBimgs = max_used_fringe_bitmap;
2304 /* Must clip because of partially visible lines. */
2305 ns_clip_to_row (w, row, ANY_AREA, YES);
2309 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2311 if (bx >= 0 && nx > 0)
2313 NSRect r = NSMakeRect (bx, by, nx, ny);
2315 [ns_lookup_indexed_color (face->background, f) set];
2322 NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2323 EmacsImage *img = bimgs[p->which - 1];
2327 unsigned short *bits = p->bits + p->dh;
2330 unsigned char *cbits = xmalloc (len);
2332 for (i = 0; i < len; i++)
2333 cbits[i] = ~(bits[i] & 0xff);
2334 img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2336 bimgs[p->which - 1] = img;
2341 /* Since we composite the bitmap instead of just blitting it, we need
2342 to erase the whole background. */
2343 [ns_lookup_indexed_color(face->background, f) set];
2349 bm_color = ns_lookup_indexed_color(face->foreground, f);
2350 else if (p->overlay_p)
2351 bm_color = ns_lookup_indexed_color(face->background, f);
2353 bm_color = f->output_data.ns->cursor_color;
2354 [img setXBMColor: bm_color];
2357 #ifdef NS_IMPL_COCOA
2359 fromRect: NSZeroRect
2360 operation: NSCompositeSourceOver
2366 NSPoint pt = r.origin;
2368 [img compositeToPoint: pt operation: NSCompositeSourceOver];
2377 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2378 int x, int y, enum text_cursor_kinds cursor_type,
2379 int cursor_width, bool on_p, bool active_p)
2380 /* --------------------------------------------------------------------------
2381 External call (RIF): draw cursor.
2382 Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2383 -------------------------------------------------------------------------- */
2386 int fx, fy, h, cursor_height;
2387 struct frame *f = WINDOW_XFRAME (w);
2388 struct glyph *phys_cursor_glyph;
2389 struct glyph *cursor_glyph;
2391 NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2393 /* If cursor is out of bounds, don't draw garbage. This can happen
2394 in mini-buffer windows when switching between echo area glyphs
2397 NSTRACE (dumpcursor);
2402 w->phys_cursor_type = cursor_type;
2403 w->phys_cursor_on_p = on_p;
2405 if (cursor_type == NO_CURSOR)
2407 w->phys_cursor_width = 0;
2411 if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2413 if (glyph_row->exact_window_width_line_p
2414 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2416 glyph_row->cursor_in_fringe_p = 1;
2417 draw_fringe_bitmap (w, glyph_row, 0);
2422 /* We draw the cursor (with NSRectFill), then draw the glyph on top
2423 (other terminals do it the other way round). We must set
2424 w->phys_cursor_width to the cursor width. For bar cursors, that
2425 is CURSOR_WIDTH; for box cursors, it is the glyph width. */
2426 get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2428 /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2429 to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2430 if (cursor_type == BAR_CURSOR)
2432 if (cursor_width < 1)
2433 cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2434 w->phys_cursor_width = cursor_width;
2436 /* If we have an HBAR, "cursor_width" MAY specify height. */
2437 else if (cursor_type == HBAR_CURSOR)
2439 cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2440 if (cursor_height > glyph_row->height)
2441 cursor_height = glyph_row->height;
2442 if (h > cursor_height) // Cursor smaller than line height, move down
2443 fy += h - cursor_height;
2447 r.origin.x = fx, r.origin.y = fy;
2449 r.size.width = w->phys_cursor_width;
2451 /* TODO: only needed in rare cases with last-resort font in HELLO..
2452 should we do this more efficiently? */
2453 ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2456 face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2457 if (face && NS_FACE_BACKGROUND (face)
2458 == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2460 [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2461 hollow_color = FRAME_CURSOR_COLOR (f);
2464 [FRAME_CURSOR_COLOR (f) set];
2466 #ifdef NS_IMPL_COCOA
2467 /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2468 atomic. Cleaner ways of doing this should be investigated.
2469 One way would be to set a global variable DRAWING_CURSOR
2470 when making the call to draw_phys..(), don't focus in that
2471 case, then move the ns_unfocus() here after that call. */
2472 NSDisableScreenUpdates ();
2475 switch (cursor_type)
2479 case FILLED_BOX_CURSOR:
2482 case HOLLOW_BOX_CURSOR:
2485 NSRectFill (NSInsetRect (r, 1, 1));
2486 [FRAME_CURSOR_COLOR (f) set];
2493 /* If the character under cursor is R2L, draw the bar cursor
2494 on the right of its glyph, rather than on the left. */
2495 cursor_glyph = get_phys_cursor_glyph (w);
2496 if ((cursor_glyph->resolved_level & 1) != 0)
2497 s.origin.x += cursor_glyph->pixel_width - s.size.width;
2504 /* draw the character under the cursor */
2505 if (cursor_type != NO_CURSOR)
2506 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2508 #ifdef NS_IMPL_COCOA
2509 NSEnableScreenUpdates ();
2516 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2517 /* --------------------------------------------------------------------------
2518 External (RIF): Draw a vertical line.
2519 -------------------------------------------------------------------------- */
2521 struct frame *f = XFRAME (WINDOW_FRAME (w));
2523 NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2525 NSTRACE (ns_draw_vertical_window_border);
2527 face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2529 [ns_lookup_indexed_color(face->foreground, f) set];
2531 ns_focus (f, &r, 1);
2538 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
2539 /* --------------------------------------------------------------------------
2540 External (RIF): Draw a window divider.
2541 -------------------------------------------------------------------------- */
2543 struct frame *f = XFRAME (WINDOW_FRAME (w));
2545 NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
2547 NSTRACE (ns_draw_window_divider);
2549 face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID);
2551 [ns_lookup_indexed_color(face->foreground, f) set];
2553 ns_focus (f, &r, 1);
2559 ns_show_hourglass (struct frame *f)
2561 /* TODO: add NSProgressIndicator to all frames. */
2565 ns_hide_hourglass (struct frame *f)
2567 /* TODO: remove NSProgressIndicator from all frames. */
2570 /* ==========================================================================
2572 Glyph drawing operations
2574 ========================================================================== */
2577 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2578 /* --------------------------------------------------------------------------
2579 Wrapper utility to account for internal border width on full-width lines,
2580 and allow top full-width rows to hit the frame top. nr should be pointer
2581 to two successive NSRects. Number of rects actually used is returned.
2582 -------------------------------------------------------------------------- */
2584 int n = get_glyph_string_clip_rects (s, nr, 2);
2588 /* --------------------------------------------------------------------
2589 Draw a wavy line under glyph string s. The wave fills wave_height
2596 wave_height = 3 | * * * *
2597 --------------------------------------------------------------------- */
2600 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
2602 int wave_height = 3, wave_length = 2;
2603 int y, dx, dy, odd, xmax;
2608 dy = wave_height - 1;
2609 y = s->ybase - wave_height + 3;
2612 /* Find and set clipping rectangle */
2613 waveClip = NSMakeRect (x, y, width, wave_height);
2614 [[NSGraphicsContext currentContext] saveGraphicsState];
2615 NSRectClip (waveClip);
2617 /* Draw the waves */
2618 a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
2620 odd = (int)(a.x/dx) % 2;
2621 a.y = b.y = y + 0.5;
2630 [NSBezierPath strokeLineFromPoint:a toPoint:b];
2631 a.x = b.x, a.y = b.y;
2632 b.x += dx, b.y = y + 0.5 + odd*dy;
2636 /* Restore previous clipping rectangle(s) */
2637 [[NSGraphicsContext currentContext] restoreGraphicsState];
2643 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2644 NSColor *defaultCol, CGFloat width, CGFloat x)
2645 /* --------------------------------------------------------------------------
2646 Draw underline, overline, and strike-through on glyph string s.
2647 -------------------------------------------------------------------------- */
2649 if (s->for_overlaps)
2653 if (face->underline_p)
2655 if (s->face->underline_type == FACE_UNDER_WAVE)
2657 if (face->underline_defaulted_p)
2660 [ns_lookup_indexed_color (face->underline_color, s->f) set];
2662 ns_draw_underwave (s, width, x);
2664 else if (s->face->underline_type == FACE_UNDER_LINE)
2668 unsigned long thickness, position;
2670 /* If the prev was underlined, match its appearance. */
2671 if (s->prev && s->prev->face->underline_p
2672 && s->prev->face->underline_type == FACE_UNDER_LINE
2673 && s->prev->underline_thickness > 0)
2675 thickness = s->prev->underline_thickness;
2676 position = s->prev->underline_position;
2681 unsigned long descent;
2684 descent = s->y + s->height - s->ybase;
2686 /* Use underline thickness of font, defaulting to 1. */
2687 thickness = (font && font->underline_thickness > 0)
2688 ? font->underline_thickness : 1;
2690 /* Determine the offset of underlining from the baseline. */
2691 if (x_underline_at_descent_line)
2692 position = descent - thickness;
2693 else if (x_use_underline_position_properties
2694 && font && font->underline_position >= 0)
2695 position = font->underline_position;
2697 position = lround (font->descent / 2);
2699 position = underline_minimum_offset;
2701 position = max (position, underline_minimum_offset);
2703 /* Ensure underlining is not cropped. */
2704 if (descent <= position)
2706 position = descent - 1;
2709 else if (descent < position + thickness)
2713 s->underline_thickness = thickness;
2714 s->underline_position = position;
2716 r = NSMakeRect (x, s->ybase + position, width, thickness);
2718 if (face->underline_defaulted_p)
2721 [ns_lookup_indexed_color (face->underline_color, s->f) set];
2725 /* Do overline. We follow other terms in using a thickness of 1
2726 and ignoring overline_margin. */
2727 if (face->overline_p)
2730 r = NSMakeRect (x, s->y, width, 1);
2732 if (face->overline_color_defaulted_p)
2735 [ns_lookup_indexed_color (face->overline_color, s->f) set];
2739 /* Do strike-through. We follow other terms for thickness and
2740 vertical position.*/
2741 if (face->strike_through_p)
2746 dy = lrint ((s->height - 1) / 2);
2747 r = NSMakeRect (x, s->y + dy, width, 1);
2749 if (face->strike_through_color_defaulted_p)
2752 [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2758 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
2759 char left_p, char right_p)
2760 /* --------------------------------------------------------------------------
2761 Draw an unfilled rect inside r, optionally leaving left and/or right open.
2762 Note we can't just use an NSDrawRect command, because of the possibility
2763 of some sides not being drawn, and because the rect will be filled.
2764 -------------------------------------------------------------------------- */
2770 s.size.height = thickness;
2772 s.origin.y += r.size.height - thickness;
2775 s.size.height = r.size.height;
2776 s.origin.y = r.origin.y;
2778 /* left, right (optional) */
2779 s.size.width = thickness;
2784 s.origin.x += r.size.width - thickness;
2791 ns_draw_relief (NSRect r, int thickness, char raised_p,
2792 char top_p, char bottom_p, char left_p, char right_p,
2793 struct glyph_string *s)
2794 /* --------------------------------------------------------------------------
2795 Draw a relief rect inside r, optionally leaving some sides open.
2796 Note we can't just use an NSDrawBezel command, because of the possibility
2797 of some sides not being drawn, and because the rect will be filled.
2798 -------------------------------------------------------------------------- */
2800 static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2801 NSColor *newBaseCol = nil;
2804 NSTRACE (ns_draw_relief);
2808 if (s->face->use_box_color_for_shadows_p)
2810 newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2812 /* else if (s->first_glyph->type == IMAGE_GLYPH
2814 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2816 newBaseCol = IMAGE_BACKGROUND (s->img, s->f, 0);
2820 newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2823 if (newBaseCol == nil)
2824 newBaseCol = [NSColor grayColor];
2826 if (newBaseCol != baseCol) /* TODO: better check */
2829 baseCol = [newBaseCol retain];
2831 lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2833 darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2836 [(raised_p ? lightCol : darkCol) set];
2838 /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2841 sr.size.height = thickness;
2842 if (top_p) NSRectFill (sr);
2845 sr.size.height = r.size.height;
2846 sr.size.width = thickness;
2847 if (left_p) NSRectFill (sr);
2849 [(raised_p ? darkCol : lightCol) set];
2852 sr.size.width = r.size.width;
2853 sr.size.height = thickness;
2854 sr.origin.y += r.size.height - thickness;
2855 if (bottom_p) NSRectFill (sr);
2858 sr.size.height = r.size.height;
2859 sr.origin.y = r.origin.y;
2860 sr.size.width = thickness;
2861 sr.origin.x += r.size.width - thickness;
2862 if (right_p) NSRectFill (sr);
2867 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2868 /* --------------------------------------------------------------------------
2869 Function modeled after x_draw_glyph_string_box ().
2870 Sets up parameters for drawing.
2871 -------------------------------------------------------------------------- */
2873 int right_x, last_x;
2874 char left_p, right_p;
2875 struct glyph *last_glyph;
2880 if (s->hl == DRAW_MOUSE_FACE)
2882 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2884 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2889 thickness = face->box_line_width;
2891 NSTRACE (ns_dumpglyphs_box_or_relief);
2893 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2894 ? WINDOW_RIGHT_EDGE_X (s->w)
2895 : window_box_right (s->w, s->area));
2896 last_glyph = (s->cmp || s->img
2897 ? s->first_glyph : s->first_glyph + s->nchars-1);
2899 right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2900 ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2902 left_p = (s->first_glyph->left_box_line_p
2903 || (s->hl == DRAW_MOUSE_FACE
2904 && (s->prev == NULL || s->prev->hl != s->hl)));
2905 right_p = (last_glyph->right_box_line_p
2906 || (s->hl == DRAW_MOUSE_FACE
2907 && (s->next == NULL || s->next->hl != s->hl)));
2909 r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2911 /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2912 if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2914 ns_draw_box (r, abs (thickness),
2915 ns_lookup_indexed_color (face->box_color, s->f),
2920 ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2921 1, 1, left_p, right_p, s);
2927 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2928 /* --------------------------------------------------------------------------
2929 Modeled after x_draw_glyph_string_background, which draws BG in
2930 certain cases. Others are left to the text rendering routine.
2931 -------------------------------------------------------------------------- */
2933 NSTRACE (ns_maybe_dumpglyphs_background);
2935 if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2937 int box_line_width = max (s->face->box_line_width, 0);
2938 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2939 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2942 if (s->hl == DRAW_MOUSE_FACE)
2944 face = FACE_FROM_ID (s->f,
2945 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2947 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2950 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2952 [(NS_FACE_BACKGROUND (face) != 0
2953 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2954 : FRAME_BACKGROUND_COLOR (s->f)) set];
2957 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
2958 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2961 if (s->hl != DRAW_CURSOR)
2963 NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2964 s->background_width,
2965 s->height-2*box_line_width);
2969 s->background_filled_p = 1;
2976 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2977 /* --------------------------------------------------------------------------
2978 Renders an image and associated borders.
2979 -------------------------------------------------------------------------- */
2981 EmacsImage *img = s->img->pixmap;
2982 int box_line_vwidth = max (s->face->box_line_width, 0);
2983 int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2984 int bg_x, bg_y, bg_height;
2991 NSTRACE (ns_dumpglyphs_image);
2993 if (s->face->box != FACE_NO_BOX
2994 && s->first_glyph->left_box_line_p && s->slice.x == 0)
2995 x += abs (s->face->box_line_width);
2998 bg_y = s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2999 bg_height = s->height;
3000 /* other terms have this, but was causing problems w/tabbar mode */
3001 /* - 2 * box_line_vwidth; */
3003 if (s->slice.x == 0) x += s->img->hmargin;
3004 if (s->slice.y == 0) y += s->img->vmargin;
3006 /* Draw BG: if we need larger area than image itself cleared, do that,
3007 otherwise, since we composite the image under NS (instead of mucking
3008 with its background color), we must clear just the image area. */
3009 if (s->hl == DRAW_MOUSE_FACE)
3011 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3013 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3016 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3018 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3020 if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3021 || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3023 br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3024 s->background_filled_p = 1;
3028 br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3033 /* Draw the image.. do we need to draw placeholder if img ==nil? */
3036 #ifdef NS_IMPL_COCOA
3037 NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3038 NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3039 s->slice.width, s->slice.height);
3042 operation: NSCompositeSourceOver
3047 [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3048 operation: NSCompositeSourceOver];
3052 if (s->hl == DRAW_CURSOR)
3054 [FRAME_CURSOR_COLOR (s->f) set];
3055 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3056 tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3058 /* Currently on NS img->mask is always 0. Since
3059 get_window_cursor_type specifies a hollow box cursor when on
3060 a non-masked image we never reach this clause. But we put it
3061 in in anticipation of better support for image masks on
3063 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3067 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3070 /* Draw underline, overline, strike-through. */
3071 ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3073 /* Draw relief, if requested */
3074 if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3076 if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3078 th = tool_bar_button_relief >= 0 ?
3079 tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3080 raised_p = (s->hl == DRAW_IMAGE_RAISED);
3084 th = abs (s->img->relief);
3085 raised_p = (s->img->relief > 0);
3088 r.origin.x = x - th;
3089 r.origin.y = y - th;
3090 r.size.width = s->slice.width + 2*th-1;
3091 r.size.height = s->slice.height + 2*th-1;
3092 ns_draw_relief (r, th, raised_p,
3094 s->slice.y + s->slice.height == s->img->height,
3096 s->slice.x + s->slice.width == s->img->width, s);
3099 /* If there is no mask, the background won't be seen,
3100 so draw a rectangle on the image for the cursor.
3101 Do this for all images, getting transparency right is not reliable. */
3102 if (s->hl == DRAW_CURSOR)
3104 int thickness = abs (s->img->relief);
3105 if (thickness == 0) thickness = 1;
3106 ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3112 ns_dumpglyphs_stretch (struct glyph_string *s)
3117 NSColor *fgCol, *bgCol;
3119 if (!s->background_filled_p)
3121 n = ns_get_glyph_string_clip_rect (s, r);
3122 *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3124 ns_focus (s->f, r, n);
3126 if (s->hl == DRAW_MOUSE_FACE)
3128 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3130 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3133 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3135 bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3136 fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3138 for (i = 0; i < n; ++i)
3140 if (!s->row->full_width_p)
3142 int overrun, leftoverrun;
3144 /* truncate to avoid overwriting fringe and/or scrollbar */
3145 overrun = max (0, (s->x + s->background_width)
3146 - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3147 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3148 r[i].size.width -= overrun;
3150 /* truncate to avoid overwriting to left of the window box */
3151 leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3152 + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3154 if (leftoverrun > 0)
3156 r[i].origin.x += leftoverrun;
3157 r[i].size.width -= leftoverrun;
3160 /* XXX: Try to work between problem where a stretch glyph on
3161 a partially-visible bottom row will clear part of the
3162 modeline, and another where list-buffers headers and similar
3163 rows erroneously have visible_height set to 0. Not sure
3164 where this is coming from as other terms seem not to show. */
3165 r[i].size.height = min (s->height, s->row->visible_height);
3170 /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3171 overwriting cursor (usually when cursor on a tab) */
3172 if (s->hl == DRAW_CURSOR)
3177 width = s->w->phys_cursor_width;
3178 r[i].size.width -= width;
3179 r[i].origin.x += width;
3183 /* Draw overlining, etc. on the cursor. */
3184 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3185 ns_draw_text_decoration (s, face, bgCol, width, x);
3187 ns_draw_text_decoration (s, face, fgCol, width, x);
3194 /* Draw overlining, etc. on the stretch glyph (or the part
3195 of the stretch glyph after the cursor). */
3196 ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3200 s->background_filled_p = 1;
3206 ns_draw_glyph_string (struct glyph_string *s)
3207 /* --------------------------------------------------------------------------
3208 External (RIF): Main draw-text call.
3209 -------------------------------------------------------------------------- */
3211 /* TODO (optimize): focus for box and contents draw */
3214 char box_drawn_p = 0;
3215 struct font *font = s->face->font;
3216 if (! font) font = FRAME_FONT (s->f);
3218 NSTRACE (ns_draw_glyph_string);
3220 if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3223 struct glyph_string *next;
3225 for (width = 0, next = s->next;
3226 next && width < s->right_overhang;
3227 width += next->width, next = next->next)
3228 if (next->first_glyph->type != IMAGE_GLYPH)
3230 if (next->first_glyph->type != STRETCH_GLYPH)
3232 n = ns_get_glyph_string_clip_rect (s->next, r);
3233 ns_focus (s->f, r, n);
3234 ns_maybe_dumpglyphs_background (s->next, 1);
3239 ns_dumpglyphs_stretch (s->next);
3241 next->num_clips = 0;
3245 if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3246 && (s->first_glyph->type == CHAR_GLYPH
3247 || s->first_glyph->type == COMPOSITE_GLYPH))
3249 n = ns_get_glyph_string_clip_rect (s, r);
3250 ns_focus (s->f, r, n);
3251 ns_maybe_dumpglyphs_background (s, 1);
3252 ns_dumpglyphs_box_or_relief (s);
3257 switch (s->first_glyph->type)
3261 n = ns_get_glyph_string_clip_rect (s, r);
3262 ns_focus (s->f, r, n);
3263 ns_dumpglyphs_image (s, r[0]);
3268 ns_dumpglyphs_stretch (s);
3272 case COMPOSITE_GLYPH:
3273 n = ns_get_glyph_string_clip_rect (s, r);
3274 ns_focus (s->f, r, n);
3276 if (s->for_overlaps || (s->cmp_from > 0
3277 && ! s->first_glyph->u.cmp.automatic))
3278 s->background_filled_p = 1;
3280 ns_maybe_dumpglyphs_background
3281 (s, s->first_glyph->type == COMPOSITE_GLYPH);
3283 flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3284 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3285 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3286 NS_DUMPGLYPH_NORMAL));
3288 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3290 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3291 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3292 NS_FACE_FOREGROUND (s->face) = tmp;
3296 BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
3297 int end = isComposite ? s->cmp_to : s->nchars;
3300 (s, s->cmp_from, end, s->x, s->ybase,
3301 (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3302 || flags == NS_DUMPGLYPH_MOUSEFACE);
3307 NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3308 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3310 : FRAME_FOREGROUND_COLOR (s->f));
3313 /* Draw underline, overline, strike-through. */
3314 ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3317 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3319 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3320 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3321 NS_FACE_FOREGROUND (s->face) = tmp;
3327 case GLYPHLESS_GLYPH:
3328 n = ns_get_glyph_string_clip_rect (s, r);
3329 ns_focus (s->f, r, n);
3331 if (s->for_overlaps || (s->cmp_from > 0
3332 && ! s->first_glyph->u.cmp.automatic))
3333 s->background_filled_p = 1;
3335 ns_maybe_dumpglyphs_background
3336 (s, s->first_glyph->type == COMPOSITE_GLYPH);
3338 /* Not yet implemented. */
3347 /* Draw box if not done already. */
3348 if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3350 n = ns_get_glyph_string_clip_rect (s, r);
3351 ns_focus (s->f, r, n);
3352 ns_dumpglyphs_box_or_relief (s);
3361 /* ==========================================================================
3365 ========================================================================== */
3369 ns_send_appdefined (int value)
3370 /* --------------------------------------------------------------------------
3371 Internal: post an appdefined event which EmacsApp-sendEvent will
3372 recognize and take as a command to halt the event loop.
3373 -------------------------------------------------------------------------- */
3375 /*NSTRACE (ns_send_appdefined); */
3377 #ifdef NS_IMPL_GNUSTEP
3378 // GNUstep needs postEvent to happen on the main thread.
3379 if (! [[NSThread currentThread] isMainThread])
3381 EmacsApp *app = (EmacsApp *)NSApp;
3382 app->nextappdefined = value;
3383 [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3390 /* Only post this event if we haven't already posted one. This will end
3391 the [NXApp run] main loop after having processed all events queued at
3393 if (send_appdefined)
3397 /* We only need one NX_APPDEFINED event to stop NXApp from running. */
3398 send_appdefined = NO;
3400 /* Don't need wakeup timer any more */
3403 [timed_entry invalidate];
3404 [timed_entry release];
3408 nxev = [NSEvent otherEventWithType: NSApplicationDefined
3409 location: NSMakePoint (0, 0)
3412 windowNumber: [[NSApp mainWindow] windowNumber]
3413 context: [NSApp context]
3418 /* Post an application defined event on the event queue. When this is
3419 received the [NXApp run] will return, thus having processed all
3420 events which are currently queued. */
3421 [NSApp postEvent: nxev atStart: NO];
3425 #ifdef HAVE_NATIVE_FS
3429 Lisp_Object frame, tail;
3431 if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3434 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3436 FOR_EACH_FRAME (tail, frame)
3438 struct frame *f = XFRAME (frame);
3441 EmacsView *view = FRAME_NS_VIEW (f);
3442 [view updateCollectionBehavior];
3448 /* GNUstep does not have cancelTracking. */
3449 #ifdef NS_IMPL_COCOA
3450 /* Check if menu open should be canceled or continued as normal. */
3452 ns_check_menu_open (NSMenu *menu)
3454 /* Click in menu bar? */
3455 NSArray *a = [[NSApp mainMenu] itemArray];
3459 if (menu == nil) // Menu tracking ended.
3461 if (menu_will_open_state == MENU_OPENING)
3462 menu_will_open_state = MENU_NONE;
3466 for (i = 0; ! found && i < [a count]; i++)
3467 found = menu == [[a objectAtIndex:i] submenu];
3470 if (menu_will_open_state == MENU_NONE && emacs_event)
3472 NSEvent *theEvent = [NSApp currentEvent];
3473 struct frame *emacsframe = SELECTED_FRAME ();
3475 [menu cancelTracking];
3476 menu_will_open_state = MENU_PENDING;
3477 emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3478 EV_TRAILER (theEvent);
3480 CGEventRef ourEvent = CGEventCreate (NULL);
3481 menu_mouse_point = CGEventGetLocation (ourEvent);
3482 CFRelease (ourEvent);
3484 else if (menu_will_open_state == MENU_OPENING)
3486 menu_will_open_state = MENU_NONE;
3491 /* Redo saved menu click if state is MENU_PENDING. */
3493 ns_check_pending_open_menu ()
3495 if (menu_will_open_state == MENU_PENDING)
3497 CGEventSourceRef source
3498 = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3500 CGEventRef event = CGEventCreateMouseEvent (source,
3501 kCGEventLeftMouseDown,
3503 kCGMouseButtonLeft);
3504 CGEventSetType (event, kCGEventLeftMouseDown);
3505 CGEventPost (kCGHIDEventTap, event);
3509 menu_will_open_state = MENU_OPENING;
3512 #endif /* NS_IMPL_COCOA */
3515 unwind_apploopnr (Lisp_Object not_used)
3518 n_emacs_events_pending = 0;
3519 ns_finish_events ();
3524 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3525 /* --------------------------------------------------------------------------
3526 External (hook): Post an event to ourself and keep reading events until
3527 we read it back again. In effect process all events which were waiting.
3528 From 21+ we have to manage the event buffer ourselves.
3529 -------------------------------------------------------------------------- */
3531 struct input_event ev;
3534 /* NSTRACE (ns_read_socket); */
3536 #ifdef HAVE_NATIVE_FS
3540 if ([NSApp modalWindow] != nil)
3543 if (hold_event_q.nr > 0)
3546 for (i = 0; i < hold_event_q.nr; ++i)
3547 kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3548 hold_event_q.nr = 0;
3553 n_emacs_events_pending = 0;
3554 ns_init_events (&ev);
3555 q_event_ptr = hold_quit;
3557 /* we manage autorelease pools by allocate/reallocate each time around
3558 the loop; strict nesting is occasionally violated but seems not to
3559 matter.. earlier methods using full nesting caused major memory leaks */
3560 [outerpool release];
3561 outerpool = [[NSAutoreleasePool alloc] init];
3563 /* If have pending open-file requests, attend to the next one of those. */
3564 if (ns_pending_files && [ns_pending_files count] != 0
3565 && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3567 [ns_pending_files removeObjectAtIndex: 0];
3569 /* Deal with pending service requests. */
3570 else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3572 NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3573 withArg: [ns_pending_service_args objectAtIndex: 0]])
3575 [ns_pending_service_names removeObjectAtIndex: 0];
3576 [ns_pending_service_args removeObjectAtIndex: 0];
3580 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
3581 /* Run and wait for events. We must always send one NX_APPDEFINED event
3582 to ourself, otherwise [NXApp run] will never exit. */
3583 send_appdefined = YES;
3584 ns_send_appdefined (-1);
3586 if (++apploopnr != 1)
3590 record_unwind_protect (unwind_apploopnr, Qt);
3592 unbind_to (specpdl_count, Qnil); /* calls unwind_apploopnr */
3595 nevents = n_emacs_events_pending;
3596 n_emacs_events_pending = 0;
3597 ns_finish_events ();
3606 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3607 fd_set *exceptfds, struct timespec const *timeout,
3608 sigset_t const *sigmask)
3609 /* --------------------------------------------------------------------------
3610 Replacement for select, checking for events
3611 -------------------------------------------------------------------------- */
3615 struct input_event event;
3618 /* NSTRACE (ns_select); */
3620 #ifdef HAVE_NATIVE_FS
3624 if (hold_event_q.nr > 0)
3626 /* We already have events pending. */
3632 for (k = 0; k < nfds+1; k++)
3634 if (readfds && FD_ISSET(k, readfds)) ++nr;
3635 if (writefds && FD_ISSET(k, writefds)) ++nr;
3639 || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3640 return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3642 [outerpool release];
3643 outerpool = [[NSAutoreleasePool alloc] init];
3646 send_appdefined = YES;
3649 pthread_mutex_lock (&select_mutex);
3654 select_readfds = *readfds;
3655 select_valid += SELECT_HAVE_READ;
3659 select_writefds = *writefds;
3660 select_valid += SELECT_HAVE_WRITE;
3665 select_timeout = *timeout;
3666 select_valid += SELECT_HAVE_TMO;
3669 pthread_mutex_unlock (&select_mutex);
3671 /* Inform fd_handler that select should be called */
3673 emacs_write_sig (selfds[1], &c, 1);
3675 else if (nr == 0 && timeout)
3677 /* No file descriptor, just a timeout, no need to wake fd_handler */
3678 double time = timespectod (*timeout);
3679 timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3682 @selector (timeout_handler:)
3687 else /* No timeout and no file descriptors, can this happen? */
3689 /* Send appdefined so we exit from the loop */
3690 ns_send_appdefined (-1);
3694 ns_init_events (&event);
3695 if (++apploopnr != 1)
3701 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
3702 record_unwind_protect (unwind_apploopnr, Qt);
3704 unbind_to (specpdl_count, Qnil); /* calls unwind_apploopnr */
3707 ns_finish_events ();
3708 if (nr > 0 && readfds)
3711 emacs_write_sig (selfds[1], &c, 1);
3715 t = last_appdefined_event_data;
3717 if (t != NO_APPDEFINED_DATA)
3719 last_appdefined_event_data = NO_APPDEFINED_DATA;
3723 /* The NX_APPDEFINED event we received was a timeout. */
3728 /* The NX_APPDEFINED event we received was the result of
3729 at least one real input event arriving. */
3735 /* Received back from select () in fd_handler; copy the results */
3736 pthread_mutex_lock (&select_mutex);
3737 if (readfds) *readfds = select_readfds;
3738 if (writefds) *writefds = select_writefds;
3739 pthread_mutex_unlock (&select_mutex);
3754 /* ==========================================================================
3758 ========================================================================== */
3762 ns_set_vertical_scroll_bar (struct window *window,
3763 int portion, int whole, int position)
3764 /* --------------------------------------------------------------------------
3765 External (hook): Update or add scrollbar
3766 -------------------------------------------------------------------------- */
3770 struct frame *f = XFRAME (WINDOW_FRAME (window));
3771 EmacsView *view = FRAME_NS_VIEW (f);
3773 int window_y, window_height;
3774 int top, left, height, width;
3776 /* optimization; display engine sends WAY too many of these.. */
3777 if (!NILP (window->vertical_scroll_bar))
3779 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3780 if ([bar checkSamePosition: position portion: portion whole: whole])
3782 if (view->scrollbarsNeedingUpdate == 0)
3784 if (!windows_or_buffers_changed)
3788 view->scrollbarsNeedingUpdate--;
3792 NSTRACE (ns_set_vertical_scroll_bar);
3794 /* Get dimensions. */
3795 window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
3797 height = window_height;
3798 width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3799 left = WINDOW_SCROLL_BAR_AREA_X (window);
3801 r = NSMakeRect (left, top, width, height);
3802 /* the parent view is flipped, so we need to flip y value */
3804 r.origin.y = (v.size.height - r.size.height - r.origin.y);
3806 XSETWINDOW (win, window);
3809 /* we want at least 5 lines to display a scrollbar */
3810 if (WINDOW_TOTAL_LINES (window) < 5)
3812 if (!NILP (window->vertical_scroll_bar))
3814 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3815 [bar removeFromSuperview];
3816 wset_vertical_scroll_bar (window, Qnil);
3818 ns_clear_frame_area (f, left, top, width, height);
3823 if (NILP (window->vertical_scroll_bar))
3825 if (width > 0 && height > 0)
3826 ns_clear_frame_area (f, left, top, width, height);
3828 bar = [[EmacsScroller alloc] initFrame: r window: win];
3829 wset_vertical_scroll_bar (window, make_save_ptr (bar));
3834 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3835 oldRect = [bar frame];
3836 r.size.width = oldRect.size.width;
3837 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3839 if (oldRect.origin.x != r.origin.x)
3840 ns_clear_frame_area (f, left, top, width, height);
3845 [bar setPosition: position portion: portion whole: whole];
3851 ns_set_horizontal_scroll_bar (struct window *window,
3852 int portion, int whole, int position)
3853 /* --------------------------------------------------------------------------
3854 External (hook): Update or add scrollbar
3855 -------------------------------------------------------------------------- */
3859 struct frame *f = XFRAME (WINDOW_FRAME (window));
3860 EmacsView *view = FRAME_NS_VIEW (f);
3862 int top, height, left, width;
3863 int window_x, window_width;
3864 int pixel_width = WINDOW_PIXEL_WIDTH (window);
3866 /* optimization; display engine sends WAY too many of these.. */
3867 if (!NILP (window->horizontal_scroll_bar))
3869 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
3870 if ([bar checkSamePosition: position portion: portion whole: whole])
3872 if (view->scrollbarsNeedingUpdate == 0)
3874 if (!windows_or_buffers_changed)
3878 view->scrollbarsNeedingUpdate--;
3882 NSTRACE (ns_set_horizontal_scroll_bar);
3884 /* Get dimensions. */
3885 window_box (window, ANY_AREA, 0, &window_x, &window_width, 0);
3887 width = window_width;
3888 height = WINDOW_CONFIG_SCROLL_BAR_LINES (window) * FRAME_LINE_HEIGHT (f);
3889 top = WINDOW_SCROLL_BAR_AREA_Y (window);
3891 r = NSMakeRect (left, top, width, height);
3892 /* the parent view is flipped, so we need to flip y value */
3894 /* ??????? PXW/scrollbars !!!!!!!!!!!!!!!!!!!! */
3895 r.origin.y = (v.size.height - r.size.height - r.origin.y);
3897 XSETWINDOW (win, window);
3900 if (WINDOW_TOTAL_COLS (window) < 5)
3902 if (!NILP (window->horizontal_scroll_bar))
3904 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
3905 [bar removeFromSuperview];
3906 wset_horizontal_scroll_bar (window, Qnil);
3908 ns_clear_frame_area (f, left, top, width, height);
3913 if (NILP (window->horizontal_scroll_bar))
3915 if (width > 0 && height > 0)
3916 ns_clear_frame_area (f, left, top, width, height);
3918 bar = [[EmacsScroller alloc] initFrame: r window: win];
3919 wset_horizontal_scroll_bar (window, make_save_ptr (bar));
3924 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
3925 oldRect = [bar frame];
3926 r.size.width = oldRect.size.width;
3927 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3929 if (oldRect.origin.x != r.origin.x)
3930 ns_clear_frame_area (f, left, top, width, height);
3935 [bar setPosition: position portion: portion whole: whole];
3941 ns_condemn_scroll_bars (struct frame *f)
3942 /* --------------------------------------------------------------------------
3943 External (hook): arrange for all frame's scrollbars to be removed
3944 at next call to judge_scroll_bars, except for those redeemed.
3945 -------------------------------------------------------------------------- */
3949 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3951 NSTRACE (ns_condemn_scroll_bars);
3953 for (i =[subviews count]-1; i >= 0; i--)
3955 view = [subviews objectAtIndex: i];
3956 if ([view isKindOfClass: [EmacsScroller class]])
3963 ns_redeem_scroll_bar (struct window *window)
3964 /* --------------------------------------------------------------------------
3965 External (hook): arrange to spare this window's scrollbar
3966 at next call to judge_scroll_bars.
3967 -------------------------------------------------------------------------- */
3970 NSTRACE (ns_redeem_scroll_bar);
3971 if (!NILP (window->vertical_scroll_bar))
3973 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3977 if (!NILP (window->horizontal_scroll_bar))
3979 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
3986 ns_judge_scroll_bars (struct frame *f)
3987 /* --------------------------------------------------------------------------
3988 External (hook): destroy all scrollbars on frame that weren't
3989 redeemed after call to condemn_scroll_bars.
3990 -------------------------------------------------------------------------- */
3994 EmacsView *eview = FRAME_NS_VIEW (f);
3995 NSArray *subviews = [[eview superview] subviews];
3998 NSTRACE (ns_judge_scroll_bars);
3999 for (i = [subviews count]-1; i >= 0; --i)
4001 view = [subviews objectAtIndex: i];
4002 if (![view isKindOfClass: [EmacsScroller class]]) continue;
4008 [eview updateFrameSize: NO];
4011 /* ==========================================================================
4015 ========================================================================== */
4018 x_display_pixel_height (struct ns_display_info *dpyinfo)
4020 NSArray *screens = [NSScreen screens];
4021 NSEnumerator *enumerator = [screens objectEnumerator];
4026 while ((screen = [enumerator nextObject]) != nil)
4027 frame = NSUnionRect (frame, [screen frame]);
4029 return NSHeight (frame);
4033 x_display_pixel_width (struct ns_display_info *dpyinfo)
4035 NSArray *screens = [NSScreen screens];
4036 NSEnumerator *enumerator = [screens objectEnumerator];
4041 while ((screen = [enumerator nextObject]) != nil)
4042 frame = NSUnionRect (frame, [screen frame]);
4044 return NSWidth (frame);
4048 static Lisp_Object ns_string_to_lispmod (const char *s)
4049 /* --------------------------------------------------------------------------
4050 Convert modifier name to lisp symbol
4051 -------------------------------------------------------------------------- */
4053 if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4055 else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4057 else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4059 else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4061 else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4063 else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4071 ns_default (const char *parameter, Lisp_Object *result,
4072 Lisp_Object yesval, Lisp_Object noval,
4073 BOOL is_float, BOOL is_modstring)
4074 /* --------------------------------------------------------------------------
4075 Check a parameter value in user's preferences
4076 -------------------------------------------------------------------------- */
4078 const char *value = ns_get_defaults_value (parameter);
4084 if (c_strcasecmp (value, "YES") == 0)
4086 else if (c_strcasecmp (value, "NO") == 0)
4088 else if (is_float && (f = strtod (value, &pos), pos != value))
4089 *result = make_float (f);
4090 else if (is_modstring && value)
4091 *result = ns_string_to_lispmod (value);
4092 else fprintf (stderr,
4093 "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4099 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4100 /* --------------------------------------------------------------------------
4101 Initialize global info and storage for display.
4102 -------------------------------------------------------------------------- */
4104 NSScreen *screen = [NSScreen mainScreen];
4105 NSWindowDepth depth = [screen depth];
4107 dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4108 dpyinfo->resy = 72.27;
4109 dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4110 NSColorSpaceFromDepth (depth)]
4111 && ![NSCalibratedWhiteColorSpace isEqualToString:
4112 NSColorSpaceFromDepth (depth)];
4113 dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4114 dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4115 dpyinfo->color_table->colors = NULL;
4116 dpyinfo->root_window = 42; /* a placeholder.. */
4117 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4118 dpyinfo->n_fonts = 0;
4119 dpyinfo->smallest_font_height = 1;
4120 dpyinfo->smallest_char_width = 1;
4122 reset_mouse_highlight (&dpyinfo->mouse_highlight);
4126 /* This and next define (many of the) public functions in this file. */
4127 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4128 with using despite presence in the "system dependent" redisplay
4129 interface. In addition, many of the ns_ methods have code that is
4130 shared with all terms, indicating need for further refactoring. */
4131 extern frame_parm_handler ns_frame_parm_handlers[];
4132 static struct redisplay_interface ns_redisplay_interface =
4134 ns_frame_parm_handlers,
4138 x_clear_end_of_line,
4140 ns_after_update_window_line,
4141 ns_update_window_begin,
4142 ns_update_window_end,
4143 0, /* flush_display */
4144 x_clear_window_mouse_face,
4145 x_get_glyph_overhangs,
4146 x_fix_overlapping_area,
4147 ns_draw_fringe_bitmap,
4148 0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4149 0, /* destroy_fringe_bitmap */
4150 ns_compute_glyph_string_overhangs,
4151 ns_draw_glyph_string,
4152 ns_define_frame_cursor,
4153 ns_clear_frame_area,
4154 ns_draw_window_cursor,
4155 ns_draw_vertical_window_border,
4156 ns_draw_window_divider,
4157 ns_shift_glyphs_for_insert,
4164 ns_delete_display (struct ns_display_info *dpyinfo)
4170 /* This function is called when the last frame on a display is deleted. */
4172 ns_delete_terminal (struct terminal *terminal)
4174 struct ns_display_info *dpyinfo = terminal->display_info.ns;
4176 /* Protect against recursive calls. delete_frame in
4177 delete_terminal calls us back when it deletes our last frame. */
4178 if (!terminal->name)
4183 x_destroy_all_bitmaps (dpyinfo);
4184 ns_delete_display (dpyinfo);
4189 static struct terminal *
4190 ns_create_terminal (struct ns_display_info *dpyinfo)
4191 /* --------------------------------------------------------------------------
4192 Set up use of NS before we make the first connection.
4193 -------------------------------------------------------------------------- */
4195 struct terminal *terminal;
4197 NSTRACE (ns_create_terminal);
4199 terminal = create_terminal (output_ns, &ns_redisplay_interface);
4201 terminal->display_info.ns = dpyinfo;
4202 dpyinfo->terminal = terminal;
4204 terminal->clear_frame_hook = ns_clear_frame;
4205 terminal->ring_bell_hook = ns_ring_bell;
4206 terminal->update_begin_hook = ns_update_begin;
4207 terminal->update_end_hook = ns_update_end;
4208 terminal->read_socket_hook = ns_read_socket;
4209 terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4210 terminal->mouse_position_hook = ns_mouse_position;
4211 terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4212 terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4213 terminal->fullscreen_hook = ns_fullscreen_hook;
4214 terminal->menu_show_hook = ns_menu_show;
4215 terminal->popup_dialog_hook = ns_popup_dialog;
4216 terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4217 terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4218 terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4219 terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4220 terminal->delete_frame_hook = x_destroy_window;
4221 terminal->delete_terminal_hook = ns_delete_terminal;
4222 /* Other hooks are NULL by default. */
4228 struct ns_display_info *
4229 ns_term_init (Lisp_Object display_name)
4230 /* --------------------------------------------------------------------------
4231 Start the Application and get things rolling.
4232 -------------------------------------------------------------------------- */
4234 struct terminal *terminal;
4235 struct ns_display_info *dpyinfo;
4236 static int ns_initialized = 0;
4239 if (ns_initialized) return x_display_list;
4242 NSTRACE (ns_term_init);
4244 [outerpool release];
4245 outerpool = [[NSAutoreleasePool alloc] init];
4247 /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4248 /*GSDebugAllocationActive (YES); */
4252 Fset_input_interrupt_mode (Qnil);
4254 if (selfds[0] == -1)
4256 if (emacs_pipe (selfds) != 0)
4258 fprintf (stderr, "Failed to create pipe: %s\n",
4259 emacs_strerror (errno));
4263 fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4264 FD_ZERO (&select_readfds);
4265 FD_ZERO (&select_writefds);
4266 pthread_mutex_init (&select_mutex, NULL);
4269 ns_pending_files = [[NSMutableArray alloc] init];
4270 ns_pending_service_names = [[NSMutableArray alloc] init];
4271 ns_pending_service_args = [[NSMutableArray alloc] init];
4273 /* Start app and create the main menu, window, view.
4274 Needs to be here because ns_initialize_display_info () uses AppKit classes.
4275 The view will then ask the NSApp to stop and return to Emacs. */
4276 [EmacsApp sharedApplication];
4279 [NSApp setDelegate: NSApp];
4281 /* Start the select thread. */
4282 [NSThread detachNewThreadSelector:@selector (fd_handler:)
4286 /* debugging: log all notifications */
4287 /* [[NSNotificationCenter defaultCenter] addObserver: NSApp
4288 selector: @selector (logNotification:)
4289 name: nil object: nil]; */
4291 dpyinfo = xzalloc (sizeof *dpyinfo);
4293 ns_initialize_display_info (dpyinfo);
4294 terminal = ns_create_terminal (dpyinfo);
4296 terminal->kboard = allocate_kboard (Qns);
4297 /* Don't let the initial kboard remain current longer than necessary.
4298 That would cause problems if a file loaded on startup tries to
4299 prompt in the mini-buffer. */
4300 if (current_kboard == initial_kboard)
4301 current_kboard = terminal->kboard;
4302 terminal->kboard->reference_count++;
4304 dpyinfo->next = x_display_list;
4305 x_display_list = dpyinfo;
4307 dpyinfo->name_list_element = Fcons (display_name, Qnil);
4309 terminal->name = xstrdup (SSDATA (display_name));
4313 if (!inhibit_x_resources)
4315 ns_default ("GSFontAntiAlias", &ns_antialias_text,
4318 /* this is a standard variable */
4319 ns_default ("AppleAntiAliasingThreshold", &tmp,
4320 make_float (10.0), make_float (6.0), YES, NO);
4321 ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4325 NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4329 Lisp_Object color_file, color_map, color;
4333 color_file = Fexpand_file_name (build_string ("rgb.txt"),
4334 Fsymbol_value (intern ("data-directory")));
4336 color_map = Fx_load_color_file (color_file);
4337 if (NILP (color_map))
4338 fatal ("Could not read %s.\n", SDATA (color_file));
4340 cl = [[NSColorList alloc] initWithName: @"Emacs"];
4341 for ( ; CONSP (color_map); color_map = XCDR (color_map))
4343 color = XCAR (color_map);
4344 name = SSDATA (XCAR (color));
4345 c = XINT (XCDR (color));
4347 [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
4348 green: GREEN_FROM_ULONG (c) / 255.0
4349 blue: BLUE_FROM_ULONG (c) / 255.0
4351 forKey: [NSString stringWithUTF8String: name]];
4353 [cl writeToFile: nil];
4358 #ifdef NS_IMPL_GNUSTEP
4359 Vwindow_system_version = build_string (gnustep_base_version);
4361 /*PSnextrelease (128, c); */
4362 char c[DBL_BUFSIZE_BOUND];
4363 int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4364 Vwindow_system_version = make_unibyte_string (c, len);
4368 delete_keyboard_wait_descriptor (0);
4370 ns_app_name = [[NSProcessInfo processInfo] processName];
4372 /* Set up OS X app menu */
4373 #ifdef NS_IMPL_COCOA
4377 /* set up the application menu */
4378 svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4379 [svcsMenu setAutoenablesItems: NO];
4380 appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4381 [appMenu setAutoenablesItems: NO];
4382 mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4383 dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4385 [appMenu insertItemWithTitle: @"About Emacs"
4386 action: @selector (orderFrontStandardAboutPanel:)
4389 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4390 [appMenu insertItemWithTitle: @"Preferences..."
4391 action: @selector (showPreferencesWindow:)
4394 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4395 item = [appMenu insertItemWithTitle: @"Services"
4396 action: @selector (menuDown:)
4399 [appMenu setSubmenu: svcsMenu forItem: item];
4400 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4401 [appMenu insertItemWithTitle: @"Hide Emacs"
4402 action: @selector (hide:)
4405 item = [appMenu insertItemWithTitle: @"Hide Others"
4406 action: @selector (hideOtherApplications:)
4409 [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4410 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4411 [appMenu insertItemWithTitle: @"Quit Emacs"
4412 action: @selector (terminate:)
4416 item = [mainMenu insertItemWithTitle: ns_app_name
4417 action: @selector (menuDown:)
4420 [mainMenu setSubmenu: appMenu forItem: item];
4421 [dockMenu insertItemWithTitle: @"New Frame"
4422 action: @selector (newFrame:)
4426 [NSApp setMainMenu: mainMenu];
4427 [NSApp setAppleMenu: appMenu];
4428 [NSApp setServicesMenu: svcsMenu];
4429 /* Needed at least on Cocoa, to get dock menu to show windows */
4430 [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4432 [[NSNotificationCenter defaultCenter]
4433 addObserver: mainMenu
4434 selector: @selector (trackingNotification:)
4435 name: NSMenuDidBeginTrackingNotification object: mainMenu];
4436 [[NSNotificationCenter defaultCenter]
4437 addObserver: mainMenu
4438 selector: @selector (trackingNotification:)
4439 name: NSMenuDidEndTrackingNotification object: mainMenu];
4441 #endif /* MAC OS X menu setup */
4443 /* Register our external input/output types, used for determining
4444 applicable services and also drag/drop eligibility. */
4445 ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4446 ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4448 ns_drag_types = [[NSArray arrayWithObjects:
4450 NSTabularTextPboardType,
4451 NSFilenamesPboardType,
4452 NSURLPboardType, nil] retain];
4454 /* If fullscreen is in init/default-frame-alist, focus isn't set
4455 right for fullscreen windows, so set this. */
4456 [NSApp activateIgnoringOtherApps:YES];
4459 ns_do_open_file = YES;
4461 #ifdef NS_IMPL_GNUSTEP
4462 /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
4463 We must re-catch it so subprocess works. */
4464 catch_child_signal ();
4471 ns_term_shutdown (int sig)
4473 [[NSUserDefaults standardUserDefaults] synchronize];
4475 /* code not reached in emacs.c after this is called by shut_down_emacs: */
4476 if (STRINGP (Vauto_save_list_file_name))
4477 unlink (SSDATA (Vauto_save_list_file_name));
4479 if (sig == 0 || sig == SIGTERM)
4481 [NSApp terminate: NSApp];
4483 else // force a stack trace to happen
4490 /* ==========================================================================
4492 EmacsApp implementation
4494 ========================================================================== */
4497 @implementation EmacsApp
4501 if (self = [super init])
4503 #ifdef NS_IMPL_COCOA
4504 self->isFirst = YES;
4506 #ifdef NS_IMPL_GNUSTEP
4507 self->applicationDidFinishLaunchingCalled = NO;
4514 #ifdef NS_IMPL_COCOA
4517 #ifndef NSAppKitVersionNumber10_8
4518 #define NSAppKitVersionNumber10_8 1187
4521 if (NSAppKitVersionNumber <= NSAppKitVersionNumber10_8)
4527 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4529 if (isFirst) [self finishLaunching];
4532 shouldKeepRunning = YES;
4536 pool = [[NSAutoreleasePool alloc] init];
4539 [self nextEventMatchingMask:NSAnyEventMask
4540 untilDate:[NSDate distantFuture]
4541 inMode:NSDefaultRunLoopMode
4543 [self sendEvent:event];
4544 [self updateWindows];
4545 } while (shouldKeepRunning);
4550 - (void)stop: (id)sender
4552 shouldKeepRunning = NO;
4553 // Stop possible dialog also. Noop if no dialog present.
4554 // The file dialog still leaks 7k - 10k on 10.9 though.
4555 [super stop:sender];
4557 #endif /* NS_IMPL_COCOA */
4559 - (void)logNotification: (NSNotification *)notification
4561 const char *name = [[notification name] UTF8String];
4562 if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4563 && !strstr (name, "WindowNumber"))
4564 NSLog (@"notification: '%@'", [notification name]);
4568 - (void)sendEvent: (NSEvent *)theEvent
4569 /* --------------------------------------------------------------------------
4570 Called when NSApp is running for each event received. Used to stop
4571 the loop when we choose, since there's no way to just run one iteration.
4572 -------------------------------------------------------------------------- */
4574 int type = [theEvent type];
4575 NSWindow *window = [theEvent window];
4577 /* NSTRACE (sendEvent); */
4578 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4580 #ifdef NS_IMPL_GNUSTEP
4581 // Keyboard events aren't propagated to file dialogs for some reason.
4582 if ([NSApp modalWindow] != nil &&
4583 (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
4585 [[NSApp modalWindow] sendEvent: theEvent];
4590 if (type == NSApplicationDefined)
4592 switch ([theEvent data2])
4594 #ifdef NS_IMPL_COCOA
4595 case NSAPP_DATA2_RUNASSCRIPT:
4600 case NSAPP_DATA2_RUNFILEDIALOG:
4601 ns_run_file_dialog ();
4607 if (type == NSCursorUpdate && window == nil)
4609 fprintf (stderr, "Dropping external cursor update event.\n");
4613 if (type == NSApplicationDefined)
4615 /* Events posted by ns_send_appdefined interrupt the run loop here.
4616 But, if a modal window is up, an appdefined can still come through,
4617 (e.g., from a makeKeyWindow event) but stopping self also stops the
4618 modal loop. Just defer it until later. */
4619 if ([NSApp modalWindow] == nil)
4621 last_appdefined_event_data = [theEvent data1];
4626 send_appdefined = YES;
4631 #ifdef NS_IMPL_COCOA
4632 /* If no dialog and none of our frames have focus and it is a move, skip it.
4633 It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
4634 such as Wifi, sound, date or similar.
4635 This prevents "spooky" highlighting in the frame under the menu. */
4636 if (type == NSMouseMoved && [NSApp modalWindow] == nil)
4638 struct ns_display_info *di;
4639 BOOL has_focus = NO;
4640 for (di = x_display_list; ! has_focus && di; di = di->next)
4641 has_focus = di->x_focus_frame != 0;
4647 [super sendEvent: theEvent];
4651 - (void)showPreferencesWindow: (id)sender
4653 struct frame *emacsframe = SELECTED_FRAME ();
4654 NSEvent *theEvent = [NSApp currentEvent];
4658 emacs_event->kind = NS_NONKEY_EVENT;
4659 emacs_event->code = KEY_NS_SHOW_PREFS;
4660 emacs_event->modifiers = 0;
4661 EV_TRAILER (theEvent);
4665 - (void)newFrame: (id)sender
4667 struct frame *emacsframe = SELECTED_FRAME ();
4668 NSEvent *theEvent = [NSApp currentEvent];
4672 emacs_event->kind = NS_NONKEY_EVENT;
4673 emacs_event->code = KEY_NS_NEW_FRAME;
4674 emacs_event->modifiers = 0;
4675 EV_TRAILER (theEvent);
4679 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4680 - (BOOL) openFile: (NSString *)fileName
4682 struct frame *emacsframe = SELECTED_FRAME ();
4683 NSEvent *theEvent = [NSApp currentEvent];
4688 emacs_event->kind = NS_NONKEY_EVENT;
4689 emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4690 ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4691 ns_input_line = Qnil; /* can be start or cons start,end */
4692 emacs_event->modifiers =0;
4693 EV_TRAILER (theEvent);
4699 /* **************************************************************************
4701 EmacsApp delegate implementation
4703 ************************************************************************** */
4705 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4706 /* --------------------------------------------------------------------------
4707 When application is loaded, terminate event loop in ns_term_init
4708 -------------------------------------------------------------------------- */
4710 NSTRACE (applicationDidFinishLaunching);
4711 #ifdef NS_IMPL_GNUSTEP
4712 ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
4714 [NSApp setServicesProvider: NSApp];
4716 [self antialiasThresholdDidChange:nil];
4717 #ifdef NS_IMPL_COCOA
4718 [[NSNotificationCenter defaultCenter]
4720 selector:@selector(antialiasThresholdDidChange:)
4721 name:NSAntialiasThresholdChangedNotification
4725 ns_send_appdefined (-2);
4728 - (void)antialiasThresholdDidChange:(NSNotification *)notification
4730 #ifdef NS_IMPL_COCOA
4731 macfont_update_antialias_threshold ();
4736 /* Termination sequences:
4739 MenuBar | File | Exit:
4740 Select Quit from App menubar:
4742 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4745 Select Quit from Dock menu:
4748 Cancel -> Nothing else
4752 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4757 - (void) terminate: (id)sender
4759 struct frame *emacsframe = SELECTED_FRAME ();
4764 emacs_event->kind = NS_NONKEY_EVENT;
4765 emacs_event->code = KEY_NS_POWER_OFF;
4766 emacs_event->arg = Qt; /* mark as non-key event */
4767 EV_TRAILER ((id)nil);
4771 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4775 if (NILP (ns_confirm_quit)) // || ns_shutdown_properly --> TO DO
4776 return NSTerminateNow;
4778 ret = NSRunAlertPanel(ns_app_name,
4779 @"Exit requested. Would you like to Save Buffers and Exit, or Cancel the request?",
4780 @"Save Buffers and Exit", @"Cancel", nil);
4782 if (ret == NSAlertDefaultReturn)
4783 return NSTerminateNow;
4784 else if (ret == NSAlertAlternateReturn)
4785 return NSTerminateCancel;
4786 return NSTerminateNow; /* just in case */
4790 not_in_argv (NSString *arg)
4793 const char *a = [arg UTF8String];
4794 for (k = 1; k < initial_argc; ++k)
4795 if (strcmp (a, initial_argv[k]) == 0) return 0;
4799 /* Notification from the Workspace to open a file */
4800 - (BOOL)application: sender openFile: (NSString *)file
4802 if (ns_do_open_file || not_in_argv (file))
4803 [ns_pending_files addObject: file];
4808 /* Open a file as a temporary file */
4809 - (BOOL)application: sender openTempFile: (NSString *)file
4811 if (ns_do_open_file || not_in_argv (file))
4812 [ns_pending_files addObject: file];
4817 /* Notification from the Workspace to open a file noninteractively (?) */
4818 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4820 if (ns_do_open_file || not_in_argv (file))
4821 [ns_pending_files addObject: file];
4825 /* Notification from the Workspace to open multiple files */
4826 - (void)application: sender openFiles: (NSArray *)fileList
4828 NSEnumerator *files = [fileList objectEnumerator];
4830 /* Don't open files from the command line unconditionally,
4831 Cocoa parses the command line wrong, --option value tries to open value
4832 if --option is the last option. */
4833 while ((file = [files nextObject]) != nil)
4834 if (ns_do_open_file || not_in_argv (file))
4835 [ns_pending_files addObject: file];
4837 [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4842 /* Handle dock menu requests. */
4843 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4849 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4850 - (void)applicationWillBecomeActive: (NSNotification *)notification
4852 //ns_app_active=YES;
4854 - (void)applicationDidBecomeActive: (NSNotification *)notification
4856 NSTRACE (applicationDidBecomeActive);
4858 #ifdef NS_IMPL_GNUSTEP
4859 if (! applicationDidFinishLaunchingCalled)
4860 [self applicationDidFinishLaunching:notification];
4862 //ns_app_active=YES;
4864 ns_update_auto_hide_menu_bar ();
4865 // No constraining takes place when the application is not active.
4866 ns_constrain_all_frames ();
4868 - (void)applicationDidResignActive: (NSNotification *)notification
4871 ns_send_appdefined (-1);
4876 /* ==========================================================================
4878 EmacsApp aux handlers for managing event loop
4880 ========================================================================== */
4883 - (void)timeout_handler: (NSTimer *)timedEntry
4884 /* --------------------------------------------------------------------------
4885 The timeout specified to ns_select has passed.
4886 -------------------------------------------------------------------------- */
4888 /*NSTRACE (timeout_handler); */
4889 ns_send_appdefined (-2);
4892 #ifdef NS_IMPL_GNUSTEP
4893 - (void)sendFromMainThread:(id)unused
4895 ns_send_appdefined (nextappdefined);
4899 - (void)fd_handler:(id)unused
4900 /* --------------------------------------------------------------------------
4901 Check data waiting on file descriptors and terminate if so
4902 -------------------------------------------------------------------------- */
4905 int waiting = 1, nfds;
4908 fd_set readfds, writefds, *wfds;
4909 struct timespec timeout, *tmo;
4910 NSAutoreleasePool *pool = nil;
4912 /* NSTRACE (fd_handler); */
4917 pool = [[NSAutoreleasePool alloc] init];
4923 FD_SET (selfds[0], &fds);
4924 result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
4925 if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
4930 pthread_mutex_lock (&select_mutex);
4933 if (select_valid & SELECT_HAVE_READ)
4934 readfds = select_readfds;
4938 if (select_valid & SELECT_HAVE_WRITE)
4940 writefds = select_writefds;
4945 if (select_valid & SELECT_HAVE_TMO)
4947 timeout = select_timeout;
4953 pthread_mutex_unlock (&select_mutex);
4955 FD_SET (selfds[0], &readfds);
4956 if (selfds[0] >= nfds) nfds = selfds[0]+1;
4958 result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
4961 ns_send_appdefined (-2);
4962 else if (result > 0)
4964 if (FD_ISSET (selfds[0], &readfds))
4966 if (read (selfds[0], &c, 1) == 1 && c == 's')
4971 pthread_mutex_lock (&select_mutex);
4972 if (select_valid & SELECT_HAVE_READ)
4973 select_readfds = readfds;
4974 if (select_valid & SELECT_HAVE_WRITE)
4975 select_writefds = writefds;
4976 if (select_valid & SELECT_HAVE_TMO)
4977 select_timeout = timeout;
4978 pthread_mutex_unlock (&select_mutex);
4980 ns_send_appdefined (result);
4990 /* ==========================================================================
4994 ========================================================================== */
4996 /* called from system: queue for next pass through event loop */
4997 - (void)requestService: (NSPasteboard *)pboard
4998 userData: (NSString *)userData
4999 error: (NSString **)error
5001 [ns_pending_service_names addObject: userData];
5002 [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5003 SSDATA (ns_string_from_pasteboard (pboard))]];
5007 /* called from ns_read_socket to clear queue */
5008 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5010 struct frame *emacsframe = SELECTED_FRAME ();
5011 NSEvent *theEvent = [NSApp currentEvent];
5016 emacs_event->kind = NS_NONKEY_EVENT;
5017 emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5018 ns_input_spi_name = build_string ([name UTF8String]);
5019 ns_input_spi_arg = build_string ([arg UTF8String]);
5020 emacs_event->modifiers = EV_MODIFIERS (theEvent);
5021 EV_TRAILER (theEvent);
5031 /* ==========================================================================
5033 EmacsView implementation
5035 ========================================================================== */
5038 @implementation EmacsView
5040 /* needed to inform when window closed from LISP */
5041 - (void) setWindowClosing: (BOOL)closing
5043 windowClosing = closing;
5049 NSTRACE (EmacsView_dealloc);
5051 if (fs_state == FULLSCREEN_BOTH)
5052 [nonfs_window release];
5057 /* called on font panel selection */
5058 - (void)changeFont: (id)sender
5060 NSEvent *e = [[self window] currentEvent];
5061 struct face *face = FRAME_DEFAULT_FACE (emacsframe);
5062 struct font *font = face->font;
5067 NSTRACE (changeFont);
5072 #ifdef NS_IMPL_GNUSTEP
5073 nsfont = ((struct nsfont_info *)font)->nsfont;
5075 #ifdef NS_IMPL_COCOA
5076 nsfont = (NSFont *) macfont_get_nsctfont (font);
5079 if ((newFont = [sender convertFont: nsfont]))
5081 SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5083 emacs_event->kind = NS_NONKEY_EVENT;
5084 emacs_event->modifiers = 0;
5085 emacs_event->code = KEY_NS_CHANGE_FONT;
5087 size = [newFont pointSize];
5088 ns_input_fontsize = make_number (lrint (size));
5089 ns_input_font = build_string ([[newFont familyName] UTF8String]);
5095 - (BOOL)acceptsFirstResponder
5097 NSTRACE (acceptsFirstResponder);
5102 - (void)resetCursorRects
5104 NSRect visible = [self visibleRect];
5105 NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5106 NSTRACE (resetCursorRects);
5108 if (currentCursor == nil)
5109 currentCursor = [NSCursor arrowCursor];
5111 if (!NSIsEmptyRect (visible))
5112 [self addCursorRect: visible cursor: currentCursor];
5113 [currentCursor setOnMouseEntered: YES];
5118 /*****************************************************************************/
5119 /* Keyboard handling. */
5122 - (void)keyDown: (NSEvent *)theEvent
5124 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5126 unsigned fnKeysym = 0;
5127 static NSMutableArray *nsEvArray;
5128 #ifdef NS_IMPL_GNUSTEP
5129 static BOOL firstTime = YES;
5132 unsigned int flags = [theEvent modifierFlags];
5136 /* Rhapsody and OS X give up and down events for the arrow keys */
5137 if (ns_fake_keydown == YES)
5138 ns_fake_keydown = NO;
5139 else if ([theEvent type] != NSKeyDown)
5145 if (![[self window] isKeyWindow]
5146 && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5147 /* we must avoid an infinite loop here. */
5148 && (EmacsView *)[[theEvent window] delegate] != self)
5150 /* XXX: There is an occasional condition in which, when Emacs display
5151 updates a different frame from the current one, and temporarily
5152 selects it, then processes some interrupt-driven input
5153 (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5154 for some reason that window has its first responder set to the NSView
5155 most recently updated (I guess), which is not the correct one. */
5156 [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5160 if (nsEvArray == nil)
5161 nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5163 [NSCursor setHiddenUntilMouseMoves: YES];
5165 if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5167 clear_mouse_face (hlinfo);
5168 hlinfo->mouse_face_hidden = 1;
5171 if (!processingCompose)
5173 /* When using screen sharing, no left or right information is sent,
5174 so use Left key in those cases. */
5175 int is_left_key, is_right_key;
5177 code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5178 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5180 /* (Carbon way: [theEvent keyCode]) */
5182 /* is it a "function key"? */
5183 /* Note: Sometimes a plain key will have the NSNumericPadKeyMask
5184 flag set (this is probably a bug in the OS).
5186 if (code < 0x00ff && (flags&NSNumericPadKeyMask))
5188 fnKeysym = ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask);
5192 fnKeysym = ns_convert_key (code);
5197 /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5198 because Emacs treats Delete and KP-Delete same (in simple.el). */
5199 if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5200 #ifdef NS_IMPL_GNUSTEP
5201 /* GNUstep uses incompatible keycodes, even for those that are
5202 supposed to be hardware independent. Just check for delete.
5203 Keypad delete does not have keysym 0xFFFF.
5204 See http://savannah.gnu.org/bugs/?25395
5206 || (fnKeysym == 0xFFFF && code == 127)
5209 code = 0xFF08; /* backspace */
5214 /* are there modifiers? */
5215 emacs_event->modifiers = 0;
5217 if (flags & NSHelpKeyMask)
5218 emacs_event->modifiers |= hyper_modifier;
5220 if (flags & NSShiftKeyMask)
5221 emacs_event->modifiers |= shift_modifier;
5223 is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5224 is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5225 || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
5228 emacs_event->modifiers |= parse_solitary_modifier
5229 (EQ (ns_right_command_modifier, Qleft)
5230 ? ns_command_modifier
5231 : ns_right_command_modifier);
5235 emacs_event->modifiers |= parse_solitary_modifier
5236 (ns_command_modifier);
5238 /* if super (default), take input manager's word so things like
5239 dvorak / qwerty layout work */
5240 if (EQ (ns_command_modifier, Qsuper)
5242 && [[theEvent characters] length] != 0)
5244 /* XXX: the code we get will be unshifted, so if we have
5245 a shift modifier, must convert ourselves */
5246 if (!(flags & NSShiftKeyMask))
5247 code = [[theEvent characters] characterAtIndex: 0];
5249 /* this is ugly and also requires linking w/Carbon framework
5250 (for LMGetKbdType) so for now leave this rare (?) case
5251 undealt with.. in future look into CGEvent methods */
5254 long smv = GetScriptManagerVariable (smKeyScript);
5255 Handle uchrHandle = GetResource
5256 ('uchr', GetScriptVariable (smv, smScriptKeys));
5258 UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5259 [[theEvent characters] characterAtIndex: 0],
5260 kUCKeyActionDisplay,
5261 (flags & ~NSCommandKeyMask) >> 8,
5262 LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5263 &dummy, 1, &dummy, &code);
5270 is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5271 is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5272 || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5275 emacs_event->modifiers |= parse_solitary_modifier
5276 (EQ (ns_right_control_modifier, Qleft)
5277 ? ns_control_modifier
5278 : ns_right_control_modifier);
5281 emacs_event->modifiers |= parse_solitary_modifier
5282 (ns_control_modifier);
5284 if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5285 emacs_event->modifiers |=
5286 parse_solitary_modifier (ns_function_modifier);
5288 left_is_none = NILP (ns_alternate_modifier)
5289 || EQ (ns_alternate_modifier, Qnone);
5291 is_right_key = (flags & NSRightAlternateKeyMask)
5292 == NSRightAlternateKeyMask;
5293 is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5295 && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5299 if ((NILP (ns_right_alternate_modifier)
5300 || EQ (ns_right_alternate_modifier, Qnone)
5301 || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5303 { /* accept pre-interp alt comb */
5304 if ([[theEvent characters] length] > 0)
5305 code = [[theEvent characters] characterAtIndex: 0];
5306 /*HACK: clear lone shift modifier to stop next if from firing */
5307 if (emacs_event->modifiers == shift_modifier)
5308 emacs_event->modifiers = 0;
5311 emacs_event->modifiers |= parse_solitary_modifier
5312 (EQ (ns_right_alternate_modifier, Qleft)
5313 ? ns_alternate_modifier
5314 : ns_right_alternate_modifier);
5317 if (is_left_key) /* default = meta */
5319 if (left_is_none && !fnKeysym)
5320 { /* accept pre-interp alt comb */
5321 if ([[theEvent characters] length] > 0)
5322 code = [[theEvent characters] characterAtIndex: 0];
5323 /*HACK: clear lone shift modifier to stop next if from firing */
5324 if (emacs_event->modifiers == shift_modifier)
5325 emacs_event->modifiers = 0;
5328 emacs_event->modifiers |=
5329 parse_solitary_modifier (ns_alternate_modifier);
5333 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5334 code, fnKeysym, flags, emacs_event->modifiers);
5336 /* if it was a function key or had modifiers, pass it directly to emacs */
5337 if (fnKeysym || (emacs_event->modifiers
5338 && (emacs_event->modifiers != shift_modifier)
5339 && [[theEvent charactersIgnoringModifiers] length] > 0))
5340 /*[[theEvent characters] length] */
5342 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5344 code |= (1<<28)|(3<<16);
5345 else if (code == 0x7f)
5346 code |= (1<<28)|(3<<16);
5348 emacs_event->kind = code > 0xFF
5349 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5351 emacs_event->code = code;
5352 EV_TRAILER (theEvent);
5353 processingCompose = NO;
5359 #ifdef NS_IMPL_GNUSTEP
5360 /* if we get here we should send the key for input manager processing */
5361 /* Disable warning, there is nothing a user can do about it anyway, and
5362 it does not seem to matter. */
5364 if (firstTime && [[NSInputManager currentInputManager]
5365 wantsToDelayTextChangeNotifications] == NO)
5367 "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
5371 if (NS_KEYLOG && !processingCompose)
5372 fprintf (stderr, "keyDown: Begin compose sequence.\n");
5374 processingCompose = YES;
5375 [nsEvArray addObject: theEvent];
5376 [self interpretKeyEvents: nsEvArray];
5377 [nsEvArray removeObject: theEvent];
5381 #ifdef NS_IMPL_COCOA
5382 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5383 decided not to send key-down for.
5384 See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5385 This only applies on Tiger and earlier.
5386 If it matches one of these, send it on to keyDown. */
5387 -(void)keyUp: (NSEvent *)theEvent
5389 int flags = [theEvent modifierFlags];
5390 int code = [theEvent keyCode];
5391 if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5392 code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5395 fprintf (stderr, "keyUp: passed test");
5396 ns_fake_keydown = YES;
5397 [self keyDown: theEvent];
5403 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5406 /* <NSTextInput>: called when done composing;
5407 NOTE: also called when we delete over working text, followed immed.
5408 by doCommandBySelector: deleteBackward: */
5409 - (void)insertText: (id)aString
5412 int len = [(NSString *)aString length];
5416 NSLog (@"insertText '%@'\tlen = %d", aString, len);
5417 processingCompose = NO;
5422 /* first, clear any working text */
5423 if (workingText != nil)
5424 [self deleteWorkingText];
5426 /* now insert the string as keystrokes */
5427 for (i =0; i<len; i++)
5429 code = [aString characterAtIndex: i];
5430 /* TODO: still need this? */
5432 code = '~'; /* 0x7E */
5433 if (code != 32) /* Space */
5434 emacs_event->modifiers = 0;
5436 = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5437 emacs_event->code = code;
5438 EV_TRAILER ((id)nil);
5443 /* <NSTextInput>: inserts display of composing characters */
5444 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5446 NSString *str = [aString respondsToSelector: @selector (string)] ?
5447 [aString string] : aString;
5449 NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
5450 str, (unsigned long)[str length],
5451 (unsigned long)selRange.length,
5452 (unsigned long)selRange.location);
5454 if (workingText != nil)
5455 [self deleteWorkingText];
5456 if ([str length] == 0)
5462 processingCompose = YES;
5463 workingText = [str copy];
5464 ns_working_text = build_string ([workingText UTF8String]);
5466 emacs_event->kind = NS_TEXT_EVENT;
5467 emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5468 EV_TRAILER ((id)nil);
5472 /* delete display of composing characters [not in <NSTextInput>] */
5473 - (void)deleteWorkingText
5475 if (workingText == nil)
5478 NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
5479 [workingText release];
5481 processingCompose = NO;
5486 emacs_event->kind = NS_TEXT_EVENT;
5487 emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5488 EV_TRAILER ((id)nil);
5492 - (BOOL)hasMarkedText
5494 return workingText != nil;
5498 - (NSRange)markedRange
5500 NSRange rng = workingText != nil
5501 ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5503 NSLog (@"markedRange request");
5511 NSLog (@"unmark (accept) text");
5512 [self deleteWorkingText];
5513 processingCompose = NO;
5517 /* used to position char selection windows, etc. */
5518 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5522 struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5524 NSLog (@"firstRectForCharRange request");
5526 rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5527 rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5528 pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5529 pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5530 +FRAME_LINE_HEIGHT (emacsframe));
5532 pt = [self convertPoint: pt toView: nil];
5533 pt = [[self window] convertBaseToScreen: pt];
5539 - (NSInteger)conversationIdentifier
5541 return (NSInteger)self;
5545 - (void)doCommandBySelector: (SEL)aSelector
5548 NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5550 processingCompose = NO;
5551 if (aSelector == @selector (deleteBackward:))
5553 /* happens when user backspaces over an ongoing composition:
5554 throw a 'delete' into the event queue */
5557 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5558 emacs_event->code = 0xFF08;
5559 EV_TRAILER ((id)nil);
5563 - (NSArray *)validAttributesForMarkedText
5565 static NSArray *arr = nil;
5566 if (arr == nil) arr = [NSArray new];
5567 /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5571 - (NSRange)selectedRange
5574 NSLog (@"selectedRange request");
5575 return NSMakeRange (NSNotFound, 0);
5578 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
5579 GNUSTEP_GUI_MINOR_VERSION > 22
5580 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5582 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
5586 NSLog (@"characterIndexForPoint request");
5590 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5592 static NSAttributedString *str = nil;
5593 if (str == nil) str = [NSAttributedString new];
5595 NSLog (@"attributedSubstringFromRange request");
5599 /* End <NSTextInput> impl. */
5600 /*****************************************************************************/
5603 /* This is what happens when the user presses a mouse button. */
5604 - (void)mouseDown: (NSEvent *)theEvent
5606 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5607 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5609 NSTRACE (mouseDown);
5611 [self deleteWorkingText];
5616 dpyinfo->last_mouse_frame = emacsframe;
5617 /* appears to be needed to prevent spurious movement events generated on
5619 emacsframe->mouse_moved = 0;
5621 if ([theEvent type] == NSScrollWheel)
5623 CGFloat delta = [theEvent deltaY];
5624 /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5627 delta = [theEvent deltaX];
5630 NSTRACE (deltaIsZero);
5633 emacs_event->kind = HORIZ_WHEEL_EVENT;
5636 emacs_event->kind = WHEEL_EVENT;
5638 emacs_event->code = 0;
5639 emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5640 ((delta > 0) ? up_modifier : down_modifier);
5644 emacs_event->kind = MOUSE_CLICK_EVENT;
5645 emacs_event->code = EV_BUTTON (theEvent);
5646 emacs_event->modifiers = EV_MODIFIERS (theEvent)
5647 | EV_UDMODIFIERS (theEvent);
5649 XSETINT (emacs_event->x, lrint (p.x));
5650 XSETINT (emacs_event->y, lrint (p.y));
5651 EV_TRAILER (theEvent);
5655 - (void)rightMouseDown: (NSEvent *)theEvent
5657 NSTRACE (rightMouseDown);
5658 [self mouseDown: theEvent];
5662 - (void)otherMouseDown: (NSEvent *)theEvent
5664 NSTRACE (otherMouseDown);
5665 [self mouseDown: theEvent];
5669 - (void)mouseUp: (NSEvent *)theEvent
5672 [self mouseDown: theEvent];
5676 - (void)rightMouseUp: (NSEvent *)theEvent
5678 NSTRACE (rightMouseUp);
5679 [self mouseDown: theEvent];
5683 - (void)otherMouseUp: (NSEvent *)theEvent
5685 NSTRACE (otherMouseUp);
5686 [self mouseDown: theEvent];
5690 - (void) scrollWheel: (NSEvent *)theEvent
5692 NSTRACE (scrollWheel);
5693 [self mouseDown: theEvent];
5697 /* Tell emacs the mouse has moved. */
5698 - (void)mouseMoved: (NSEvent *)e
5700 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5701 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5705 // NSTRACE (mouseMoved);
5707 dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
5708 pt = [self convertPoint: [e locationInWindow] fromView: nil];
5709 dpyinfo->last_mouse_motion_x = pt.x;
5710 dpyinfo->last_mouse_motion_y = pt.y;
5712 /* update any mouse face */
5713 if (hlinfo->mouse_face_hidden)
5715 hlinfo->mouse_face_hidden = 0;
5716 clear_mouse_face (hlinfo);
5719 /* tooltip handling */
5720 previous_help_echo_string = help_echo_string;
5721 help_echo_string = Qnil;
5723 if (!NILP (Vmouse_autoselect_window))
5725 NSTRACE (mouse_autoselect_window);
5726 static Lisp_Object last_mouse_window;
5728 = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
5730 if (WINDOWP (window)
5731 && !EQ (window, last_mouse_window)
5732 && !EQ (window, selected_window)
5733 && (focus_follows_mouse
5734 || (EQ (XWINDOW (window)->frame,
5735 XWINDOW (selected_window)->frame))))
5737 NSTRACE (in_window);
5738 emacs_event->kind = SELECT_WINDOW_EVENT;
5739 emacs_event->frame_or_window = window;
5742 /* Remember the last window where we saw the mouse. */
5743 last_mouse_window = window;
5746 if (!note_mouse_movement (emacsframe, pt.x, pt.y))
5747 help_echo_string = previous_help_echo_string;
5749 XSETFRAME (frame, emacsframe);
5750 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5752 /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5753 (note_mouse_highlight), which is called through the
5754 note_mouse_movement () call above */
5755 any_help_event_p = YES;
5756 gen_help_event (help_echo_string, frame, help_echo_window,
5757 help_echo_object, help_echo_pos);
5760 if (emacsframe->mouse_moved && send_appdefined)
5761 ns_send_appdefined (-1);
5765 - (void)mouseDragged: (NSEvent *)e
5767 NSTRACE (mouseDragged);
5768 [self mouseMoved: e];
5772 - (void)rightMouseDragged: (NSEvent *)e
5774 NSTRACE (rightMouseDragged);
5775 [self mouseMoved: e];
5779 - (void)otherMouseDragged: (NSEvent *)e
5781 NSTRACE (otherMouseDragged);
5782 [self mouseMoved: e];
5786 - (BOOL)windowShouldClose: (id)sender
5788 NSEvent *e =[[self window] currentEvent];
5790 NSTRACE (windowShouldClose);
5791 windowClosing = YES;
5794 emacs_event->kind = DELETE_WINDOW_EVENT;
5795 emacs_event->modifiers = 0;
5796 emacs_event->code = 0;
5798 /* Don't close this window, let this be done from lisp code. */
5802 - (void) updateFrameSize: (BOOL) delay;
5804 NSWindow *window = [self window];
5805 NSRect wr = [window frame];
5807 int oldc = cols, oldr = rows;
5808 int oldw = FRAME_PIXEL_WIDTH (emacsframe);
5809 int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5812 NSTRACE (updateFrameSize);
5813 NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
5815 if (! [self isFullscreen])
5817 #ifdef NS_IMPL_GNUSTEP
5818 // GNUstep does not always update the tool bar height. Force it.
5819 if (toolbar && [toolbar isVisible])
5820 update_frame_tool_bar (emacsframe);
5823 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5824 + FRAME_TOOLBAR_HEIGHT (emacsframe);
5827 if (wait_for_tool_bar)
5829 if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0)
5831 wait_for_tool_bar = NO;
5834 neww = (int)wr.size.width - emacsframe->border_width;
5835 newh = (int)wr.size.height - extra;
5837 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
5838 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
5840 if (cols < MINWIDTH)
5843 if (rows < MINHEIGHT)
5846 if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5848 NSView *view = FRAME_NS_VIEW (emacsframe);
5849 NSWindow *win = [view window];
5850 NSSize sz = [win resizeIncrements];
5852 change_frame_size (emacsframe,
5853 FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
5854 FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
5856 SET_FRAME_GARBAGED (emacsframe);
5857 cancel_mouse_face (emacsframe);
5859 // Did resize increments change because of a font change?
5860 if (sz.width != FRAME_COLUMN_WIDTH (emacsframe) ||
5861 sz.height != FRAME_LINE_HEIGHT (emacsframe) ||
5862 (frame_resize_pixelwise && sz.width != 1))
5864 sz.width = frame_resize_pixelwise
5865 ? 1 : FRAME_COLUMN_WIDTH (emacsframe);
5866 sz.height = frame_resize_pixelwise
5867 ? 1 : FRAME_LINE_HEIGHT (emacsframe);
5868 [win setResizeIncrements: sz];
5870 NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
5873 [view setFrame: NSMakeRect (0, 0, neww, newh)];
5874 [self windowDidMove:nil]; // Update top/left.
5878 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5879 /* normalize frame to gridded text size */
5883 NSTRACE (windowWillResize);
5884 NSTRACE_SIZE ("Original size", frameSize);
5885 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5887 if (fs_state == FULLSCREEN_MAXIMIZED
5888 && (maximized_width != (int)frameSize.width
5889 || maximized_height != (int)frameSize.height))
5890 [self setFSValue: FULLSCREEN_NONE];
5891 else if (fs_state == FULLSCREEN_WIDTH
5892 && maximized_width != (int)frameSize.width)
5893 [self setFSValue: FULLSCREEN_NONE];
5894 else if (fs_state == FULLSCREEN_HEIGHT
5895 && maximized_height != (int)frameSize.height)
5896 [self setFSValue: FULLSCREEN_NONE];
5897 if (fs_state == FULLSCREEN_NONE)
5898 maximized_width = maximized_height = -1;
5900 if (! [self isFullscreen])
5902 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5903 + FRAME_TOOLBAR_HEIGHT (emacsframe);
5906 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
5907 if (cols < MINWIDTH)
5910 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
5911 frameSize.height - extra);
5912 if (rows < MINHEIGHT)
5914 #ifdef NS_IMPL_COCOA
5916 /* this sets window title to have size in it; the wm does this under GS */
5917 NSRect r = [[self window] frame];
5918 if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5926 else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
5929 NSWindow *window = [self window];
5932 char *t = strdup ([[[self window] title] UTF8String]);
5933 char *pos = strstr (t, " — ");
5938 size_title = xmalloc (strlen (old_title) + 40);
5939 esprintf (size_title, "%s — (%d x %d)", old_title, cols, rows);
5940 [window setTitle: [NSString stringWithUTF8String: size_title]];
5945 #endif /* NS_IMPL_COCOA */
5946 /*fprintf (stderr," ...size became %.0f x %.0f (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5952 - (void)windowDidResize: (NSNotification *)notification
5954 if (! [self fsIsNative])
5956 NSWindow *theWindow = [notification object];
5957 /* We can get notification on the non-FS window when in
5959 if ([self window] != theWindow) return;
5962 #ifdef NS_IMPL_GNUSTEP
5963 NSWindow *theWindow = [notification object];
5965 /* In GNUstep, at least currently, it's possible to get a didResize
5966 without getting a willResize.. therefore we need to act as if we got
5967 the willResize now */
5968 NSSize sz = [theWindow frame].size;
5969 sz = [self windowWillResize: theWindow toSize: sz];
5970 #endif /* NS_IMPL_GNUSTEP */
5972 NSTRACE (windowDidResize);
5973 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5975 if (cols > 0 && rows > 0)
5977 [self updateFrameSize: YES];
5980 ns_send_appdefined (-1);
5983 #ifdef NS_IMPL_COCOA
5984 - (void)viewDidEndLiveResize
5986 [super viewDidEndLiveResize];
5989 [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
5993 maximizing_resize = NO;
5995 #endif /* NS_IMPL_COCOA */
5998 - (void)windowDidBecomeKey: (NSNotification *)notification
5999 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6001 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6002 struct frame *old_focus = dpyinfo->x_focus_frame;
6004 NSTRACE (windowDidBecomeKey);
6006 if (emacsframe != old_focus)
6007 dpyinfo->x_focus_frame = emacsframe;
6009 ns_frame_rehighlight (emacsframe);
6013 emacs_event->kind = FOCUS_IN_EVENT;
6014 EV_TRAILER ((id)nil);
6019 - (void)windowDidResignKey: (NSNotification *)notification
6020 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6022 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6023 BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6024 NSTRACE (windowDidResignKey);
6027 dpyinfo->x_focus_frame = 0;
6029 emacsframe->mouse_moved = 0;
6030 ns_frame_rehighlight (emacsframe);
6032 /* FIXME: for some reason needed on second and subsequent clicks away
6033 from sole-frame Emacs to get hollow box to show */
6034 if (!windowClosing && [[self window] isVisible] == YES)
6036 x_update_cursor (emacsframe, 1);
6037 x_set_frame_alpha (emacsframe);
6040 if (any_help_event_p)
6043 XSETFRAME (frame, emacsframe);
6044 help_echo_string = Qnil;
6045 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
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 #ifdef NS_IMPL_COCOA
6502 NSApplicationPresentationOptions options
6503 = NSApplicationPresentationAutoHideDock
6504 | NSApplicationPresentationAutoHideMenuBar;
6506 [NSApp setPresentationOptions: options];
6508 [NSMenu setMenuBarVisible:NO];
6512 fw = [[EmacsFSWindow alloc]
6513 initWithContentRect:[w contentRectForFrameRect:wr]
6514 styleMask:NSBorderlessWindowMask
6515 backing:NSBackingStoreBuffered
6519 [fw setContentView:[w contentView]];
6520 [fw setTitle:[w title]];
6521 [fw setDelegate:self];
6522 [fw setAcceptsMouseMovedEvents: YES];
6523 [fw useOptimizedDrawing: YES];
6524 [fw setResizeIncrements: sz];
6525 [fw setBackgroundColor: col];
6526 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6529 f->border_width = 0;
6530 FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
6531 tobar_height = FRAME_TOOLBAR_HEIGHT (f);
6532 FRAME_TOOLBAR_HEIGHT (f) = 0;
6536 [self windowWillEnterFullScreen:nil];
6537 [fw makeKeyAndOrderFront:NSApp];
6538 [fw makeFirstResponder:self];
6540 r = [fw frameRectForContentRect:[screen frame]];
6541 [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
6542 [self windowDidEnterFullScreen:nil];
6553 #ifdef NS_IMPL_COCOA
6554 [NSApp setPresentationOptions: NSApplicationPresentationDefault];
6556 [NSMenu setMenuBarVisible:YES];
6560 [w setContentView:[fw contentView]];
6561 [w setResizeIncrements: sz];
6562 [w setBackgroundColor: col];
6563 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6566 f->border_width = bwidth;
6567 FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
6568 if (FRAME_EXTERNAL_TOOL_BAR (f))
6569 FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
6571 [self windowWillExitFullScreen:nil];
6572 [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
6574 [w makeKeyAndOrderFront:NSApp];
6575 [self windowDidExitFullScreen:nil];
6576 [self updateFrameSize:YES];
6582 if (fs_state != emacsframe->want_fullscreen)
6584 if (fs_state == FULLSCREEN_BOTH)
6586 [self toggleFullScreen:self];
6589 switch (emacsframe->want_fullscreen)
6591 case FULLSCREEN_BOTH:
6592 [self toggleFullScreen:self];
6594 case FULLSCREEN_WIDTH:
6595 next_maximized = FULLSCREEN_WIDTH;
6596 if (fs_state != FULLSCREEN_BOTH)
6597 [[self window] performZoom:self];
6599 case FULLSCREEN_HEIGHT:
6600 next_maximized = FULLSCREEN_HEIGHT;
6601 if (fs_state != FULLSCREEN_BOTH)
6602 [[self window] performZoom:self];
6604 case FULLSCREEN_MAXIMIZED:
6605 next_maximized = FULLSCREEN_MAXIMIZED;
6606 if (fs_state != FULLSCREEN_BOTH)
6607 [[self window] performZoom:self];
6609 case FULLSCREEN_NONE:
6610 if (fs_state != FULLSCREEN_BOTH)
6612 next_maximized = FULLSCREEN_NONE;
6613 [[self window] performZoom:self];
6618 emacsframe->want_fullscreen = FULLSCREEN_NONE;
6623 - (void) setFSValue: (int)value
6625 Lisp_Object lval = Qnil;
6628 case FULLSCREEN_BOTH:
6631 case FULLSCREEN_WIDTH:
6634 case FULLSCREEN_HEIGHT:
6637 case FULLSCREEN_MAXIMIZED:
6641 store_frame_param (emacsframe, Qfullscreen, lval);
6645 - (void)mouseEntered: (NSEvent *)theEvent
6647 NSTRACE (mouseEntered);
6649 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6650 = EV_TIMESTAMP (theEvent);
6654 - (void)mouseExited: (NSEvent *)theEvent
6656 Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6658 NSTRACE (mouseExited);
6663 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6664 = EV_TIMESTAMP (theEvent);
6666 if (emacsframe == hlinfo->mouse_face_mouse_frame)
6668 clear_mouse_face (hlinfo);
6669 hlinfo->mouse_face_mouse_frame = 0;
6677 if (context_menu_value == -1)
6678 context_menu_value = [sender tag];
6681 NSInteger tag = [sender tag];
6682 find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6683 emacsframe->menu_bar_vector,
6687 ns_send_appdefined (-1);
6692 - (EmacsToolbar *)toolbar
6698 /* this gets called on toolbar button click */
6699 - toolbarClicked: (id)item
6702 int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6704 NSTRACE (toolbarClicked);
6709 /* send first event (for some reason two needed) */
6710 theEvent = [[self window] currentEvent];
6711 emacs_event->kind = TOOL_BAR_EVENT;
6712 XSETFRAME (emacs_event->arg, emacsframe);
6713 EV_TRAILER (theEvent);
6715 emacs_event->kind = TOOL_BAR_EVENT;
6716 /* XSETINT (emacs_event->code, 0); */
6717 emacs_event->arg = AREF (emacsframe->tool_bar_items,
6718 idx + TOOL_BAR_ITEM_KEY);
6719 emacs_event->modifiers = EV_MODIFIERS (theEvent);
6720 EV_TRAILER (theEvent);
6725 - toggleToolbar: (id)sender
6730 emacs_event->kind = NS_NONKEY_EVENT;
6731 emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6732 EV_TRAILER ((id)nil);
6737 - (void)drawRect: (NSRect)rect
6739 int x = NSMinX (rect), y = NSMinY (rect);
6740 int width = NSWidth (rect), height = NSHeight (rect);
6744 if (!emacsframe || !emacsframe->output_data.ns)
6747 ns_clear_frame_area (emacsframe, x, y, width, height);
6748 expose_frame (emacsframe, x, y, width, height);
6751 drawRect: may be called (at least in OS X 10.5) for invisible
6752 views as well for some reason. Thus, do not infer visibility
6755 emacsframe->async_visible = 1;
6756 emacsframe->async_iconified = 0;
6761 /* NSDraggingDestination protocol methods. Actually this is not really a
6762 protocol, but a category of Object. O well... */
6764 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
6766 NSTRACE (draggingEntered);
6767 return NSDragOperationGeneric;
6771 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6777 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6782 NSEvent *theEvent = [[self window] currentEvent];
6784 NSDragOperation op = [sender draggingSourceOperationMask];
6787 NSTRACE (performDragOperation);
6792 position = [self convertPoint: [sender draggingLocation] fromView: nil];
6793 x = lrint (position.x); y = lrint (position.y);
6795 pb = [sender draggingPasteboard];
6796 type = [pb availableTypeFromArray: ns_drag_types];
6798 if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
6799 // URL drags contain all operations (0xf), don't allow all to be set.
6802 if (op & NSDragOperationLink)
6803 modifiers |= NSControlKeyMask;
6804 if (op & NSDragOperationCopy)
6805 modifiers |= NSAlternateKeyMask;
6806 if (op & NSDragOperationGeneric)
6807 modifiers |= NSCommandKeyMask;
6810 modifiers = EV_MODIFIERS2 (modifiers);
6815 else if ([type isEqualToString: NSFilenamesPboardType])
6818 NSEnumerator *fenum;
6821 if (!(files = [pb propertyListForType: type]))
6824 fenum = [files objectEnumerator];
6825 while ( (file = [fenum nextObject]) )
6827 emacs_event->kind = DRAG_N_DROP_EVENT;
6828 XSETINT (emacs_event->x, x);
6829 XSETINT (emacs_event->y, y);
6830 ns_input_file = append2 (ns_input_file,
6831 build_string ([file UTF8String]));
6832 emacs_event->modifiers = modifiers;
6833 emacs_event->arg = list2 (Qfile, build_string ([file UTF8String]));
6834 EV_TRAILER (theEvent);
6838 else if ([type isEqualToString: NSURLPboardType])
6840 NSURL *url = [NSURL URLFromPasteboard: pb];
6841 if (url == nil) return NO;
6843 emacs_event->kind = DRAG_N_DROP_EVENT;
6844 XSETINT (emacs_event->x, x);
6845 XSETINT (emacs_event->y, y);
6846 emacs_event->modifiers = modifiers;
6847 emacs_event->arg = list2 (Qurl,
6848 build_string ([[url absoluteString]
6850 EV_TRAILER (theEvent);
6852 if ([url isFileURL] != NO)
6854 NSString *file = [url path];
6855 ns_input_file = append2 (ns_input_file,
6856 build_string ([file UTF8String]));
6860 else if ([type isEqualToString: NSStringPboardType]
6861 || [type isEqualToString: NSTabularTextPboardType])
6865 if (! (data = [pb stringForType: type]))
6868 emacs_event->kind = DRAG_N_DROP_EVENT;
6869 XSETINT (emacs_event->x, x);
6870 XSETINT (emacs_event->y, y);
6871 emacs_event->modifiers = modifiers;
6872 emacs_event->arg = list2 (Qnil, build_string ([data UTF8String]));
6873 EV_TRAILER (theEvent);
6878 fprintf (stderr, "Invalid data type in dragging pasteboard");
6884 - (id) validRequestorForSendType: (NSString *)typeSent
6885 returnType: (NSString *)typeReturned
6887 NSTRACE (validRequestorForSendType);
6888 if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6889 && typeReturned == nil)
6891 if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6895 return [super validRequestorForSendType: typeSent
6896 returnType: typeReturned];
6900 /* The next two methods are part of NSServicesRequests informal protocol,
6901 supposedly called when a services menu item is chosen from this app.
6902 But this should not happen because we override the services menu with our
6903 own entries which call ns-perform-service.
6904 Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6905 So let's at least stub them out until further investigation can be done. */
6907 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6909 /* we could call ns_string_from_pasteboard(pboard) here but then it should
6910 be written into the buffer in place of the existing selection..
6911 ordinary service calls go through functions defined in ns-win.el */
6915 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6917 NSArray *typesDeclared;
6920 /* We only support NSStringPboardType */
6921 if ([types containsObject:NSStringPboardType] == NO) {
6925 val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6926 if (CONSP (val) && SYMBOLP (XCAR (val)))
6929 if (CONSP (val) && NILP (XCDR (val)))
6932 if (! STRINGP (val))
6935 typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6936 [pb declareTypes:typesDeclared owner:nil];
6937 ns_string_to_pasteboard (pb, val);
6942 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6943 (gives a miniaturized version of the window); currently we use the latter for
6944 frames whose active buffer doesn't correspond to any file
6945 (e.g., '*scratch*') */
6946 - setMiniwindowImage: (BOOL) setMini
6948 id image = [[self window] miniwindowImage];
6949 NSTRACE (setMiniwindowImage);
6951 /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6952 about "AppleDockIconEnabled" notwithstanding, however the set message
6953 below has its effect nonetheless. */
6954 if (image != emacsframe->output_data.ns->miniimage)
6956 if (image && [image isKindOfClass: [EmacsImage class]])
6958 [[self window] setMiniwindowImage:
6959 setMini ? emacsframe->output_data.ns->miniimage : nil];
6966 - (void) setRows: (int) r andColumns: (int) c
6972 @end /* EmacsView */
6976 /* ==========================================================================
6978 EmacsWindow implementation
6980 ========================================================================== */
6982 @implementation EmacsWindow
6984 #ifdef NS_IMPL_COCOA
6985 - (id)accessibilityAttributeValue:(NSString *)attribute
6987 Lisp_Object str = Qnil;
6988 struct frame *f = SELECTED_FRAME ();
6989 struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
6991 if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6992 return NSAccessibilityTextFieldRole;
6994 if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6995 && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6997 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6999 else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
7001 if (! NILP (BVAR (curbuf, mark_active)))
7002 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7006 ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
7007 ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
7008 ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
7010 if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
7011 str = make_uninit_multibyte_string (range, byte_range);
7013 str = make_uninit_string (range);
7014 /* To check: This returns emacs-utf-8, which is a superset of utf-8.
7015 Is this a problem? */
7016 memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
7023 if (CONSP (str) && SYMBOLP (XCAR (str)))
7026 if (CONSP (str) && NILP (XCDR (str)))
7031 const char *utfStr = SSDATA (str);
7032 NSString *nsStr = [NSString stringWithUTF8String: utfStr];
7037 return [super accessibilityAttributeValue:attribute];
7039 #endif /* NS_IMPL_COCOA */
7041 /* If we have multiple monitors, one above the other, we don't want to
7042 restrict the height to just one monitor. So we override this. */
7043 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
7045 /* When making the frame visible for the first time or if there is just
7046 one screen, we want to constrain. Other times not. */
7047 NSArray *screens = [NSScreen screens];
7048 NSUInteger nr_screens = [screens count], nr_eff_screens = 0, i;
7049 struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
7050 NSTRACE (constrainFrameRect);
7051 NSTRACE_RECT ("input", frameRect);
7053 if (ns_menu_bar_should_be_hidden ())
7056 if (nr_screens == 1)
7057 return [super constrainFrameRect:frameRect toScreen:screen];
7059 #ifdef NS_IMPL_COCOA
7060 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7061 // If separate spaces is on, it is like each screen is independent. There is
7062 // no spanning of frames across screens.
7063 if ([NSScreen screensHaveSeparateSpaces])
7064 return [super constrainFrameRect:frameRect toScreen:screen];
7068 for (i = 0; i < nr_screens; ++i)
7070 NSScreen *s = [screens objectAtIndex: i];
7071 NSRect scrrect = [s frame];
7072 NSRect intersect = NSIntersectionRect (frameRect, scrrect);
7074 if (intersect.size.width > 0 || intersect.size.height > 0)
7078 if (nr_eff_screens == 1)
7079 return [super constrainFrameRect:frameRect toScreen:screen];
7081 /* The default implementation does two things 1) ensure that the top
7082 of the rectangle is below the menu bar (or below the top of the
7083 screen) and 2) resizes windows larger than the screen. As we
7084 don't want the latter, a smaller rectangle is used. */
7085 #define FAKE_HEIGHT 64
7086 float old_top = frameRect.origin.y + frameRect.size.height;
7088 r.size.height = FAKE_HEIGHT;
7089 r.size.width = frameRect.size.width;
7090 r.origin.x = frameRect.origin.x;
7091 r.origin.y = old_top - FAKE_HEIGHT;
7093 NSTRACE_RECT ("input to super", r);
7095 r = [super constrainFrameRect:r toScreen:screen];
7097 NSTRACE_RECT ("output from super", r);
7099 float new_top = r.origin.y + FAKE_HEIGHT;
7100 if (new_top < old_top)
7102 frameRect.origin.y = new_top - frameRect.size.height;
7105 NSTRACE_RECT ("output", frameRect);
7111 @end /* EmacsWindow */
7114 @implementation EmacsFSWindow
7116 - (BOOL)canBecomeKeyWindow
7121 - (BOOL)canBecomeMainWindow
7128 /* ==========================================================================
7130 EmacsScroller implementation
7132 ========================================================================== */
7135 @implementation EmacsScroller
7137 /* for repeat button push */
7138 #define SCROLL_BAR_FIRST_DELAY 0.5
7139 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
7141 + (CGFloat) scrollerWidth
7143 /* TODO: if we want to allow variable widths, this is the place to do it,
7144 however neither GNUstep nor Cocoa support it very well */
7145 return [NSScroller scrollerWidth];
7149 - initFrame: (NSRect )r window: (Lisp_Object)nwin
7151 NSTRACE (EmacsScroller_initFrame);
7153 r.size.width = [EmacsScroller scrollerWidth];
7154 [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
7155 [self setContinuous: YES];
7156 [self setEnabled: YES];
7158 /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
7159 locked against the top and bottom edges, and right edge on OS X, where
7160 scrollers are on right. */
7161 #ifdef NS_IMPL_GNUSTEP
7162 [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
7164 [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
7169 pixel_height = NSHeight (r);
7170 if (pixel_height == 0) pixel_height = 1;
7171 min_portion = 20 / pixel_height;
7173 frame = XFRAME (XWINDOW (win)->frame);
7174 if (FRAME_LIVE_P (frame))
7177 EmacsView *view = FRAME_NS_VIEW (frame);
7178 NSView *sview = [[view window] contentView];
7179 NSArray *subs = [sview subviews];
7181 /* disable optimization stopping redraw of other scrollbars */
7182 view->scrollbarsNeedingUpdate = 0;
7183 for (i =[subs count]-1; i >= 0; i--)
7184 if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
7185 view->scrollbarsNeedingUpdate++;
7186 [sview addSubview: self];
7189 /* [self setFrame: r]; */
7195 - (void)setFrame: (NSRect)newRect
7197 NSTRACE (EmacsScroller_setFrame);
7198 /* block_input (); */
7199 pixel_height = NSHeight (newRect);
7200 if (pixel_height == 0) pixel_height = 1;
7201 min_portion = 20 / pixel_height;
7202 [super setFrame: newRect];
7204 /* unblock_input (); */
7231 /* ensure other scrollbar updates after deletion */
7232 view = (EmacsView *)FRAME_NS_VIEW (frame);
7234 view->scrollbarsNeedingUpdate++;
7236 wset_vertical_scroll_bar (XWINDOW (win), Qnil);
7238 [self removeFromSuperview];
7246 - (void)resetCursorRects
7248 NSRect visible = [self visibleRect];
7249 NSTRACE (resetCursorRects);
7251 if (!NSIsEmptyRect (visible))
7252 [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
7253 [[NSCursor arrowCursor] setOnMouseEntered: YES];
7257 - (int) checkSamePosition: (int) position portion: (int) portion
7260 return em_position ==position && em_portion ==portion && em_whole ==whole
7261 && portion != whole; /* needed for resize empty buf */
7265 - setPosition: (int)position portion: (int)portion whole: (int)whole
7267 NSTRACE (setPosition);
7269 em_position = position;
7270 em_portion = portion;
7273 if (portion >= whole)
7275 #ifdef NS_IMPL_COCOA
7276 [self setKnobProportion: 1.0];
7277 [self setDoubleValue: 1.0];
7279 [self setFloatValue: 0.0 knobProportion: 1.0];
7286 portion = max ((float)whole*min_portion/pixel_height, portion);
7287 pos = (float)position / (whole - portion);
7288 por = (CGFloat)portion/whole;
7289 #ifdef NS_IMPL_COCOA
7290 [self setKnobProportion: por];
7291 [self setDoubleValue: pos];
7293 [self setFloatValue: pos knobProportion: por];
7297 /* Events may come here even if the event loop is not running.
7298 If we don't enter the event loop, the scroll bar will not update.
7299 So send SIGIO to ourselves. */
7300 if (apploopnr == 0) raise (SIGIO);
7305 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
7306 drag events will go directly to the EmacsScroller. Leaving in for now. */
7307 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
7308 x: (Lisp_Object *)x y: ( Lisp_Object *)y
7310 *part = last_hit_part;
7312 XSETINT (*y, pixel_height);
7313 if ([self floatValue] > 0.999F)
7314 XSETINT (*x, pixel_height);
7316 XSETINT (*x, pixel_height * [self floatValue]);
7320 /* set up emacs_event */
7321 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
7326 emacs_event->part = last_hit_part;
7327 emacs_event->code = 0;
7328 emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
7329 emacs_event->frame_or_window = win;
7330 emacs_event->timestamp = EV_TIMESTAMP (e);
7331 emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
7332 emacs_event->arg = Qnil;
7333 XSETINT (emacs_event->x, loc * pixel_height);
7334 XSETINT (emacs_event->y, pixel_height-20);
7338 n_emacs_events_pending++;
7339 kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
7342 hold_event (emacs_event);
7343 EVENT_INIT (*emacs_event);
7344 ns_send_appdefined (-1);
7348 /* called manually thru timer to implement repeated button action w/hold-down */
7349 - repeatScroll: (NSTimer *)scrollEntry
7351 NSEvent *e = [[self window] currentEvent];
7352 NSPoint p = [[self window] mouseLocationOutsideOfEventStream];
7353 BOOL inKnob = [self testPart: p] == NSScrollerKnob;
7355 /* clear timer if need be */
7356 if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
7358 [scroll_repeat_entry invalidate];
7359 [scroll_repeat_entry release];
7360 scroll_repeat_entry = nil;
7366 = [[NSTimer scheduledTimerWithTimeInterval:
7367 SCROLL_BAR_CONTINUOUS_DELAY
7369 selector: @selector (repeatScroll:)
7375 [self sendScrollEventAtLoc: 0 fromEvent: e];
7380 /* Asynchronous mouse tracking for scroller. This allows us to dispatch
7381 mouseDragged events without going into a modal loop. */
7382 - (void)mouseDown: (NSEvent *)e
7385 /* hitPart is only updated AFTER event is passed on */
7386 NSScrollerPart part = [self testPart: [e locationInWindow]];
7387 CGFloat inc = 0.0, loc, kloc, pos;
7390 NSTRACE (EmacsScroller_mouseDown);
7394 case NSScrollerDecrementPage:
7395 last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
7396 case NSScrollerIncrementPage:
7397 last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
7398 case NSScrollerDecrementLine:
7399 last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
7400 case NSScrollerIncrementLine:
7401 last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
7402 case NSScrollerKnob:
7403 last_hit_part = scroll_bar_handle; break;
7404 case NSScrollerKnobSlot: /* GNUstep-only */
7405 last_hit_part = scroll_bar_move_ratio; break;
7406 default: /* NSScrollerNoPart? */
7407 fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
7414 pos = 0; /* ignored */
7416 /* set a timer to repeat, as we can't let superclass do this modally */
7418 = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
7420 selector: @selector (repeatScroll:)
7427 /* handle, or on GNUstep possibly slot */
7428 NSEvent *fake_event;
7430 /* compute float loc in slot and mouse offset on knob */
7431 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7433 loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7439 else if (loc >= NSHeight (sr))
7441 loc = NSHeight (sr);
7449 kr = [self convertRect: [self rectForPart: NSScrollerKnob]
7451 kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
7453 last_mouse_offset = kloc;
7455 /* if knob, tell emacs a location offset by knob pos
7456 (to indicate top of handle) */
7457 if (part == NSScrollerKnob)
7458 pos = (loc - last_mouse_offset) / NSHeight (sr);
7460 /* else this is a slot click on GNUstep: go straight there */
7461 pos = loc / NSHeight (sr);
7463 /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
7464 fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
7465 location: [e locationInWindow]
7466 modifierFlags: [e modifierFlags]
7467 timestamp: [e timestamp]
7468 windowNumber: [e windowNumber]
7469 context: [e context]
7470 eventNumber: [e eventNumber]
7471 clickCount: [e clickCount]
7472 pressure: [e pressure]];
7473 [super mouseUp: fake_event];
7476 if (part != NSScrollerKnob)
7477 [self sendScrollEventAtLoc: pos fromEvent: e];
7481 /* Called as we manually track scroller drags, rather than superclass. */
7482 - (void)mouseDragged: (NSEvent *)e
7487 NSTRACE (EmacsScroller_mouseDragged);
7489 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7491 loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7497 else if (loc >= NSHeight (sr) + last_mouse_offset)
7499 loc = NSHeight (sr) + last_mouse_offset;
7502 pos = (loc - last_mouse_offset) / NSHeight (sr);
7503 [self sendScrollEventAtLoc: pos fromEvent: e];
7507 - (void)mouseUp: (NSEvent *)e
7509 if (scroll_repeat_entry)
7511 [scroll_repeat_entry invalidate];
7512 [scroll_repeat_entry release];
7513 scroll_repeat_entry = nil;
7515 last_hit_part = scroll_bar_above_handle;
7519 /* treat scrollwheel events in the bar as though they were in the main window */
7520 - (void) scrollWheel: (NSEvent *)theEvent
7522 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
7523 [view mouseDown: theEvent];
7526 @end /* EmacsScroller */
7529 #ifdef NS_IMPL_GNUSTEP
7530 /* Dummy class to get rid of startup warnings. */
7531 @implementation EmacsDocument
7537 /* ==========================================================================
7539 Font-related functions; these used to be in nsfaces.m
7541 ========================================================================== */
7545 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
7547 struct font *font = XFONT_OBJECT (font_object);
7548 EmacsView *view = FRAME_NS_VIEW (f);
7551 fontset = fontset_from_font (font_object);
7552 FRAME_FONTSET (f) = fontset;
7554 if (FRAME_FONT (f) == font)
7555 /* This font is already set in frame F. There's nothing more to
7559 FRAME_FONT (f) = font;
7561 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
7562 FRAME_COLUMN_WIDTH (f) = font->average_width;
7563 FRAME_LINE_HEIGHT (f) = font->height;
7565 /* Compute the scroll bar width in character columns. */
7566 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
7568 int wid = FRAME_COLUMN_WIDTH (f);
7569 FRAME_CONFIG_SCROLL_BAR_COLS (f)
7570 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
7574 int wid = FRAME_COLUMN_WIDTH (f);
7575 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
7578 /* Compute the scroll bar height in character lines. */
7579 if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
7581 int height = FRAME_LINE_HEIGHT (f);
7582 FRAME_CONFIG_SCROLL_BAR_LINES (f)
7583 = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
7587 int height = FRAME_LINE_HEIGHT (f);
7588 FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
7591 /* Now make the frame display the given font. */
7592 if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
7593 x_set_window_size (f, 0, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
7594 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 1);
7600 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
7601 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
7605 ns_xlfd_to_fontname (const char *xlfd)
7606 /* --------------------------------------------------------------------------
7607 Convert an X font name (XLFD) to an NS font name.
7608 Only family is used.
7609 The string returned is temporarily allocated.
7610 -------------------------------------------------------------------------- */
7612 char *name = xmalloc (180);
7616 if (!strncmp (xlfd, "--", 2))
7617 sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7619 sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7621 /* stopgap for malformed XLFD input */
7622 if (strlen (name) == 0)
7623 strcpy (name, "Monaco");
7625 /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7626 also uppercase after '-' or ' ' */
7627 name[0] = c_toupper (name[0]);
7628 for (len =strlen (name), i =0; i<len; i++)
7634 name[i+1] = c_toupper (name[i+1]);
7636 else if (name[i] == '_')
7640 name[i+1] = c_toupper (name[i+1]);
7643 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name); */
7644 ret = [[NSString stringWithUTF8String: name] UTF8String];
7651 syms_of_nsterm (void)
7653 NSTRACE (syms_of_nsterm);
7655 ns_antialias_threshold = 10.0;
7657 /* from 23+ we need to tell emacs what modifiers there are.. */
7658 DEFSYM (Qmodifier_value, "modifier-value");
7659 DEFSYM (Qalt, "alt");
7660 DEFSYM (Qhyper, "hyper");
7661 DEFSYM (Qmeta, "meta");
7662 DEFSYM (Qsuper, "super");
7663 DEFSYM (Qcontrol, "control");
7664 DEFSYM (QUTF8_STRING, "UTF8_STRING");
7666 DEFSYM (Qfile, "file");
7667 DEFSYM (Qurl, "url");
7669 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7670 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7671 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7672 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7673 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7675 DEFVAR_LISP ("ns-input-file", ns_input_file,
7676 "The file specified in the last NS event.");
7677 ns_input_file =Qnil;
7679 DEFVAR_LISP ("ns-working-text", ns_working_text,
7680 "String for visualizing working composition sequence.");
7681 ns_working_text =Qnil;
7683 DEFVAR_LISP ("ns-input-font", ns_input_font,
7684 "The font specified in the last NS event.");
7685 ns_input_font =Qnil;
7687 DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7688 "The fontsize specified in the last NS event.");
7689 ns_input_fontsize =Qnil;
7691 DEFVAR_LISP ("ns-input-line", ns_input_line,
7692 "The line specified in the last NS event.");
7693 ns_input_line =Qnil;
7695 DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7696 "The service name specified in the last NS event.");
7697 ns_input_spi_name =Qnil;
7699 DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7700 "The service argument specified in the last NS event.");
7701 ns_input_spi_arg =Qnil;
7703 DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7704 "This variable describes the behavior of the alternate or option key.\n\
7705 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7706 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7707 at all, allowing it to be used at a lower level for accented character entry.");
7708 ns_alternate_modifier = Qmeta;
7710 DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7711 "This variable describes the behavior of the right alternate or option key.\n\
7712 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7713 Set to left means be the same key as `ns-alternate-modifier'.\n\
7714 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7715 at all, allowing it to be used at a lower level for accented character entry.");
7716 ns_right_alternate_modifier = Qleft;
7718 DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7719 "This variable describes the behavior of the command key.\n\
7720 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7721 ns_command_modifier = Qsuper;
7723 DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7724 "This variable describes the behavior of the right command key.\n\
7725 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7726 Set to left means be the same key as `ns-command-modifier'.\n\
7727 Set to none means that the command / option key is not interpreted by Emacs\n\
7728 at all, allowing it to be used at a lower level for accented character entry.");
7729 ns_right_command_modifier = Qleft;
7731 DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7732 "This variable describes the behavior of the control key.\n\
7733 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7734 ns_control_modifier = Qcontrol;
7736 DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7737 "This variable describes the behavior of the right control key.\n\
7738 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7739 Set to left means be the same key as `ns-control-modifier'.\n\
7740 Set to none means that the control / option key is not interpreted by Emacs\n\
7741 at all, allowing it to be used at a lower level for accented character entry.");
7742 ns_right_control_modifier = Qleft;
7744 DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7745 "This variable describes the behavior of the function key (on laptops).\n\
7746 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7747 Set to none means that the function key is not interpreted by Emacs at all,\n\
7748 allowing it to be used at a lower level for accented character entry.");
7749 ns_function_modifier = Qnone;
7751 DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7752 "Non-nil (the default) means to render text antialiased.");
7753 ns_antialias_text = Qt;
7755 DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7756 "Whether to confirm application quit using dialog.");
7757 ns_confirm_quit = Qnil;
7759 DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7760 doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7761 Only works on OSX 10.6 or later. */);
7762 ns_auto_hide_menu_bar = Qnil;
7764 DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
7765 doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
7766 Nil means use fullscreen the old (< 10.7) way. The old way works better with
7767 multiple monitors, but lacks tool bar. This variable is ignored on OSX < 10.7.
7768 Default is t for OSX >= 10.7, nil otherwise. */);
7769 #ifdef HAVE_NATIVE_FS
7770 ns_use_native_fullscreen = YES;
7772 ns_use_native_fullscreen = NO;
7774 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
7776 DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
7777 doc: /*Non-nil means use animation on non-native fullscreen.
7778 For native fullscreen, this does nothing.
7779 Default is nil. */);
7780 ns_use_fullscreen_animation = NO;
7782 DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
7783 doc: /*Non-nil means to use sRGB colorspace on OSX >= 10.7.
7784 Note that this does not apply to images.
7785 This variable is ignored on OSX < 10.7 and GNUstep. */);
7786 ns_use_srgb_colorspace = YES;
7788 /* TODO: move to common code */
7789 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7790 doc: /* Which toolkit scroll bars Emacs uses, if any.
7791 A value of nil means Emacs doesn't use toolkit scroll bars.
7792 With the X Window system, the value is a symbol describing the
7793 X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
7794 With MS Windows or Nextstep, the value is t. */);
7795 Vx_toolkit_scroll_bars = Qt;
7797 DEFVAR_BOOL ("x-use-underline-position-properties",
7798 x_use_underline_position_properties,
7799 doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7800 A value of nil means ignore them. If you encounter fonts with bogus
7801 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7802 to 4.1, set this to nil. */);
7803 x_use_underline_position_properties = 0;
7805 DEFVAR_BOOL ("x-underline-at-descent-line",
7806 x_underline_at_descent_line,
7807 doc: /* Non-nil means to draw the underline at the same place as the descent line.
7808 A value of nil means to draw the underline according to the value of the
7809 variable `x-use-underline-position-properties', which is usually at the
7810 baseline level. The default value is nil. */);
7811 x_underline_at_descent_line = 0;
7813 /* Tell Emacs about this window system. */
7814 Fprovide (Qns, Qnil);
7816 DEFSYM (Qcocoa, "cocoa");
7817 DEFSYM (Qgnustep, "gnustep");
7819 #ifdef NS_IMPL_COCOA
7820 Fprovide (Qcocoa, Qnil);
7823 Fprovide (Qgnustep, Qnil);