]> code.delx.au - gnu-emacs/blob - src/nsterm.m
Make `toggle-frame-maximized' respect the dock on OS X (bug#22988).
[gnu-emacs] / src / nsterm.m
1 /* NeXT/Open/GNUstep / MacOSX communication module. -*- coding: utf-8 -*-
2
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2016 Free Software
4 Foundation, Inc.
5
6 This file is part of GNU Emacs.
7
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 (at
11 your option) any later version.
12
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.
17
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/>. */
20
21 /*
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)
27 */
28
29 /* This should be the first include, as it may set up #defines affecting
30 interpretation of even the system includes. */
31 #include <config.h>
32
33 #include <fcntl.h>
34 #include <math.h>
35 #include <pthread.h>
36 #include <sys/types.h>
37 #include <time.h>
38 #include <signal.h>
39 #include <unistd.h>
40
41 #include <c-ctype.h>
42 #include <c-strcase.h>
43 #include <ftoastr.h>
44
45 #include "lisp.h"
46 #include "blockinput.h"
47 #include "sysselect.h"
48 #include "nsterm.h"
49 #include "systime.h"
50 #include "character.h"
51 #include "fontset.h"
52 #include "composite.h"
53 #include "ccl.h"
54
55 #include "termhooks.h"
56 #include "termchar.h"
57 #include "menu.h"
58 #include "window.h"
59 #include "keyboard.h"
60 #include "buffer.h"
61 #include "font.h"
62
63 #ifdef NS_IMPL_GNUSTEP
64 #include "process.h"
65 #endif
66
67 #ifdef NS_IMPL_COCOA
68 #include "macfont.h"
69 #endif
70
71
72 extern NSString *NSMenuDidBeginTrackingNotification;
73
74
75 /* ==========================================================================
76
77 NSTRACE, Trace support.
78
79 ========================================================================== */
80
81 #if NSTRACE_ENABLED
82
83 /* The following use "volatile" since they can be accessed from
84 parallel threads. */
85 volatile int nstrace_num = 0;
86 volatile int nstrace_depth = 0;
87
88 /* When 0, no trace is emitted. This is used by NSTRACE_WHEN and
89 NSTRACE_UNLESS to silence functions called.
90
91 TODO: This should really be a thread-local variable, to avoid that
92 a function with disabled trace thread silence trace output in
93 another. However, in practice this seldom is a problem. */
94 volatile int nstrace_enabled_global = 1;
95
96 /* Called when nstrace_enabled goes out of scope. */
97 void nstrace_leave(int * pointer_to_nstrace_enabled)
98 {
99 if (*pointer_to_nstrace_enabled)
100 {
101 --nstrace_depth;
102 }
103 }
104
105
106 /* Called when nstrace_saved_enabled_global goes out of scope. */
107 void nstrace_restore_global_trace_state(int * pointer_to_saved_enabled_global)
108 {
109 nstrace_enabled_global = *pointer_to_saved_enabled_global;
110 }
111
112
113 char const * nstrace_fullscreen_type_name (int fs_type)
114 {
115 switch (fs_type)
116 {
117 case -1: return "-1";
118 case FULLSCREEN_NONE: return "FULLSCREEN_NONE";
119 case FULLSCREEN_WIDTH: return "FULLSCREEN_WIDTH";
120 case FULLSCREEN_HEIGHT: return "FULLSCREEN_HEIGHT";
121 case FULLSCREEN_BOTH: return "FULLSCREEN_BOTH";
122 case FULLSCREEN_MAXIMIZED: return "FULLSCREEN_MAXIMIZED";
123 default: return "FULLSCREEN_?????";
124 }
125 }
126 #endif
127
128
129 /* ==========================================================================
130
131 NSColor, EmacsColor category.
132
133 ========================================================================== */
134 @implementation NSColor (EmacsColor)
135 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
136 blue:(CGFloat)blue alpha:(CGFloat)alpha
137 {
138 #ifdef NS_IMPL_COCOA
139 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
140 if (ns_use_srgb_colorspace)
141 return [NSColor colorWithSRGBRed: red
142 green: green
143 blue: blue
144 alpha: alpha];
145 #endif
146 #endif
147 return [NSColor colorWithCalibratedRed: red
148 green: green
149 blue: blue
150 alpha: alpha];
151 }
152
153 - (NSColor *)colorUsingDefaultColorSpace
154 {
155 #ifdef NS_IMPL_COCOA
156 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
157 if (ns_use_srgb_colorspace)
158 return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
159 #endif
160 #endif
161 return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
162 }
163
164 @end
165
166 /* ==========================================================================
167
168 Local declarations
169
170 ========================================================================== */
171
172 /* Convert a symbol indexed with an NSxxx value to a value as defined
173 in keyboard.c (lispy_function_key). I hope this is a correct way
174 of doing things... */
175 static unsigned convert_ns_to_X_keysym[] =
176 {
177 NSHomeFunctionKey, 0x50,
178 NSLeftArrowFunctionKey, 0x51,
179 NSUpArrowFunctionKey, 0x52,
180 NSRightArrowFunctionKey, 0x53,
181 NSDownArrowFunctionKey, 0x54,
182 NSPageUpFunctionKey, 0x55,
183 NSPageDownFunctionKey, 0x56,
184 NSEndFunctionKey, 0x57,
185 NSBeginFunctionKey, 0x58,
186 NSSelectFunctionKey, 0x60,
187 NSPrintFunctionKey, 0x61,
188 NSClearLineFunctionKey, 0x0B,
189 NSExecuteFunctionKey, 0x62,
190 NSInsertFunctionKey, 0x63,
191 NSUndoFunctionKey, 0x65,
192 NSRedoFunctionKey, 0x66,
193 NSMenuFunctionKey, 0x67,
194 NSFindFunctionKey, 0x68,
195 NSHelpFunctionKey, 0x6A,
196 NSBreakFunctionKey, 0x6B,
197
198 NSF1FunctionKey, 0xBE,
199 NSF2FunctionKey, 0xBF,
200 NSF3FunctionKey, 0xC0,
201 NSF4FunctionKey, 0xC1,
202 NSF5FunctionKey, 0xC2,
203 NSF6FunctionKey, 0xC3,
204 NSF7FunctionKey, 0xC4,
205 NSF8FunctionKey, 0xC5,
206 NSF9FunctionKey, 0xC6,
207 NSF10FunctionKey, 0xC7,
208 NSF11FunctionKey, 0xC8,
209 NSF12FunctionKey, 0xC9,
210 NSF13FunctionKey, 0xCA,
211 NSF14FunctionKey, 0xCB,
212 NSF15FunctionKey, 0xCC,
213 NSF16FunctionKey, 0xCD,
214 NSF17FunctionKey, 0xCE,
215 NSF18FunctionKey, 0xCF,
216 NSF19FunctionKey, 0xD0,
217 NSF20FunctionKey, 0xD1,
218 NSF21FunctionKey, 0xD2,
219 NSF22FunctionKey, 0xD3,
220 NSF23FunctionKey, 0xD4,
221 NSF24FunctionKey, 0xD5,
222
223 NSBackspaceCharacter, 0x08, /* 8: Not on some KBs. */
224 NSDeleteCharacter, 0xFF, /* 127: Big 'delete' key upper right. */
225 NSDeleteFunctionKey, 0x9F, /* 63272: Del forw key off main array. */
226
227 NSTabCharacter, 0x09,
228 0x19, 0x09, /* left tab->regular since pass shift */
229 NSCarriageReturnCharacter, 0x0D,
230 NSNewlineCharacter, 0x0D,
231 NSEnterCharacter, 0x8D,
232
233 0x41|NSNumericPadKeyMask, 0xAE, /* KP_Decimal */
234 0x43|NSNumericPadKeyMask, 0xAA, /* KP_Multiply */
235 0x45|NSNumericPadKeyMask, 0xAB, /* KP_Add */
236 0x4B|NSNumericPadKeyMask, 0xAF, /* KP_Divide */
237 0x4E|NSNumericPadKeyMask, 0xAD, /* KP_Subtract */
238 0x51|NSNumericPadKeyMask, 0xBD, /* KP_Equal */
239 0x52|NSNumericPadKeyMask, 0xB0, /* KP_0 */
240 0x53|NSNumericPadKeyMask, 0xB1, /* KP_1 */
241 0x54|NSNumericPadKeyMask, 0xB2, /* KP_2 */
242 0x55|NSNumericPadKeyMask, 0xB3, /* KP_3 */
243 0x56|NSNumericPadKeyMask, 0xB4, /* KP_4 */
244 0x57|NSNumericPadKeyMask, 0xB5, /* KP_5 */
245 0x58|NSNumericPadKeyMask, 0xB6, /* KP_6 */
246 0x59|NSNumericPadKeyMask, 0xB7, /* KP_7 */
247 0x5B|NSNumericPadKeyMask, 0xB8, /* KP_8 */
248 0x5C|NSNumericPadKeyMask, 0xB9, /* KP_9 */
249
250 0x1B, 0x1B /* escape */
251 };
252
253 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
254 the maximum font size to NOT antialias. On GNUstep there is currently
255 no way to control this behavior. */
256 float ns_antialias_threshold;
257
258 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
259 NSString *ns_app_name = @"Emacs"; /* default changed later */
260
261 /* Display variables */
262 struct ns_display_info *x_display_list; /* Chain of existing displays */
263 long context_menu_value = 0;
264
265 /* display update */
266 static struct frame *ns_updating_frame;
267 static NSView *focus_view = NULL;
268 static int ns_window_num = 0;
269 #ifdef NS_IMPL_GNUSTEP
270 static NSRect uRect; // TODO: This is dead, remove it?
271 #endif
272 static BOOL gsaved = NO;
273 static BOOL ns_fake_keydown = NO;
274 #ifdef NS_IMPL_COCOA
275 static BOOL ns_menu_bar_is_hidden = NO;
276 #endif
277 /*static int debug_lock = 0; */
278
279 /* event loop */
280 static BOOL send_appdefined = YES;
281 #define NO_APPDEFINED_DATA (-8)
282 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
283 static NSTimer *timed_entry = 0;
284 static NSTimer *scroll_repeat_entry = nil;
285 static fd_set select_readfds, select_writefds;
286 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
287 static int select_nfds = 0, select_valid = 0;
288 static struct timespec select_timeout = { 0, 0 };
289 static int selfds[2] = { -1, -1 };
290 static pthread_mutex_t select_mutex;
291 static int apploopnr = 0;
292 static NSAutoreleasePool *outerpool;
293 static struct input_event *emacs_event = NULL;
294 static struct input_event *q_event_ptr = NULL;
295 static int n_emacs_events_pending = 0;
296 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
297 *ns_pending_service_args;
298 static BOOL ns_do_open_file = NO;
299 static BOOL ns_last_use_native_fullscreen;
300
301 /* Non-zero means that a HELP_EVENT has been generated since Emacs
302 start. */
303
304 static BOOL any_help_event_p = NO;
305
306 static struct {
307 struct input_event *q;
308 int nr, cap;
309 } hold_event_q = {
310 NULL, 0, 0
311 };
312
313 static NSString *represented_filename = nil;
314 static struct frame *represented_frame = 0;
315
316 #ifdef NS_IMPL_COCOA
317 /*
318 * State for pending menu activation:
319 * MENU_NONE Normal state
320 * MENU_PENDING A menu has been clicked on, but has been canceled so we can
321 * run lisp to update the menu.
322 * MENU_OPENING Menu is up to date, and the click event is redone so the menu
323 * will open.
324 */
325 #define MENU_NONE 0
326 #define MENU_PENDING 1
327 #define MENU_OPENING 2
328 static int menu_will_open_state = MENU_NONE;
329
330 /* Saved position for menu click. */
331 static CGPoint menu_mouse_point;
332 #endif
333
334 /* Convert modifiers in a NeXTstep event to emacs style modifiers. */
335 #define NS_FUNCTION_KEY_MASK 0x800000
336 #define NSLeftControlKeyMask (0x000001 | NSControlKeyMask)
337 #define NSRightControlKeyMask (0x002000 | NSControlKeyMask)
338 #define NSLeftCommandKeyMask (0x000008 | NSCommandKeyMask)
339 #define NSRightCommandKeyMask (0x000010 | NSCommandKeyMask)
340 #define NSLeftAlternateKeyMask (0x000020 | NSAlternateKeyMask)
341 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
342 #define EV_MODIFIERS2(flags) \
343 (((flags & NSHelpKeyMask) ? \
344 hyper_modifier : 0) \
345 | (!EQ (ns_right_alternate_modifier, Qleft) && \
346 ((flags & NSRightAlternateKeyMask) \
347 == NSRightAlternateKeyMask) ? \
348 parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
349 | ((flags & NSAlternateKeyMask) ? \
350 parse_solitary_modifier (ns_alternate_modifier) : 0) \
351 | ((flags & NSShiftKeyMask) ? \
352 shift_modifier : 0) \
353 | (!EQ (ns_right_control_modifier, Qleft) && \
354 ((flags & NSRightControlKeyMask) \
355 == NSRightControlKeyMask) ? \
356 parse_solitary_modifier (ns_right_control_modifier) : 0) \
357 | ((flags & NSControlKeyMask) ? \
358 parse_solitary_modifier (ns_control_modifier) : 0) \
359 | ((flags & NS_FUNCTION_KEY_MASK) ? \
360 parse_solitary_modifier (ns_function_modifier) : 0) \
361 | (!EQ (ns_right_command_modifier, Qleft) && \
362 ((flags & NSRightCommandKeyMask) \
363 == NSRightCommandKeyMask) ? \
364 parse_solitary_modifier (ns_right_command_modifier) : 0) \
365 | ((flags & NSCommandKeyMask) ? \
366 parse_solitary_modifier (ns_command_modifier):0))
367 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
368
369 #define EV_UDMODIFIERS(e) \
370 ((([e type] == NSLeftMouseDown) ? down_modifier : 0) \
371 | (([e type] == NSRightMouseDown) ? down_modifier : 0) \
372 | (([e type] == NSOtherMouseDown) ? down_modifier : 0) \
373 | (([e type] == NSLeftMouseDragged) ? down_modifier : 0) \
374 | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
375 | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
376 | (([e type] == NSLeftMouseUp) ? up_modifier : 0) \
377 | (([e type] == NSRightMouseUp) ? up_modifier : 0) \
378 | (([e type] == NSOtherMouseUp) ? up_modifier : 0))
379
380 #define EV_BUTTON(e) \
381 ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 : \
382 (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
383 [e buttonNumber] - 1)
384
385 /* Convert the time field to a timestamp in milliseconds. */
386 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
387
388 /* This is a piece of code which is common to all the event handling
389 methods. Maybe it should even be a function. */
390 #define EV_TRAILER(e) \
391 { \
392 XSETFRAME (emacs_event->frame_or_window, emacsframe); \
393 EV_TRAILER2 (e); \
394 }
395
396 #define EV_TRAILER2(e) \
397 { \
398 if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \
399 if (q_event_ptr) \
400 { \
401 Lisp_Object tem = Vinhibit_quit; \
402 Vinhibit_quit = Qt; \
403 n_emacs_events_pending++; \
404 kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \
405 Vinhibit_quit = tem; \
406 } \
407 else \
408 hold_event (emacs_event); \
409 EVENT_INIT (*emacs_event); \
410 ns_send_appdefined (-1); \
411 }
412
413 /* TODO: get rid of need for these forward declarations */
414 static void ns_condemn_scroll_bars (struct frame *f);
415 static void ns_judge_scroll_bars (struct frame *f);
416 void x_set_frame_alpha (struct frame *f);
417
418
419 /* ==========================================================================
420
421 Utilities
422
423 ========================================================================== */
424
425 void
426 ns_set_represented_filename (NSString* fstr, struct frame *f)
427 {
428 represented_filename = [fstr retain];
429 represented_frame = f;
430 }
431
432 void
433 ns_init_events (struct input_event* ev)
434 {
435 EVENT_INIT (*ev);
436 emacs_event = ev;
437 }
438
439 void
440 ns_finish_events ()
441 {
442 emacs_event = NULL;
443 }
444
445 static void
446 hold_event (struct input_event *event)
447 {
448 if (hold_event_q.nr == hold_event_q.cap)
449 {
450 if (hold_event_q.cap == 0) hold_event_q.cap = 10;
451 else hold_event_q.cap *= 2;
452 hold_event_q.q =
453 xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
454 }
455
456 hold_event_q.q[hold_event_q.nr++] = *event;
457 /* Make sure ns_read_socket is called, i.e. we have input. */
458 raise (SIGIO);
459 send_appdefined = YES;
460 }
461
462 static Lisp_Object
463 append2 (Lisp_Object list, Lisp_Object item)
464 /* --------------------------------------------------------------------------
465 Utility to append to a list
466 -------------------------------------------------------------------------- */
467 {
468 return CALLN (Fnconc, list, list1 (item));
469 }
470
471
472 const char *
473 ns_etc_directory (void)
474 /* If running as a self-contained app bundle, return as a string the
475 filename of the etc directory, if present; else nil. */
476 {
477 NSBundle *bundle = [NSBundle mainBundle];
478 NSString *resourceDir = [bundle resourcePath];
479 NSString *resourcePath;
480 NSFileManager *fileManager = [NSFileManager defaultManager];
481 BOOL isDir;
482
483 resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
484 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
485 {
486 if (isDir) return [resourcePath UTF8String];
487 }
488 return NULL;
489 }
490
491
492 const char *
493 ns_exec_path (void)
494 /* If running as a self-contained app bundle, return as a path string
495 the filenames of the libexec and bin directories, ie libexec:bin.
496 Otherwise, return nil.
497 Normally, Emacs does not add its own bin/ directory to the PATH.
498 However, a self-contained NS build has a different layout, with
499 bin/ and libexec/ subdirectories in the directory that contains
500 Emacs.app itself.
501 We put libexec first, because init_callproc_1 uses the first
502 element to initialize exec-directory. An alternative would be
503 for init_callproc to check for invocation-directory/libexec.
504 */
505 {
506 NSBundle *bundle = [NSBundle mainBundle];
507 NSString *resourceDir = [bundle resourcePath];
508 NSString *binDir = [bundle bundlePath];
509 NSString *resourcePath, *resourcePaths;
510 NSRange range;
511 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
512 NSFileManager *fileManager = [NSFileManager defaultManager];
513 NSArray *paths;
514 NSEnumerator *pathEnum;
515 BOOL isDir;
516
517 range = [resourceDir rangeOfString: @"Contents"];
518 if (range.location != NSNotFound)
519 {
520 binDir = [binDir stringByAppendingPathComponent: @"Contents"];
521 #ifdef NS_IMPL_COCOA
522 binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
523 #endif
524 }
525
526 paths = [binDir stringsByAppendingPaths:
527 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
528 pathEnum = [paths objectEnumerator];
529 resourcePaths = @"";
530
531 while ((resourcePath = [pathEnum nextObject]))
532 {
533 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
534 if (isDir)
535 {
536 if ([resourcePaths length] > 0)
537 resourcePaths
538 = [resourcePaths stringByAppendingString: pathSeparator];
539 resourcePaths
540 = [resourcePaths stringByAppendingString: resourcePath];
541 }
542 }
543 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
544
545 return NULL;
546 }
547
548
549 const char *
550 ns_load_path (void)
551 /* If running as a self-contained app bundle, return as a path string
552 the filenames of the site-lisp and lisp directories.
553 Ie, site-lisp:lisp. Otherwise, return nil. */
554 {
555 NSBundle *bundle = [NSBundle mainBundle];
556 NSString *resourceDir = [bundle resourcePath];
557 NSString *resourcePath, *resourcePaths;
558 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
559 NSFileManager *fileManager = [NSFileManager defaultManager];
560 BOOL isDir;
561 NSArray *paths = [resourceDir stringsByAppendingPaths:
562 [NSArray arrayWithObjects:
563 @"site-lisp", @"lisp", nil]];
564 NSEnumerator *pathEnum = [paths objectEnumerator];
565 resourcePaths = @"";
566
567 /* Hack to skip site-lisp. */
568 if (no_site_lisp) resourcePath = [pathEnum nextObject];
569
570 while ((resourcePath = [pathEnum nextObject]))
571 {
572 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
573 if (isDir)
574 {
575 if ([resourcePaths length] > 0)
576 resourcePaths
577 = [resourcePaths stringByAppendingString: pathSeparator];
578 resourcePaths
579 = [resourcePaths stringByAppendingString: resourcePath];
580 }
581 }
582 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
583
584 return NULL;
585 }
586
587
588 void
589 ns_init_locale (void)
590 /* OS X doesn't set any environment variables for the locale when run
591 from the GUI. Get the locale from the OS and set LANG. */
592 {
593 NSLocale *locale = [NSLocale currentLocale];
594
595 NSTRACE ("ns_init_locale");
596
597 @try
598 {
599 /* Set LANG to locale, but not if LANG is already set. */
600 setenv("LANG", [[locale localeIdentifier] UTF8String], 0);
601 }
602 @catch (NSException *e)
603 {
604 NSLog (@"Locale detection failed: %@: %@", [e name], [e reason]);
605 }
606 }
607
608
609 void
610 ns_release_object (void *obj)
611 /* --------------------------------------------------------------------------
612 Release an object (callable from C)
613 -------------------------------------------------------------------------- */
614 {
615 [(id)obj release];
616 }
617
618
619 void
620 ns_retain_object (void *obj)
621 /* --------------------------------------------------------------------------
622 Retain an object (callable from C)
623 -------------------------------------------------------------------------- */
624 {
625 [(id)obj retain];
626 }
627
628
629 void *
630 ns_alloc_autorelease_pool (void)
631 /* --------------------------------------------------------------------------
632 Allocate a pool for temporary objects (callable from C)
633 -------------------------------------------------------------------------- */
634 {
635 return [[NSAutoreleasePool alloc] init];
636 }
637
638
639 void
640 ns_release_autorelease_pool (void *pool)
641 /* --------------------------------------------------------------------------
642 Free a pool and temporary objects it refers to (callable from C)
643 -------------------------------------------------------------------------- */
644 {
645 ns_release_object (pool);
646 }
647
648
649 static BOOL
650 ns_menu_bar_should_be_hidden (void)
651 /* True, if the menu bar should be hidden. */
652 {
653 return !NILP (ns_auto_hide_menu_bar)
654 && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
655 }
656
657
658 struct EmacsMargins
659 {
660 CGFloat top;
661 CGFloat bottom;
662 CGFloat left;
663 CGFloat right;
664 };
665
666
667 static struct EmacsMargins
668 ns_screen_margins (NSScreen *screen)
669 /* The parts of SCREEN used by the operating system. */
670 {
671 NSTRACE ("ns_screen_margins");
672
673 struct EmacsMargins margins;
674
675 NSRect screenFrame = [screen frame];
676 NSRect screenVisibleFrame = [screen visibleFrame];
677
678 /* Sometimes, visibleFrame isn't up-to-date with respect to a hidden
679 menu bar, check this explicitly. */
680 if (ns_menu_bar_should_be_hidden())
681 {
682 margins.top = 0;
683 }
684 else
685 {
686 CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
687 CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
688 + screenVisibleFrame.size.height);
689
690 margins.top = frameTop - visibleFrameTop;
691 }
692
693 {
694 CGFloat frameRight = screenFrame.origin.x + screenFrame.size.width;
695 CGFloat visibleFrameRight = (screenVisibleFrame.origin.x
696 + screenVisibleFrame.size.width);
697 margins.right = frameRight - visibleFrameRight;
698 }
699
700 margins.bottom = screenVisibleFrame.origin.y - screenFrame.origin.y;
701 margins.left = screenVisibleFrame.origin.x - screenFrame.origin.x;
702
703 NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
704 margins.left,
705 margins.right,
706 margins.top,
707 margins.bottom);
708
709 return margins;
710 }
711
712
713 /* A screen margin between 1 and DOCK_IGNORE_LIMIT (inclusive) is
714 assumed to contain a hidden dock. OS X currently use 4 pixels for
715 this, however, to be future compatible, a larger value is used. */
716 #define DOCK_IGNORE_LIMIT 6
717
718 static struct EmacsMargins
719 ns_screen_margins_ignoring_hidden_dock (NSScreen *screen)
720 /* The parts of SCREEN used by the operating system, excluding the parts
721 reserved for an hidden dock. */
722 {
723 NSTRACE ("ns_screen_margins_ignoring_hidden_dock");
724
725 struct EmacsMargins margins = ns_screen_margins(screen);
726
727 /* OS X (currently) reserved 4 pixels along the edge where a hidden
728 dock is located. Unfortunately, it's not possible to find the
729 location and information about if the dock is hidden. Instead,
730 it is assumed that if the margin of an edge is less than
731 DOCK_IGNORE_LIMIT, it contains a hidden dock. */
732 if (margins.left <= DOCK_IGNORE_LIMIT)
733 {
734 margins.left = 0;
735 }
736 if (margins.right <= DOCK_IGNORE_LIMIT)
737 {
738 margins.right = 0;
739 }
740 if (margins.top <= DOCK_IGNORE_LIMIT)
741 {
742 margins.top = 0;
743 }
744 /* Note: This doesn't occur in current versions of OS X, but
745 included for completeness and future compatibility. */
746 if (margins.bottom <= DOCK_IGNORE_LIMIT)
747 {
748 margins.bottom = 0;
749 }
750
751 NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
752 margins.left,
753 margins.right,
754 margins.top,
755 margins.bottom);
756
757 return margins;
758 }
759
760
761 static CGFloat
762 ns_menu_bar_height (NSScreen *screen)
763 /* The height of the menu bar, if visible.
764
765 Note: Don't use this when fullscreen is enabled -- the screen
766 sometimes includes, sometimes excludes the menu bar area. */
767 {
768 struct EmacsMargins margins = ns_screen_margins(screen);
769
770 CGFloat res = margins.top;
771
772 NSTRACE ("ns_menu_bar_height " NSTRACE_FMT_RETURN " %.0f", res);
773
774 return res;
775 }
776
777
778 /* ==========================================================================
779
780 Focus (clipping) and screen update
781
782 ========================================================================== */
783
784 //
785 // Window constraining
786 // -------------------
787 //
788 // To ensure that the windows are not placed under the menu bar, they
789 // are typically moved by the call-back constrainFrameRect. However,
790 // by overriding it, it's possible to inhibit this, leaving the window
791 // in it's original position.
792 //
793 // It's possible to hide the menu bar. However, technically, it's only
794 // possible to hide it when the application is active. To ensure that
795 // this work properly, the menu bar and window constraining are
796 // deferred until the application becomes active.
797 //
798 // Even though it's not possible to manually move a window above the
799 // top of the screen, it is allowed if it's done programmatically,
800 // when the menu is hidden. This allows the editable area to cover the
801 // full screen height.
802 //
803 // Test cases
804 // ----------
805 //
806 // Use the following extra files:
807 //
808 // init.el:
809 // ;; Hide menu and place frame slightly above the top of the screen.
810 // (setq ns-auto-hide-menu-bar t)
811 // (set-frame-position (selected-frame) 0 -20)
812 //
813 // Test 1:
814 //
815 // emacs -Q -l init.el
816 //
817 // Result: No menu bar, and the title bar should be above the screen.
818 //
819 // Test 2:
820 //
821 // emacs -Q
822 //
823 // Result: Menu bar visible, frame placed immediately below the menu.
824 //
825
826 static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
827 {
828 NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
829 NSTRACE_ARG_RECT (frameRect));
830
831 // --------------------
832 // Collect information about the screen the frame is covering.
833 //
834
835 NSArray *screens = [NSScreen screens];
836 NSUInteger nr_screens = [screens count];
837
838 int i;
839
840 // The height of the menu bar, if present in any screen the frame is
841 // displayed in.
842 int menu_bar_height = 0;
843
844 // A rectangle covering all the screen the frame is displayed in.
845 NSRect multiscreenRect = NSMakeRect(0, 0, 0, 0);
846 for (i = 0; i < nr_screens; ++i )
847 {
848 NSScreen *s = [screens objectAtIndex: i];
849 NSRect scrRect = [s frame];
850
851 NSTRACE_MSG ("Screen %d: " NSTRACE_FMT_RECT,
852 i, NSTRACE_ARG_RECT (scrRect));
853
854 if (NSIntersectionRect (frameRect, scrRect).size.height != 0)
855 {
856 multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
857
858 if (!isFullscreen)
859 {
860 CGFloat screen_menu_bar_height = ns_menu_bar_height (s);
861 menu_bar_height = max(menu_bar_height, screen_menu_bar_height);
862 }
863 }
864 }
865
866 NSTRACE_RECT ("multiscreenRect", multiscreenRect);
867
868 NSTRACE_MSG ("menu_bar_height: %d", menu_bar_height);
869
870 if (multiscreenRect.size.width == 0
871 || multiscreenRect.size.height == 0)
872 {
873 // Failed to find any monitor, give up.
874 NSTRACE_MSG ("multiscreenRect empty");
875 NSTRACE_RETURN_RECT (frameRect);
876 return frameRect;
877 }
878
879
880 // --------------------
881 // Find a suitable placement.
882 //
883
884 if (ns_menu_bar_should_be_hidden())
885 {
886 // When the menu bar is hidden, the user may place part of the
887 // frame above the top of the screen, for example to hide the
888 // title bar.
889 //
890 // Hence, keep the original position.
891 }
892 else
893 {
894 // Ensure that the frame is below the menu bar, or below the top
895 // of the screen.
896 //
897 // This assume that the menu bar is placed at the top in the
898 // rectangle that covers the monitors. (It doesn't have to be,
899 // but if it's not it's hard to do anything useful.)
900 CGFloat topOfWorkArea = (multiscreenRect.origin.y
901 + multiscreenRect.size.height
902 - menu_bar_height);
903
904 CGFloat topOfFrame = frameRect.origin.y + frameRect.size.height;
905 if (topOfFrame > topOfWorkArea)
906 {
907 frameRect.origin.y -= topOfFrame - topOfWorkArea;
908 NSTRACE_RECT ("After placement adjust", frameRect);
909 }
910 }
911
912 // Include the following section to restrict frame to the screens.
913 // (If so, update it to allow the frame to stretch down below the
914 // screen.)
915 #if 0
916 // --------------------
917 // Ensure frame doesn't stretch below the screens.
918 //
919
920 CGFloat diff = multiscreenRect.origin.y - frameRect.origin.y;
921
922 if (diff > 0)
923 {
924 frameRect.origin.y = multiscreenRect.origin.y;
925 frameRect.size.height -= diff;
926 }
927 #endif
928
929 NSTRACE_RETURN_RECT (frameRect);
930 return frameRect;
931 }
932
933
934 static void
935 ns_constrain_all_frames (void)
936 /* --------------------------------------------------------------------------
937 Ensure that the menu bar doesn't cover any frames.
938 -------------------------------------------------------------------------- */
939 {
940 Lisp_Object tail, frame;
941
942 NSTRACE ("ns_constrain_all_frames");
943
944 block_input ();
945
946 FOR_EACH_FRAME (tail, frame)
947 {
948 struct frame *f = XFRAME (frame);
949 if (FRAME_NS_P (f))
950 {
951 EmacsView *view = FRAME_NS_VIEW (f);
952
953 if (![view isFullscreen])
954 {
955 [[view window]
956 setFrame:constrain_frame_rect([[view window] frame], false)
957 display:NO];
958 }
959 }
960 }
961
962 unblock_input ();
963 }
964
965
966 static void
967 ns_update_auto_hide_menu_bar (void)
968 /* --------------------------------------------------------------------------
969 Show or hide the menu bar, based on user setting.
970 -------------------------------------------------------------------------- */
971 {
972 #ifdef NS_IMPL_COCOA
973 NSTRACE ("ns_update_auto_hide_menu_bar");
974
975 block_input ();
976
977 if (NSApp != nil && [NSApp isActive])
978 {
979 // Note, "setPresentationOptions" triggers an error unless the
980 // application is active.
981 BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
982
983 if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
984 {
985 NSApplicationPresentationOptions options
986 = NSApplicationPresentationDefault;
987
988 if (menu_bar_should_be_hidden)
989 options |= NSApplicationPresentationAutoHideMenuBar
990 | NSApplicationPresentationAutoHideDock;
991
992 [NSApp setPresentationOptions: options];
993
994 ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
995
996 if (!ns_menu_bar_is_hidden)
997 {
998 ns_constrain_all_frames ();
999 }
1000 }
1001 }
1002
1003 unblock_input ();
1004 #endif
1005 }
1006
1007
1008 static void
1009 ns_update_begin (struct frame *f)
1010 /* --------------------------------------------------------------------------
1011 Prepare for a grouped sequence of drawing calls
1012 external (RIF) call; whole frame, called before update_window_begin
1013 -------------------------------------------------------------------------- */
1014 {
1015 EmacsView *view = FRAME_NS_VIEW (f);
1016 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_begin");
1017
1018 ns_update_auto_hide_menu_bar ();
1019
1020 #ifdef NS_IMPL_COCOA
1021 if ([view isFullscreen] && [view fsIsNative])
1022 {
1023 // Fix reappearing tool bar in fullscreen for OSX 10.7
1024 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
1025 NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
1026 if (! tbar_visible != ! [toolbar isVisible])
1027 [toolbar setVisible: tbar_visible];
1028 }
1029 #endif
1030
1031 ns_updating_frame = f;
1032 [view lockFocus];
1033
1034 /* drawRect may have been called for say the minibuffer, and then clip path
1035 is for the minibuffer. But the display engine may draw more because
1036 we have set the frame as garbaged. So reset clip path to the whole
1037 view. */
1038 #ifdef NS_IMPL_COCOA
1039 {
1040 NSBezierPath *bp;
1041 NSRect r = [view frame];
1042 NSRect cr = [[view window] frame];
1043 /* If a large frame size is set, r may be larger than the window frame
1044 before constrained. In that case don't change the clip path, as we
1045 will clear in to the tool bar and title bar. */
1046 if (r.size.height
1047 + FRAME_NS_TITLEBAR_HEIGHT (f)
1048 + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
1049 {
1050 bp = [[NSBezierPath bezierPathWithRect: r] retain];
1051 [bp setClip];
1052 [bp release];
1053 }
1054 }
1055 #endif
1056
1057 #ifdef NS_IMPL_GNUSTEP
1058 uRect = NSMakeRect (0, 0, 0, 0);
1059 #endif
1060 }
1061
1062
1063 static void
1064 ns_update_window_begin (struct window *w)
1065 /* --------------------------------------------------------------------------
1066 Prepare for a grouped sequence of drawing calls
1067 external (RIF) call; for one window, called after update_begin
1068 -------------------------------------------------------------------------- */
1069 {
1070 struct frame *f = XFRAME (WINDOW_FRAME (w));
1071 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1072
1073 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_begin");
1074 w->output_cursor = w->cursor;
1075
1076 block_input ();
1077
1078 if (f == hlinfo->mouse_face_mouse_frame)
1079 {
1080 /* Don't do highlighting for mouse motion during the update. */
1081 hlinfo->mouse_face_defer = 1;
1082
1083 /* If the frame needs to be redrawn,
1084 simply forget about any prior mouse highlighting. */
1085 if (FRAME_GARBAGED_P (f))
1086 hlinfo->mouse_face_window = Qnil;
1087
1088 /* (further code for mouse faces ifdef'd out in other terms elided) */
1089 }
1090
1091 unblock_input ();
1092 }
1093
1094
1095 static void
1096 ns_update_window_end (struct window *w, bool cursor_on_p,
1097 bool mouse_face_overwritten_p)
1098 /* --------------------------------------------------------------------------
1099 Finished a grouped sequence of drawing calls
1100 external (RIF) call; for one window called before update_end
1101 -------------------------------------------------------------------------- */
1102 {
1103 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_end");
1104
1105 /* note: this fn is nearly identical in all terms */
1106 if (!w->pseudo_window_p)
1107 {
1108 block_input ();
1109
1110 if (cursor_on_p)
1111 display_and_set_cursor (w, 1,
1112 w->output_cursor.hpos, w->output_cursor.vpos,
1113 w->output_cursor.x, w->output_cursor.y);
1114
1115 if (draw_window_fringes (w, 1))
1116 {
1117 if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1118 x_draw_right_divider (w);
1119 else
1120 x_draw_vertical_border (w);
1121 }
1122
1123 unblock_input ();
1124 }
1125
1126 /* If a row with mouse-face was overwritten, arrange for
1127 frame_up_to_date to redisplay the mouse highlight. */
1128 if (mouse_face_overwritten_p)
1129 reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
1130 }
1131
1132
1133 static void
1134 ns_update_end (struct frame *f)
1135 /* --------------------------------------------------------------------------
1136 Finished a grouped sequence of drawing calls
1137 external (RIF) call; for whole frame, called after update_window_end
1138 -------------------------------------------------------------------------- */
1139 {
1140 EmacsView *view = FRAME_NS_VIEW (f);
1141
1142 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
1143
1144 /* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1145 MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1146
1147 block_input ();
1148
1149 [view unlockFocus];
1150 [[view window] flushWindow];
1151
1152 unblock_input ();
1153 ns_updating_frame = NULL;
1154 }
1155
1156 static void
1157 ns_focus (struct frame *f, NSRect *r, int n)
1158 /* --------------------------------------------------------------------------
1159 Internal: Focus on given frame. During small local updates this is used to
1160 draw, however during large updates, ns_update_begin and ns_update_end are
1161 called to wrap the whole thing, in which case these calls are stubbed out.
1162 Except, on GNUstep, we accumulate the rectangle being drawn into, because
1163 the back end won't do this automatically, and will just end up flushing
1164 the entire window.
1165 -------------------------------------------------------------------------- */
1166 {
1167 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
1168 if (r != NULL)
1169 {
1170 NSTRACE_RECT ("r", *r);
1171 }
1172
1173 if (f != ns_updating_frame)
1174 {
1175 NSView *view = FRAME_NS_VIEW (f);
1176 if (view != focus_view)
1177 {
1178 if (focus_view != NULL)
1179 {
1180 [focus_view unlockFocus];
1181 [[focus_view window] flushWindow];
1182 /*debug_lock--; */
1183 }
1184
1185 if (view)
1186 [view lockFocus];
1187 focus_view = view;
1188 /*if (view) debug_lock++; */
1189 }
1190 }
1191
1192 /* clipping */
1193 if (r)
1194 {
1195 [[NSGraphicsContext currentContext] saveGraphicsState];
1196 if (n == 2)
1197 NSRectClipList (r, 2);
1198 else
1199 NSRectClip (*r);
1200 gsaved = YES;
1201 }
1202 }
1203
1204
1205 static void
1206 ns_unfocus (struct frame *f)
1207 /* --------------------------------------------------------------------------
1208 Internal: Remove focus on given frame
1209 -------------------------------------------------------------------------- */
1210 {
1211 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_unfocus");
1212
1213 if (gsaved)
1214 {
1215 [[NSGraphicsContext currentContext] restoreGraphicsState];
1216 gsaved = NO;
1217 }
1218
1219 if (f != ns_updating_frame)
1220 {
1221 if (focus_view != NULL)
1222 {
1223 [focus_view unlockFocus];
1224 [[focus_view window] flushWindow];
1225 focus_view = NULL;
1226 /*debug_lock--; */
1227 }
1228 }
1229 }
1230
1231
1232 static void
1233 ns_clip_to_row (struct window *w, struct glyph_row *row,
1234 enum glyph_row_area area, BOOL gc)
1235 /* --------------------------------------------------------------------------
1236 Internal (but parallels other terms): Focus drawing on given row
1237 -------------------------------------------------------------------------- */
1238 {
1239 struct frame *f = XFRAME (WINDOW_FRAME (w));
1240 NSRect clip_rect;
1241 int window_x, window_y, window_width;
1242
1243 window_box (w, area, &window_x, &window_y, &window_width, 0);
1244
1245 clip_rect.origin.x = window_x;
1246 clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1247 clip_rect.origin.y = max (clip_rect.origin.y, window_y);
1248 clip_rect.size.width = window_width;
1249 clip_rect.size.height = row->visible_height;
1250
1251 ns_focus (f, &clip_rect, 1);
1252 }
1253
1254
1255 /* ==========================================================================
1256
1257 Visible bell and beep.
1258
1259 ========================================================================== */
1260
1261
1262 // This bell implementation shows the visual bell image asynchronously
1263 // from the rest of Emacs. This is done by adding a NSView to the
1264 // superview of the Emacs window and removing it using a timer.
1265 //
1266 // Unfortunately, some Emacs operations, like scrolling, is done using
1267 // low-level primitives that copy the content of the window, including
1268 // the bell image. To some extent, this is handled by removing the
1269 // image prior to scrolling and marking that the window is in need for
1270 // redisplay.
1271 //
1272 // To test this code, make sure that there is no artifacts of the bell
1273 // image in the following situations. Use a non-empty buffer (like the
1274 // tutorial) to ensure that a scroll is performed:
1275 //
1276 // * Single-window: C-g C-v
1277 //
1278 // * Side-by-windows: C-x 3 C-g C-v
1279 //
1280 // * Windows above each other: C-x 2 C-g C-v
1281
1282 @interface EmacsBell : NSImageView
1283 {
1284 // Number of currently active bell:s.
1285 unsigned int nestCount;
1286 NSView * mView;
1287 bool isAttached;
1288 }
1289 - (void)show:(NSView *)view;
1290 - (void)hide;
1291 - (void)remove;
1292 @end
1293
1294 @implementation EmacsBell
1295
1296 - (id)init;
1297 {
1298 NSTRACE ("[EmacsBell init]");
1299 if ((self = [super init]))
1300 {
1301 nestCount = 0;
1302 isAttached = false;
1303 #ifdef NS_IMPL_GNUSTEP
1304 // GNUstep doesn't provide named images. This was reported in
1305 // 2011, see https://savannah.gnu.org/bugs/?33396
1306 //
1307 // As a drop in replacement, a semitransparent gray square is used.
1308 self.image = [[NSImage alloc] initWithSize:NSMakeSize(32 * 5, 32 * 5)];
1309 [self.image lockFocus];
1310 [[NSColor colorForEmacsRed:0.5 green:0.5 blue:0.5 alpha:0.5] set];
1311 NSRectFill(NSMakeRect(0, 0, 32, 32));
1312 [self.image unlockFocus];
1313 #else
1314 self.image = [NSImage imageNamed:NSImageNameCaution];
1315 [self.image setSize:NSMakeSize(self.image.size.width * 5,
1316 self.image.size.height * 5)];
1317 #endif
1318 }
1319 return self;
1320 }
1321
1322 - (void)show:(NSView *)view
1323 {
1324 NSTRACE ("[EmacsBell show:]");
1325 NSTRACE_MSG ("nestCount: %u", nestCount);
1326
1327 // Show the image, unless it's already shown.
1328 if (nestCount == 0)
1329 {
1330 NSRect rect = [view bounds];
1331 NSPoint pos;
1332 pos.x = rect.origin.x + (rect.size.width - self.image.size.width )/2;
1333 pos.y = rect.origin.y + (rect.size.height - self.image.size.height)/2;
1334
1335 [self setFrameOrigin:pos];
1336 [self setFrameSize:self.image.size];
1337
1338 isAttached = true;
1339 mView = view;
1340 [[[view window] contentView] addSubview:self
1341 positioned:NSWindowAbove
1342 relativeTo:nil];
1343 }
1344
1345 ++nestCount;
1346
1347 [self performSelector:@selector(hide) withObject:self afterDelay:0.5];
1348 }
1349
1350
1351 - (void)hide
1352 {
1353 // Note: Trace output from this method isn't shown, reason unknown.
1354 // NSTRACE ("[EmacsBell hide]");
1355
1356 if (nestCount > 0)
1357 --nestCount;
1358
1359 // Remove the image once the last bell became inactive.
1360 if (nestCount == 0)
1361 {
1362 [self remove];
1363 }
1364 }
1365
1366
1367 -(void)remove
1368 {
1369 NSTRACE ("[EmacsBell remove]");
1370 if (isAttached)
1371 {
1372 NSTRACE_MSG ("removeFromSuperview");
1373 [self removeFromSuperview];
1374 mView.needsDisplay = YES;
1375 isAttached = false;
1376 }
1377 }
1378
1379 @end
1380
1381
1382 static EmacsBell * bell_view = nil;
1383
1384 static void
1385 ns_ring_bell (struct frame *f)
1386 /* --------------------------------------------------------------------------
1387 "Beep" routine
1388 -------------------------------------------------------------------------- */
1389 {
1390 NSTRACE ("ns_ring_bell");
1391 if (visible_bell)
1392 {
1393 struct frame *frame = SELECTED_FRAME ();
1394 NSView *view;
1395
1396 if (bell_view == nil)
1397 {
1398 bell_view = [[EmacsBell alloc] init];
1399 [bell_view retain];
1400 }
1401
1402 block_input ();
1403
1404 view = FRAME_NS_VIEW (frame);
1405 if (view != nil)
1406 {
1407 [bell_view show:view];
1408 }
1409
1410 unblock_input ();
1411 }
1412 else
1413 {
1414 NSBeep ();
1415 }
1416 }
1417
1418
1419 static void hide_bell ()
1420 /* --------------------------------------------------------------------------
1421 Ensure the bell is hidden.
1422 -------------------------------------------------------------------------- */
1423 {
1424 NSTRACE ("hide_bell");
1425
1426 if (bell_view != nil)
1427 {
1428 [bell_view remove];
1429 }
1430 }
1431
1432
1433 /* ==========================================================================
1434
1435 Frame / window manager related functions
1436
1437 ========================================================================== */
1438
1439
1440 static void
1441 ns_raise_frame (struct frame *f)
1442 /* --------------------------------------------------------------------------
1443 Bring window to foreground and make it active
1444 -------------------------------------------------------------------------- */
1445 {
1446 NSView *view;
1447
1448 check_window_system (f);
1449 view = FRAME_NS_VIEW (f);
1450 block_input ();
1451 if (FRAME_VISIBLE_P (f))
1452 [[view window] makeKeyAndOrderFront: NSApp];
1453 unblock_input ();
1454 }
1455
1456
1457 static void
1458 ns_lower_frame (struct frame *f)
1459 /* --------------------------------------------------------------------------
1460 Send window to back
1461 -------------------------------------------------------------------------- */
1462 {
1463 NSView *view;
1464
1465 check_window_system (f);
1466 view = FRAME_NS_VIEW (f);
1467 block_input ();
1468 [[view window] orderBack: NSApp];
1469 unblock_input ();
1470 }
1471
1472
1473 static void
1474 ns_frame_raise_lower (struct frame *f, bool raise)
1475 /* --------------------------------------------------------------------------
1476 External (hook)
1477 -------------------------------------------------------------------------- */
1478 {
1479 NSTRACE ("ns_frame_raise_lower");
1480
1481 if (raise)
1482 ns_raise_frame (f);
1483 else
1484 ns_lower_frame (f);
1485 }
1486
1487
1488 static void
1489 ns_frame_rehighlight (struct frame *frame)
1490 /* --------------------------------------------------------------------------
1491 External (hook): called on things like window switching within frame
1492 -------------------------------------------------------------------------- */
1493 {
1494 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1495 struct frame *old_highlight = dpyinfo->x_highlight_frame;
1496
1497 NSTRACE ("ns_frame_rehighlight");
1498 if (dpyinfo->x_focus_frame)
1499 {
1500 dpyinfo->x_highlight_frame
1501 = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1502 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1503 : dpyinfo->x_focus_frame);
1504 if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1505 {
1506 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1507 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1508 }
1509 }
1510 else
1511 dpyinfo->x_highlight_frame = 0;
1512
1513 if (dpyinfo->x_highlight_frame &&
1514 dpyinfo->x_highlight_frame != old_highlight)
1515 {
1516 if (old_highlight)
1517 {
1518 x_update_cursor (old_highlight, 1);
1519 x_set_frame_alpha (old_highlight);
1520 }
1521 if (dpyinfo->x_highlight_frame)
1522 {
1523 x_update_cursor (dpyinfo->x_highlight_frame, 1);
1524 x_set_frame_alpha (dpyinfo->x_highlight_frame);
1525 }
1526 }
1527 }
1528
1529
1530 void
1531 x_make_frame_visible (struct frame *f)
1532 /* --------------------------------------------------------------------------
1533 External: Show the window (X11 semantics)
1534 -------------------------------------------------------------------------- */
1535 {
1536 NSTRACE ("x_make_frame_visible");
1537 /* XXX: at some points in past this was not needed, as the only place that
1538 called this (frame.c:Fraise_frame ()) also called raise_lower;
1539 if this ends up the case again, comment this out again. */
1540 if (!FRAME_VISIBLE_P (f))
1541 {
1542 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1543
1544 SET_FRAME_VISIBLE (f, 1);
1545 ns_raise_frame (f);
1546
1547 /* Making a new frame from a fullscreen frame will make the new frame
1548 fullscreen also. So skip handleFS as this will print an error. */
1549 if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1550 && [view isFullscreen])
1551 return;
1552
1553 if (f->want_fullscreen != FULLSCREEN_NONE)
1554 {
1555 block_input ();
1556 [view handleFS];
1557 unblock_input ();
1558 }
1559 }
1560 }
1561
1562
1563 void
1564 x_make_frame_invisible (struct frame *f)
1565 /* --------------------------------------------------------------------------
1566 External: Hide the window (X11 semantics)
1567 -------------------------------------------------------------------------- */
1568 {
1569 NSView *view;
1570 NSTRACE ("x_make_frame_invisible");
1571 check_window_system (f);
1572 view = FRAME_NS_VIEW (f);
1573 [[view window] orderOut: NSApp];
1574 SET_FRAME_VISIBLE (f, 0);
1575 SET_FRAME_ICONIFIED (f, 0);
1576 }
1577
1578
1579 void
1580 x_iconify_frame (struct frame *f)
1581 /* --------------------------------------------------------------------------
1582 External: Iconify window
1583 -------------------------------------------------------------------------- */
1584 {
1585 NSView *view;
1586 struct ns_display_info *dpyinfo;
1587
1588 NSTRACE ("x_iconify_frame");
1589 check_window_system (f);
1590 view = FRAME_NS_VIEW (f);
1591 dpyinfo = FRAME_DISPLAY_INFO (f);
1592
1593 if (dpyinfo->x_highlight_frame == f)
1594 dpyinfo->x_highlight_frame = 0;
1595
1596 if ([[view window] windowNumber] <= 0)
1597 {
1598 /* the window is still deferred. Make it very small, bring it
1599 on screen and order it out. */
1600 NSRect s = { { 100, 100}, {0, 0} };
1601 NSRect t;
1602 t = [[view window] frame];
1603 [[view window] setFrame: s display: NO];
1604 [[view window] orderBack: NSApp];
1605 [[view window] orderOut: NSApp];
1606 [[view window] setFrame: t display: NO];
1607 }
1608 [[view window] miniaturize: NSApp];
1609 }
1610
1611 /* Free X resources of frame F. */
1612
1613 void
1614 x_free_frame_resources (struct frame *f)
1615 {
1616 NSView *view;
1617 struct ns_display_info *dpyinfo;
1618 Mouse_HLInfo *hlinfo;
1619
1620 NSTRACE ("x_free_frame_resources");
1621 check_window_system (f);
1622 view = FRAME_NS_VIEW (f);
1623 dpyinfo = FRAME_DISPLAY_INFO (f);
1624 hlinfo = MOUSE_HL_INFO (f);
1625
1626 [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1627
1628 block_input ();
1629
1630 free_frame_menubar (f);
1631 free_frame_faces (f);
1632
1633 if (f == dpyinfo->x_focus_frame)
1634 dpyinfo->x_focus_frame = 0;
1635 if (f == dpyinfo->x_highlight_frame)
1636 dpyinfo->x_highlight_frame = 0;
1637 if (f == hlinfo->mouse_face_mouse_frame)
1638 reset_mouse_highlight (hlinfo);
1639
1640 if (f->output_data.ns->miniimage != nil)
1641 [f->output_data.ns->miniimage release];
1642
1643 [[view window] close];
1644 [view release];
1645
1646 xfree (f->output_data.ns);
1647
1648 unblock_input ();
1649 }
1650
1651 void
1652 x_destroy_window (struct frame *f)
1653 /* --------------------------------------------------------------------------
1654 External: Delete the window
1655 -------------------------------------------------------------------------- */
1656 {
1657 NSTRACE ("x_destroy_window");
1658 check_window_system (f);
1659 x_free_frame_resources (f);
1660 ns_window_num--;
1661 }
1662
1663
1664 void
1665 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1666 /* --------------------------------------------------------------------------
1667 External: Position the window
1668 -------------------------------------------------------------------------- */
1669 {
1670 NSView *view = FRAME_NS_VIEW (f);
1671 NSArray *screens = [NSScreen screens];
1672 NSScreen *fscreen = [screens objectAtIndex: 0];
1673 NSScreen *screen = [[view window] screen];
1674
1675 NSTRACE ("x_set_offset");
1676
1677 block_input ();
1678
1679 f->left_pos = xoff;
1680 f->top_pos = yoff;
1681
1682 if (view != nil && screen && fscreen)
1683 {
1684 f->left_pos = f->size_hint_flags & XNegative
1685 ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1686 : f->left_pos;
1687 /* We use visibleFrame here to take menu bar into account.
1688 Ideally we should also adjust left/top with visibleFrame.origin. */
1689
1690 f->top_pos = f->size_hint_flags & YNegative
1691 ? ([screen visibleFrame].size.height + f->top_pos
1692 - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1693 - FRAME_TOOLBAR_HEIGHT (f))
1694 : f->top_pos;
1695 #ifdef NS_IMPL_GNUSTEP
1696 if (f->left_pos < 100)
1697 f->left_pos = 100; /* don't overlap menu */
1698 #endif
1699 /* Constrain the setFrameTopLeftPoint so we don't move behind the
1700 menu bar. */
1701 NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos),
1702 SCREENMAXBOUND ([fscreen frame].size.height
1703 - NS_TOP_POS (f)));
1704 NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1705 [[view window] setFrameTopLeftPoint: pt];
1706 f->size_hint_flags &= ~(XNegative|YNegative);
1707 }
1708
1709 unblock_input ();
1710 }
1711
1712
1713 void
1714 x_set_window_size (struct frame *f,
1715 bool change_gravity,
1716 int width,
1717 int height,
1718 bool pixelwise)
1719 /* --------------------------------------------------------------------------
1720 Adjust window pixel size based on given character grid size
1721 Impl is a bit more complex than other terms, need to do some
1722 internal clipping.
1723 -------------------------------------------------------------------------- */
1724 {
1725 EmacsView *view = FRAME_NS_VIEW (f);
1726 NSWindow *window = [view window];
1727 NSRect wr = [window frame];
1728 int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1729 int pixelwidth, pixelheight;
1730 int orig_height = wr.size.height;
1731
1732 NSTRACE ("x_set_window_size");
1733
1734 if (view == nil)
1735 return;
1736
1737 NSTRACE_RECT ("current", wr);
1738 NSTRACE_MSG ("Width:%d Height:%d Pixelwise:%d", width, height, pixelwise);
1739 NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
1740
1741 block_input ();
1742
1743 if (pixelwise)
1744 {
1745 pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1746 pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1747 }
1748 else
1749 {
1750 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width);
1751 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1752 }
1753
1754 /* If we have a toolbar, take its height into account. */
1755 if (tb && ! [view isFullscreen])
1756 {
1757 /* NOTE: previously this would generate wrong result if toolbar not
1758 yet displayed and fixing toolbar_height=32 helped, but
1759 now (200903) seems no longer needed */
1760 FRAME_TOOLBAR_HEIGHT (f) =
1761 NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1762 - FRAME_NS_TITLEBAR_HEIGHT (f);
1763 #if 0
1764 /* Only breaks things here, removed by martin 2015-09-30. */
1765 #ifdef NS_IMPL_GNUSTEP
1766 FRAME_TOOLBAR_HEIGHT (f) -= 3;
1767 #endif
1768 #endif
1769 }
1770 else
1771 FRAME_TOOLBAR_HEIGHT (f) = 0;
1772
1773 wr.size.width = pixelwidth + f->border_width;
1774 wr.size.height = pixelheight;
1775 if (! [view isFullscreen])
1776 wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1777 + FRAME_TOOLBAR_HEIGHT (f);
1778
1779 /* Do not try to constrain to this screen. We may have multiple
1780 screens, and want Emacs to span those. Constraining to screen
1781 prevents that, and that is not nice to the user. */
1782 if (f->output_data.ns->zooming)
1783 f->output_data.ns->zooming = 0;
1784 else
1785 wr.origin.y += orig_height - wr.size.height;
1786
1787 frame_size_history_add
1788 (f, Qx_set_window_size_1, width, height,
1789 list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1790 Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1791 make_number (f->border_width),
1792 make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1793 make_number (FRAME_TOOLBAR_HEIGHT (f))));
1794
1795 [window setFrame: wr display: YES];
1796
1797 /* This is a trick to compensate for Emacs' managing the scrollbar area
1798 as a fixed number of standard character columns. Instead of leaving
1799 blank space for the extra, we chopped it off above. Now for
1800 left-hand scrollbars, we shift all rendering to the left by the
1801 difference between the real width and Emacs' imagined one. For
1802 right-hand bars, don't worry about it since the extra is never used.
1803 (Obviously doesn't work for vertically split windows tho..) */
1804 {
1805 NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1806 ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1807 - NS_SCROLL_BAR_WIDTH (f), 0)
1808 : NSMakePoint (0, 0);
1809
1810 [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1811 [view setBoundsOrigin: origin];
1812 }
1813
1814 [view updateFrameSize: NO];
1815 unblock_input ();
1816 }
1817
1818
1819 static void
1820 ns_fullscreen_hook (struct frame *f)
1821 {
1822 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1823
1824 NSTRACE ("ns_fullscreen_hook");
1825
1826 if (!FRAME_VISIBLE_P (f))
1827 return;
1828
1829 if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1830 {
1831 /* Old style fs don't initiate correctly if created from
1832 init/default-frame alist, so use a timer (not nice...).
1833 */
1834 [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1835 selector: @selector (handleFS)
1836 userInfo: nil repeats: NO];
1837 return;
1838 }
1839
1840 block_input ();
1841 [view handleFS];
1842 unblock_input ();
1843 }
1844
1845 /* ==========================================================================
1846
1847 Color management
1848
1849 ========================================================================== */
1850
1851
1852 NSColor *
1853 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1854 {
1855 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1856 if (idx < 1 || idx >= color_table->avail)
1857 return nil;
1858 return color_table->colors[idx];
1859 }
1860
1861
1862 unsigned long
1863 ns_index_color (NSColor *color, struct frame *f)
1864 {
1865 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1866 ptrdiff_t idx;
1867 ptrdiff_t i;
1868
1869 if (!color_table->colors)
1870 {
1871 color_table->size = NS_COLOR_CAPACITY;
1872 color_table->avail = 1; /* skip idx=0 as marker */
1873 color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1874 color_table->colors[0] = nil;
1875 color_table->empty_indices = [[NSMutableSet alloc] init];
1876 }
1877
1878 /* Do we already have this color? */
1879 for (i = 1; i < color_table->avail; i++)
1880 if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1881 return i;
1882
1883 if ([color_table->empty_indices count] > 0)
1884 {
1885 NSNumber *index = [color_table->empty_indices anyObject];
1886 [color_table->empty_indices removeObject: index];
1887 idx = [index unsignedLongValue];
1888 }
1889 else
1890 {
1891 if (color_table->avail == color_table->size)
1892 color_table->colors =
1893 xpalloc (color_table->colors, &color_table->size, 1,
1894 min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1895 idx = color_table->avail++;
1896 }
1897
1898 color_table->colors[idx] = color;
1899 [color retain];
1900 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1901 return idx;
1902 }
1903
1904
1905 void
1906 ns_free_indexed_color (unsigned long idx, struct frame *f)
1907 {
1908 struct ns_color_table *color_table;
1909 NSColor *color;
1910 NSNumber *index;
1911
1912 if (!f)
1913 return;
1914
1915 color_table = FRAME_DISPLAY_INFO (f)->color_table;
1916
1917 if (idx <= 0 || idx >= color_table->size) {
1918 message1 ("ns_free_indexed_color: Color index out of range.\n");
1919 return;
1920 }
1921
1922 index = [NSNumber numberWithUnsignedInt: idx];
1923 if ([color_table->empty_indices containsObject: index]) {
1924 message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1925 return;
1926 }
1927
1928 color = color_table->colors[idx];
1929 [color release];
1930 color_table->colors[idx] = nil;
1931 [color_table->empty_indices addObject: index];
1932 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1933 }
1934
1935
1936 static int
1937 ns_get_color (const char *name, NSColor **col)
1938 /* --------------------------------------------------------------------------
1939 Parse a color name
1940 -------------------------------------------------------------------------- */
1941 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1942 X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1943 See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1944 {
1945 NSColor *new = nil;
1946 static char hex[20];
1947 int scaling = 0;
1948 float r = -1.0, g, b;
1949 NSString *nsname = [NSString stringWithUTF8String: name];
1950
1951 NSTRACE ("ns_get_color(%s, **)", name);
1952
1953 block_input ();
1954
1955 if ([nsname isEqualToString: @"ns_selection_bg_color"])
1956 {
1957 #ifdef NS_IMPL_COCOA
1958 NSString *defname = [[NSUserDefaults standardUserDefaults]
1959 stringForKey: @"AppleHighlightColor"];
1960 if (defname != nil)
1961 nsname = defname;
1962 else
1963 #endif
1964 if ((new = [NSColor selectedTextBackgroundColor]) != nil)
1965 {
1966 *col = [new colorUsingDefaultColorSpace];
1967 unblock_input ();
1968 return 0;
1969 }
1970 else
1971 nsname = NS_SELECTION_BG_COLOR_DEFAULT;
1972
1973 name = [nsname UTF8String];
1974 }
1975 else if ([nsname isEqualToString: @"ns_selection_fg_color"])
1976 {
1977 /* NOTE: OSX applications normally don't set foreground selection, but
1978 text may be unreadable if we don't.
1979 */
1980 if ((new = [NSColor selectedTextColor]) != nil)
1981 {
1982 *col = [new colorUsingDefaultColorSpace];
1983 unblock_input ();
1984 return 0;
1985 }
1986
1987 nsname = NS_SELECTION_FG_COLOR_DEFAULT;
1988 name = [nsname UTF8String];
1989 }
1990
1991 /* First, check for some sort of numeric specification. */
1992 hex[0] = '\0';
1993
1994 if (name[0] == '0' || name[0] == '1' || name[0] == '.') /* RGB decimal */
1995 {
1996 NSScanner *scanner = [NSScanner scannerWithString: nsname];
1997 [scanner scanFloat: &r];
1998 [scanner scanFloat: &g];
1999 [scanner scanFloat: &b];
2000 }
2001 else if (!strncmp(name, "rgb:", 4)) /* A newer X11 format -- rgb:r/g/b */
2002 scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
2003 else if (name[0] == '#') /* An old X11 format; convert to newer */
2004 {
2005 int len = (strlen(name) - 1);
2006 int start = (len % 3 == 0) ? 1 : len / 4 + 1;
2007 int i;
2008 scaling = strlen(name+start) / 3;
2009 for (i = 0; i < 3; i++)
2010 sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
2011 name + start + i * scaling);
2012 hex[3 * (scaling + 1) - 1] = '\0';
2013 }
2014
2015 if (hex[0])
2016 {
2017 int rr, gg, bb;
2018 float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
2019 if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
2020 {
2021 r = rr / fscale;
2022 g = gg / fscale;
2023 b = bb / fscale;
2024 }
2025 }
2026
2027 if (r >= 0.0F)
2028 {
2029 *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
2030 unblock_input ();
2031 return 0;
2032 }
2033
2034 /* Otherwise, color is expected to be from a list */
2035 {
2036 NSEnumerator *lenum, *cenum;
2037 NSString *name;
2038 NSColorList *clist;
2039
2040 #ifdef NS_IMPL_GNUSTEP
2041 /* XXX: who is wrong, the requestor or the implementation? */
2042 if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
2043 == NSOrderedSame)
2044 nsname = @"highlightColor";
2045 #endif
2046
2047 lenum = [[NSColorList availableColorLists] objectEnumerator];
2048 while ( (clist = [lenum nextObject]) && new == nil)
2049 {
2050 cenum = [[clist allKeys] objectEnumerator];
2051 while ( (name = [cenum nextObject]) && new == nil )
2052 {
2053 if ([name compare: nsname
2054 options: NSCaseInsensitiveSearch] == NSOrderedSame )
2055 new = [clist colorWithKey: name];
2056 }
2057 }
2058 }
2059
2060 if (new)
2061 *col = [new colorUsingDefaultColorSpace];
2062 unblock_input ();
2063 return new ? 0 : 1;
2064 }
2065
2066
2067 int
2068 ns_lisp_to_color (Lisp_Object color, NSColor **col)
2069 /* --------------------------------------------------------------------------
2070 Convert a Lisp string object to a NS color
2071 -------------------------------------------------------------------------- */
2072 {
2073 NSTRACE ("ns_lisp_to_color");
2074 if (STRINGP (color))
2075 return ns_get_color (SSDATA (color), col);
2076 else if (SYMBOLP (color))
2077 return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
2078 return 1;
2079 }
2080
2081
2082 Lisp_Object
2083 ns_color_to_lisp (NSColor *col)
2084 /* --------------------------------------------------------------------------
2085 Convert a color to a lisp string with the RGB equivalent
2086 -------------------------------------------------------------------------- */
2087 {
2088 EmacsCGFloat red, green, blue, alpha, gray;
2089 char buf[1024];
2090 const char *str;
2091 NSTRACE ("ns_color_to_lisp");
2092
2093 block_input ();
2094 if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
2095
2096 if ((str =[[col colorNameComponent] UTF8String]))
2097 {
2098 unblock_input ();
2099 return build_string ((char *)str);
2100 }
2101
2102 [[col colorUsingDefaultColorSpace]
2103 getRed: &red green: &green blue: &blue alpha: &alpha];
2104 if (red == green && red == blue)
2105 {
2106 [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
2107 getWhite: &gray alpha: &alpha];
2108 snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
2109 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
2110 unblock_input ();
2111 return build_string (buf);
2112 }
2113
2114 snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
2115 lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
2116
2117 unblock_input ();
2118 return build_string (buf);
2119 }
2120
2121
2122 void
2123 ns_query_color(void *col, XColor *color_def, int setPixel)
2124 /* --------------------------------------------------------------------------
2125 Get ARGB values out of NSColor col and put them into color_def.
2126 If setPixel, set the pixel to a concatenated version.
2127 and set color_def pixel to the resulting index.
2128 -------------------------------------------------------------------------- */
2129 {
2130 EmacsCGFloat r, g, b, a;
2131
2132 [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
2133 color_def->red = r * 65535;
2134 color_def->green = g * 65535;
2135 color_def->blue = b * 65535;
2136
2137 if (setPixel == YES)
2138 color_def->pixel
2139 = ARGB_TO_ULONG((int)(a*255),
2140 (int)(r*255), (int)(g*255), (int)(b*255));
2141 }
2142
2143
2144 bool
2145 ns_defined_color (struct frame *f,
2146 const char *name,
2147 XColor *color_def,
2148 bool alloc,
2149 bool makeIndex)
2150 /* --------------------------------------------------------------------------
2151 Return true if named color found, and set color_def rgb accordingly.
2152 If makeIndex and alloc are nonzero put the color in the color_table,
2153 and set color_def pixel to the resulting index.
2154 If makeIndex is zero, set color_def pixel to ARGB.
2155 Return false if not found
2156 -------------------------------------------------------------------------- */
2157 {
2158 NSColor *col;
2159 NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color");
2160
2161 block_input ();
2162 if (ns_get_color (name, &col) != 0) /* Color not found */
2163 {
2164 unblock_input ();
2165 return 0;
2166 }
2167 if (makeIndex && alloc)
2168 color_def->pixel = ns_index_color (col, f);
2169 ns_query_color (col, color_def, !makeIndex);
2170 unblock_input ();
2171 return 1;
2172 }
2173
2174
2175 void
2176 x_set_frame_alpha (struct frame *f)
2177 /* --------------------------------------------------------------------------
2178 change the entire-frame transparency
2179 -------------------------------------------------------------------------- */
2180 {
2181 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2182 double alpha = 1.0;
2183 double alpha_min = 1.0;
2184
2185 NSTRACE ("x_set_frame_alpha");
2186
2187 if (dpyinfo->x_highlight_frame == f)
2188 alpha = f->alpha[0];
2189 else
2190 alpha = f->alpha[1];
2191
2192 if (FLOATP (Vframe_alpha_lower_limit))
2193 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
2194 else if (INTEGERP (Vframe_alpha_lower_limit))
2195 alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
2196
2197 if (alpha < 0.0)
2198 return;
2199 else if (1.0 < alpha)
2200 alpha = 1.0;
2201 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
2202 alpha = alpha_min;
2203
2204 #ifdef NS_IMPL_COCOA
2205 {
2206 EmacsView *view = FRAME_NS_VIEW (f);
2207 [[view window] setAlphaValue: alpha];
2208 }
2209 #endif
2210 }
2211
2212
2213 /* ==========================================================================
2214
2215 Mouse handling
2216
2217 ========================================================================== */
2218
2219
2220 void
2221 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2222 /* --------------------------------------------------------------------------
2223 Programmatically reposition mouse pointer in pixel coordinates
2224 -------------------------------------------------------------------------- */
2225 {
2226 NSTRACE ("frame_set_mouse_pixel_position");
2227 ns_raise_frame (f);
2228 #if 0
2229 /* FIXME: this does not work, and what about GNUstep? */
2230 #ifdef NS_IMPL_COCOA
2231 [FRAME_NS_VIEW (f) lockFocus];
2232 PSsetmouse ((float)pix_x, (float)pix_y);
2233 [FRAME_NS_VIEW (f) unlockFocus];
2234 #endif
2235 #endif
2236 }
2237
2238 static int
2239 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2240 /* ------------------------------------------------------------------------
2241 Called by EmacsView on mouseMovement events. Passes on
2242 to emacs mainstream code if we moved off of a rect of interest
2243 known as last_mouse_glyph.
2244 ------------------------------------------------------------------------ */
2245 {
2246 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2247 NSRect *r;
2248
2249 // NSTRACE ("note_mouse_movement");
2250
2251 dpyinfo->last_mouse_motion_frame = frame;
2252 r = &dpyinfo->last_mouse_glyph;
2253
2254 /* Note, this doesn't get called for enter/leave, since we don't have a
2255 position. Those are taken care of in the corresponding NSView methods. */
2256
2257 /* has movement gone beyond last rect we were tracking? */
2258 if (x < r->origin.x || x >= r->origin.x + r->size.width
2259 || y < r->origin.y || y >= r->origin.y + r->size.height)
2260 {
2261 ns_update_begin (frame);
2262 frame->mouse_moved = 1;
2263 note_mouse_highlight (frame, x, y);
2264 remember_mouse_glyph (frame, x, y, r);
2265 ns_update_end (frame);
2266 return 1;
2267 }
2268
2269 return 0;
2270 }
2271
2272
2273 static void
2274 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2275 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2276 Time *time)
2277 /* --------------------------------------------------------------------------
2278 External (hook): inform emacs about mouse position and hit parts.
2279 If a scrollbar is being dragged, set bar_window, part, x, y, time.
2280 x & y should be position in the scrollbar (the whole bar, not the handle)
2281 and length of scrollbar respectively
2282 -------------------------------------------------------------------------- */
2283 {
2284 id view;
2285 NSPoint position;
2286 Lisp_Object frame, tail;
2287 struct frame *f;
2288 struct ns_display_info *dpyinfo;
2289
2290 NSTRACE ("ns_mouse_position");
2291
2292 if (*fp == NULL)
2293 {
2294 fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2295 return;
2296 }
2297
2298 dpyinfo = FRAME_DISPLAY_INFO (*fp);
2299
2300 block_input ();
2301
2302 /* Clear the mouse-moved flag for every frame on this display. */
2303 FOR_EACH_FRAME (tail, frame)
2304 if (FRAME_NS_P (XFRAME (frame))
2305 && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2306 XFRAME (frame)->mouse_moved = 0;
2307
2308 dpyinfo->last_mouse_scroll_bar = nil;
2309 if (dpyinfo->last_mouse_frame
2310 && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2311 f = dpyinfo->last_mouse_frame;
2312 else
2313 f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2314
2315 if (f && FRAME_NS_P (f))
2316 {
2317 view = FRAME_NS_VIEW (*fp);
2318
2319 position = [[view window] mouseLocationOutsideOfEventStream];
2320 position = [view convertPoint: position fromView: nil];
2321 remember_mouse_glyph (f, position.x, position.y,
2322 &dpyinfo->last_mouse_glyph);
2323 NSTRACE_POINT ("position", position);
2324
2325 if (bar_window) *bar_window = Qnil;
2326 if (part) *part = scroll_bar_above_handle;
2327
2328 if (x) XSETINT (*x, lrint (position.x));
2329 if (y) XSETINT (*y, lrint (position.y));
2330 if (time)
2331 *time = dpyinfo->last_mouse_movement_time;
2332 *fp = f;
2333 }
2334
2335 unblock_input ();
2336 }
2337
2338
2339 static void
2340 ns_frame_up_to_date (struct frame *f)
2341 /* --------------------------------------------------------------------------
2342 External (hook): Fix up mouse highlighting right after a full update.
2343 Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2344 -------------------------------------------------------------------------- */
2345 {
2346 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date");
2347
2348 if (FRAME_NS_P (f))
2349 {
2350 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2351 if (f == hlinfo->mouse_face_mouse_frame)
2352 {
2353 block_input ();
2354 ns_update_begin(f);
2355 note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2356 hlinfo->mouse_face_mouse_x,
2357 hlinfo->mouse_face_mouse_y);
2358 ns_update_end(f);
2359 unblock_input ();
2360 }
2361 }
2362 }
2363
2364
2365 static void
2366 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2367 /* --------------------------------------------------------------------------
2368 External (RIF): set frame mouse pointer type.
2369 -------------------------------------------------------------------------- */
2370 {
2371 NSTRACE ("ns_define_frame_cursor");
2372 if (FRAME_POINTER_TYPE (f) != cursor)
2373 {
2374 EmacsView *view = FRAME_NS_VIEW (f);
2375 FRAME_POINTER_TYPE (f) = cursor;
2376 [[view window] invalidateCursorRectsForView: view];
2377 /* Redisplay assumes this function also draws the changed frame
2378 cursor, but this function doesn't, so do it explicitly. */
2379 x_update_cursor (f, 1);
2380 }
2381 }
2382
2383
2384
2385 /* ==========================================================================
2386
2387 Keyboard handling
2388
2389 ========================================================================== */
2390
2391
2392 static unsigned
2393 ns_convert_key (unsigned code)
2394 /* --------------------------------------------------------------------------
2395 Internal call used by NSView-keyDown.
2396 -------------------------------------------------------------------------- */
2397 {
2398 const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2399 unsigned keysym;
2400 /* An array would be faster, but less easy to read. */
2401 for (keysym = 0; keysym < last_keysym; keysym += 2)
2402 if (code == convert_ns_to_X_keysym[keysym])
2403 return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2404 return 0;
2405 /* if decide to use keyCode and Carbon table, use this line:
2406 return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2407 }
2408
2409
2410 char *
2411 x_get_keysym_name (int keysym)
2412 /* --------------------------------------------------------------------------
2413 Called by keyboard.c. Not sure if the return val is important, except
2414 that it be unique.
2415 -------------------------------------------------------------------------- */
2416 {
2417 static char value[16];
2418 NSTRACE ("x_get_keysym_name");
2419 sprintf (value, "%d", keysym);
2420 return value;
2421 }
2422
2423
2424
2425 /* ==========================================================================
2426
2427 Block drawing operations
2428
2429 ========================================================================== */
2430
2431
2432 static void
2433 ns_redraw_scroll_bars (struct frame *f)
2434 {
2435 int i;
2436 id view;
2437 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2438 NSTRACE ("ns_redraw_scroll_bars");
2439 for (i =[subviews count]-1; i >= 0; i--)
2440 {
2441 view = [subviews objectAtIndex: i];
2442 if (![view isKindOfClass: [EmacsScroller class]]) continue;
2443 [view display];
2444 }
2445 }
2446
2447
2448 void
2449 ns_clear_frame (struct frame *f)
2450 /* --------------------------------------------------------------------------
2451 External (hook): Erase the entire frame
2452 -------------------------------------------------------------------------- */
2453 {
2454 NSView *view = FRAME_NS_VIEW (f);
2455 NSRect r;
2456
2457 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame");
2458
2459 /* comes on initial frame because we have
2460 after-make-frame-functions = select-frame */
2461 if (!FRAME_DEFAULT_FACE (f))
2462 return;
2463
2464 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2465
2466 r = [view bounds];
2467
2468 block_input ();
2469 ns_focus (f, &r, 1);
2470 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2471 NSRectFill (r);
2472 ns_unfocus (f);
2473
2474 /* as of 2006/11 or so this is now needed */
2475 ns_redraw_scroll_bars (f);
2476 unblock_input ();
2477 }
2478
2479
2480 static void
2481 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2482 /* --------------------------------------------------------------------------
2483 External (RIF): Clear section of frame
2484 -------------------------------------------------------------------------- */
2485 {
2486 NSRect r = NSMakeRect (x, y, width, height);
2487 NSView *view = FRAME_NS_VIEW (f);
2488 struct face *face = FRAME_DEFAULT_FACE (f);
2489
2490 if (!view || !face)
2491 return;
2492
2493 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
2494
2495 r = NSIntersectionRect (r, [view frame]);
2496 ns_focus (f, &r, 1);
2497 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2498
2499 NSRectFill (r);
2500
2501 ns_unfocus (f);
2502 return;
2503 }
2504
2505 static void
2506 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2507 {
2508 NSTRACE ("ns_copy_bits");
2509
2510 if (FRAME_NS_VIEW (f))
2511 {
2512 hide_bell(); // Ensure the bell image isn't scrolled.
2513
2514 ns_focus (f, &dest, 1);
2515 [FRAME_NS_VIEW (f) scrollRect: src
2516 by: NSMakeSize (dest.origin.x - src.origin.x,
2517 dest.origin.y - src.origin.y)];
2518 ns_unfocus (f);
2519 }
2520 }
2521
2522 static void
2523 ns_scroll_run (struct window *w, struct run *run)
2524 /* --------------------------------------------------------------------------
2525 External (RIF): Insert or delete n lines at line vpos
2526 -------------------------------------------------------------------------- */
2527 {
2528 struct frame *f = XFRAME (w->frame);
2529 int x, y, width, height, from_y, to_y, bottom_y;
2530
2531 NSTRACE ("ns_scroll_run");
2532
2533 /* begin copy from other terms */
2534 /* Get frame-relative bounding box of the text display area of W,
2535 without mode lines. Include in this box the left and right
2536 fringe of W. */
2537 window_box (w, ANY_AREA, &x, &y, &width, &height);
2538
2539 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2540 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2541 bottom_y = y + height;
2542
2543 if (to_y < from_y)
2544 {
2545 /* Scrolling up. Make sure we don't copy part of the mode
2546 line at the bottom. */
2547 if (from_y + run->height > bottom_y)
2548 height = bottom_y - from_y;
2549 else
2550 height = run->height;
2551 }
2552 else
2553 {
2554 /* Scrolling down. Make sure we don't copy over the mode line.
2555 at the bottom. */
2556 if (to_y + run->height > bottom_y)
2557 height = bottom_y - to_y;
2558 else
2559 height = run->height;
2560 }
2561 /* end copy from other terms */
2562
2563 if (height == 0)
2564 return;
2565
2566 block_input ();
2567
2568 x_clear_cursor (w);
2569
2570 {
2571 NSRect srcRect = NSMakeRect (x, from_y, width, height);
2572 NSRect dstRect = NSMakeRect (x, to_y, width, height);
2573
2574 ns_copy_bits (f, srcRect , dstRect);
2575 }
2576
2577 unblock_input ();
2578 }
2579
2580
2581 static void
2582 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2583 /* --------------------------------------------------------------------------
2584 External (RIF): preparatory to fringe update after text was updated
2585 -------------------------------------------------------------------------- */
2586 {
2587 struct frame *f;
2588 int width, height;
2589
2590 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line");
2591
2592 /* begin copy from other terms */
2593 eassert (w);
2594
2595 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2596 desired_row->redraw_fringe_bitmaps_p = 1;
2597
2598 /* When a window has disappeared, make sure that no rest of
2599 full-width rows stays visible in the internal border. */
2600 if (windows_or_buffers_changed
2601 && desired_row->full_width_p
2602 && (f = XFRAME (w->frame),
2603 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2604 width != 0)
2605 && (height = desired_row->visible_height,
2606 height > 0))
2607 {
2608 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2609
2610 block_input ();
2611 ns_clear_frame_area (f, 0, y, width, height);
2612 ns_clear_frame_area (f,
2613 FRAME_PIXEL_WIDTH (f) - width,
2614 y, width, height);
2615 unblock_input ();
2616 }
2617 }
2618
2619
2620 static void
2621 ns_shift_glyphs_for_insert (struct frame *f,
2622 int x, int y, int width, int height,
2623 int shift_by)
2624 /* --------------------------------------------------------------------------
2625 External (RIF): copy an area horizontally, don't worry about clearing src
2626 -------------------------------------------------------------------------- */
2627 {
2628 NSRect srcRect = NSMakeRect (x, y, width, height);
2629 NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2630
2631 NSTRACE ("ns_shift_glyphs_for_insert");
2632
2633 ns_copy_bits (f, srcRect, dstRect);
2634 }
2635
2636
2637
2638 /* ==========================================================================
2639
2640 Character encoding and metrics
2641
2642 ========================================================================== */
2643
2644
2645 static void
2646 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2647 /* --------------------------------------------------------------------------
2648 External (RIF); compute left/right overhang of whole string and set in s
2649 -------------------------------------------------------------------------- */
2650 {
2651 struct font *font = s->font;
2652
2653 if (s->char2b)
2654 {
2655 struct font_metrics metrics;
2656 unsigned int codes[2];
2657 codes[0] = *(s->char2b);
2658 codes[1] = *(s->char2b + s->nchars - 1);
2659
2660 font->driver->text_extents (font, codes, 2, &metrics);
2661 s->left_overhang = -metrics.lbearing;
2662 s->right_overhang
2663 = metrics.rbearing > metrics.width
2664 ? metrics.rbearing - metrics.width : 0;
2665 }
2666 else
2667 {
2668 s->left_overhang = 0;
2669 if (EQ (font->driver->type, Qns))
2670 s->right_overhang = ((struct nsfont_info *)font)->ital ?
2671 FONT_HEIGHT (font) * 0.2 : 0;
2672 else
2673 s->right_overhang = 0;
2674 }
2675 }
2676
2677
2678
2679 /* ==========================================================================
2680
2681 Fringe and cursor drawing
2682
2683 ========================================================================== */
2684
2685
2686 extern int max_used_fringe_bitmap;
2687 static void
2688 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2689 struct draw_fringe_bitmap_params *p)
2690 /* --------------------------------------------------------------------------
2691 External (RIF); fringe-related
2692 -------------------------------------------------------------------------- */
2693 {
2694 /* Fringe bitmaps comes in two variants, normal and periodic. A
2695 periodic bitmap is used to create a continuous pattern. Since a
2696 bitmap is rendered one text line at a time, the start offset (dh)
2697 of the bitmap varies. Concretely, this is used for the empty
2698 line indicator.
2699
2700 For a bitmap, "h + dh" is the full height and is always
2701 invariant. For a normal bitmap "dh" is zero.
2702
2703 For example, when the period is three and the full height is 72
2704 the following combinations exists:
2705
2706 h=72 dh=0
2707 h=71 dh=1
2708 h=70 dh=2 */
2709
2710 struct frame *f = XFRAME (WINDOW_FRAME (w));
2711 struct face *face = p->face;
2712 static EmacsImage **bimgs = NULL;
2713 static int nBimgs = 0;
2714
2715 NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
2716 NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
2717 p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
2718
2719 /* grow bimgs if needed */
2720 if (nBimgs < max_used_fringe_bitmap)
2721 {
2722 bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2723 memset (bimgs + nBimgs, 0,
2724 (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2725 nBimgs = max_used_fringe_bitmap;
2726 }
2727
2728 /* Must clip because of partially visible lines. */
2729 ns_clip_to_row (w, row, ANY_AREA, YES);
2730
2731 if (!p->overlay_p)
2732 {
2733 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2734
2735 if (bx >= 0 && nx > 0)
2736 {
2737 NSRect r = NSMakeRect (bx, by, nx, ny);
2738 NSRectClip (r);
2739 [ns_lookup_indexed_color (face->background, f) set];
2740 NSRectFill (r);
2741 }
2742 }
2743
2744 if (p->which)
2745 {
2746 NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2747 EmacsImage *img = bimgs[p->which - 1];
2748
2749 if (!img)
2750 {
2751 // Note: For "periodic" images, allocate one EmacsImage for
2752 // the base image, and use it for all dh:s.
2753 unsigned short *bits = p->bits;
2754 int full_height = p->h + p->dh;
2755 int i;
2756 unsigned char *cbits = xmalloc (full_height);
2757
2758 for (i = 0; i < full_height; i++)
2759 cbits[i] = bits[i];
2760 img = [[EmacsImage alloc] initFromXBM: cbits width: 8
2761 height: full_height
2762 fg: 0 bg: 0];
2763 bimgs[p->which - 1] = img;
2764 xfree (cbits);
2765 }
2766
2767 NSTRACE_RECT ("r", r);
2768
2769 NSRectClip (r);
2770 /* Since we composite the bitmap instead of just blitting it, we need
2771 to erase the whole background. */
2772 [ns_lookup_indexed_color(face->background, f) set];
2773 NSRectFill (r);
2774
2775 {
2776 NSColor *bm_color;
2777 if (!p->cursor_p)
2778 bm_color = ns_lookup_indexed_color(face->foreground, f);
2779 else if (p->overlay_p)
2780 bm_color = ns_lookup_indexed_color(face->background, f);
2781 else
2782 bm_color = f->output_data.ns->cursor_color;
2783 [img setXBMColor: bm_color];
2784 }
2785
2786 #ifdef NS_IMPL_COCOA
2787 // Note: For periodic images, the full image height is "h + hd".
2788 // By using the height h, a suitable part of the image is used.
2789 NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
2790
2791 NSTRACE_RECT ("fromRect", fromRect);
2792
2793 [img drawInRect: r
2794 fromRect: fromRect
2795 operation: NSCompositeSourceOver
2796 fraction: 1.0
2797 respectFlipped: YES
2798 hints: nil];
2799 #else
2800 {
2801 NSPoint pt = r.origin;
2802 pt.y += p->h;
2803 [img compositeToPoint: pt operation: NSCompositeSourceOver];
2804 }
2805 #endif
2806 }
2807 ns_unfocus (f);
2808 }
2809
2810
2811 static void
2812 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2813 int x, int y, enum text_cursor_kinds cursor_type,
2814 int cursor_width, bool on_p, bool active_p)
2815 /* --------------------------------------------------------------------------
2816 External call (RIF): draw cursor.
2817 Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2818 -------------------------------------------------------------------------- */
2819 {
2820 NSRect r, s;
2821 int fx, fy, h, cursor_height;
2822 struct frame *f = WINDOW_XFRAME (w);
2823 struct glyph *phys_cursor_glyph;
2824 struct glyph *cursor_glyph;
2825 struct face *face;
2826 NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2827
2828 /* If cursor is out of bounds, don't draw garbage. This can happen
2829 in mini-buffer windows when switching between echo area glyphs
2830 and mini-buffer. */
2831
2832 NSTRACE ("ns_draw_window_cursor");
2833
2834 if (!on_p)
2835 return;
2836
2837 w->phys_cursor_type = cursor_type;
2838 w->phys_cursor_on_p = on_p;
2839
2840 if (cursor_type == NO_CURSOR)
2841 {
2842 w->phys_cursor_width = 0;
2843 return;
2844 }
2845
2846 if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2847 {
2848 if (glyph_row->exact_window_width_line_p
2849 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2850 {
2851 glyph_row->cursor_in_fringe_p = 1;
2852 draw_fringe_bitmap (w, glyph_row, 0);
2853 }
2854 return;
2855 }
2856
2857 /* We draw the cursor (with NSRectFill), then draw the glyph on top
2858 (other terminals do it the other way round). We must set
2859 w->phys_cursor_width to the cursor width. For bar cursors, that
2860 is CURSOR_WIDTH; for box cursors, it is the glyph width. */
2861 get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2862
2863 /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2864 to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2865 if (cursor_type == BAR_CURSOR)
2866 {
2867 if (cursor_width < 1)
2868 cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2869 w->phys_cursor_width = cursor_width;
2870 }
2871 /* If we have an HBAR, "cursor_width" MAY specify height. */
2872 else if (cursor_type == HBAR_CURSOR)
2873 {
2874 cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2875 if (cursor_height > glyph_row->height)
2876 cursor_height = glyph_row->height;
2877 if (h > cursor_height) // Cursor smaller than line height, move down
2878 fy += h - cursor_height;
2879 h = cursor_height;
2880 }
2881
2882 r.origin.x = fx, r.origin.y = fy;
2883 r.size.height = h;
2884 r.size.width = w->phys_cursor_width;
2885
2886 /* TODO: only needed in rare cases with last-resort font in HELLO..
2887 should we do this more efficiently? */
2888 ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2889
2890
2891 face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2892 if (face && NS_FACE_BACKGROUND (face)
2893 == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2894 {
2895 [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2896 hollow_color = FRAME_CURSOR_COLOR (f);
2897 }
2898 else
2899 [FRAME_CURSOR_COLOR (f) set];
2900
2901 #ifdef NS_IMPL_COCOA
2902 /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2903 atomic. Cleaner ways of doing this should be investigated.
2904 One way would be to set a global variable DRAWING_CURSOR
2905 when making the call to draw_phys..(), don't focus in that
2906 case, then move the ns_unfocus() here after that call. */
2907 NSDisableScreenUpdates ();
2908 #endif
2909
2910 switch (cursor_type)
2911 {
2912 case DEFAULT_CURSOR:
2913 case NO_CURSOR:
2914 break;
2915 case FILLED_BOX_CURSOR:
2916 NSRectFill (r);
2917 break;
2918 case HOLLOW_BOX_CURSOR:
2919 NSRectFill (r);
2920 [hollow_color set];
2921 NSRectFill (NSInsetRect (r, 1, 1));
2922 [FRAME_CURSOR_COLOR (f) set];
2923 break;
2924 case HBAR_CURSOR:
2925 NSRectFill (r);
2926 break;
2927 case BAR_CURSOR:
2928 s = r;
2929 /* If the character under cursor is R2L, draw the bar cursor
2930 on the right of its glyph, rather than on the left. */
2931 cursor_glyph = get_phys_cursor_glyph (w);
2932 if ((cursor_glyph->resolved_level & 1) != 0)
2933 s.origin.x += cursor_glyph->pixel_width - s.size.width;
2934
2935 NSRectFill (s);
2936 break;
2937 }
2938 ns_unfocus (f);
2939
2940 /* draw the character under the cursor */
2941 if (cursor_type != NO_CURSOR)
2942 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2943
2944 #ifdef NS_IMPL_COCOA
2945 NSEnableScreenUpdates ();
2946 #endif
2947
2948 }
2949
2950
2951 static void
2952 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2953 /* --------------------------------------------------------------------------
2954 External (RIF): Draw a vertical line.
2955 -------------------------------------------------------------------------- */
2956 {
2957 struct frame *f = XFRAME (WINDOW_FRAME (w));
2958 struct face *face;
2959 NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2960
2961 NSTRACE ("ns_draw_vertical_window_border");
2962
2963 face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2964 if (face)
2965 [ns_lookup_indexed_color(face->foreground, f) set];
2966
2967 ns_focus (f, &r, 1);
2968 NSRectFill(r);
2969 ns_unfocus (f);
2970 }
2971
2972
2973 static void
2974 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
2975 /* --------------------------------------------------------------------------
2976 External (RIF): Draw a window divider.
2977 -------------------------------------------------------------------------- */
2978 {
2979 struct frame *f = XFRAME (WINDOW_FRAME (w));
2980 struct face *face;
2981 NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
2982
2983 NSTRACE ("ns_draw_window_divider");
2984
2985 face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID);
2986 if (face)
2987 [ns_lookup_indexed_color(face->foreground, f) set];
2988
2989 ns_focus (f, &r, 1);
2990 NSRectFill(r);
2991 ns_unfocus (f);
2992 }
2993
2994 static void
2995 ns_show_hourglass (struct frame *f)
2996 {
2997 /* TODO: add NSProgressIndicator to all frames. */
2998 }
2999
3000 static void
3001 ns_hide_hourglass (struct frame *f)
3002 {
3003 /* TODO: remove NSProgressIndicator from all frames. */
3004 }
3005
3006 /* ==========================================================================
3007
3008 Glyph drawing operations
3009
3010 ========================================================================== */
3011
3012 static int
3013 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
3014 /* --------------------------------------------------------------------------
3015 Wrapper utility to account for internal border width on full-width lines,
3016 and allow top full-width rows to hit the frame top. nr should be pointer
3017 to two successive NSRects. Number of rects actually used is returned.
3018 -------------------------------------------------------------------------- */
3019 {
3020 int n = get_glyph_string_clip_rects (s, nr, 2);
3021 return n;
3022 }
3023
3024 /* --------------------------------------------------------------------
3025 Draw a wavy line under glyph string s. The wave fills wave_height
3026 pixels from y.
3027
3028 x wave_length = 2
3029 --
3030 y * * * * *
3031 |* * * * * * * * *
3032 wave_height = 3 | * * * *
3033 --------------------------------------------------------------------- */
3034
3035 static void
3036 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
3037 {
3038 int wave_height = 3, wave_length = 2;
3039 int y, dx, dy, odd, xmax;
3040 NSPoint a, b;
3041 NSRect waveClip;
3042
3043 dx = wave_length;
3044 dy = wave_height - 1;
3045 y = s->ybase - wave_height + 3;
3046 xmax = x + width;
3047
3048 /* Find and set clipping rectangle */
3049 waveClip = NSMakeRect (x, y, width, wave_height);
3050 [[NSGraphicsContext currentContext] saveGraphicsState];
3051 NSRectClip (waveClip);
3052
3053 /* Draw the waves */
3054 a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
3055 b.x = a.x + dx;
3056 odd = (int)(a.x/dx) % 2;
3057 a.y = b.y = y + 0.5;
3058
3059 if (odd)
3060 a.y += dy;
3061 else
3062 b.y += dy;
3063
3064 while (a.x <= xmax)
3065 {
3066 [NSBezierPath strokeLineFromPoint:a toPoint:b];
3067 a.x = b.x, a.y = b.y;
3068 b.x += dx, b.y = y + 0.5 + odd*dy;
3069 odd = !odd;
3070 }
3071
3072 /* Restore previous clipping rectangle(s) */
3073 [[NSGraphicsContext currentContext] restoreGraphicsState];
3074 }
3075
3076
3077
3078 void
3079 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3080 NSColor *defaultCol, CGFloat width, CGFloat x)
3081 /* --------------------------------------------------------------------------
3082 Draw underline, overline, and strike-through on glyph string s.
3083 -------------------------------------------------------------------------- */
3084 {
3085 if (s->for_overlaps)
3086 return;
3087
3088 /* Do underline. */
3089 if (face->underline_p)
3090 {
3091 if (s->face->underline_type == FACE_UNDER_WAVE)
3092 {
3093 if (face->underline_defaulted_p)
3094 [defaultCol set];
3095 else
3096 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3097
3098 ns_draw_underwave (s, width, x);
3099 }
3100 else if (s->face->underline_type == FACE_UNDER_LINE)
3101 {
3102
3103 NSRect r;
3104 unsigned long thickness, position;
3105
3106 /* If the prev was underlined, match its appearance. */
3107 if (s->prev && s->prev->face->underline_p
3108 && s->prev->face->underline_type == FACE_UNDER_LINE
3109 && s->prev->underline_thickness > 0)
3110 {
3111 thickness = s->prev->underline_thickness;
3112 position = s->prev->underline_position;
3113 }
3114 else
3115 {
3116 struct font *font;
3117 unsigned long descent;
3118
3119 font=s->font;
3120 descent = s->y + s->height - s->ybase;
3121
3122 /* Use underline thickness of font, defaulting to 1. */
3123 thickness = (font && font->underline_thickness > 0)
3124 ? font->underline_thickness : 1;
3125
3126 /* Determine the offset of underlining from the baseline. */
3127 if (x_underline_at_descent_line)
3128 position = descent - thickness;
3129 else if (x_use_underline_position_properties
3130 && font && font->underline_position >= 0)
3131 position = font->underline_position;
3132 else if (font)
3133 position = lround (font->descent / 2);
3134 else
3135 position = underline_minimum_offset;
3136
3137 position = max (position, underline_minimum_offset);
3138
3139 /* Ensure underlining is not cropped. */
3140 if (descent <= position)
3141 {
3142 position = descent - 1;
3143 thickness = 1;
3144 }
3145 else if (descent < position + thickness)
3146 thickness = 1;
3147 }
3148
3149 s->underline_thickness = thickness;
3150 s->underline_position = position;
3151
3152 r = NSMakeRect (x, s->ybase + position, width, thickness);
3153
3154 if (face->underline_defaulted_p)
3155 [defaultCol set];
3156 else
3157 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3158 NSRectFill (r);
3159 }
3160 }
3161 /* Do overline. We follow other terms in using a thickness of 1
3162 and ignoring overline_margin. */
3163 if (face->overline_p)
3164 {
3165 NSRect r;
3166 r = NSMakeRect (x, s->y, width, 1);
3167
3168 if (face->overline_color_defaulted_p)
3169 [defaultCol set];
3170 else
3171 [ns_lookup_indexed_color (face->overline_color, s->f) set];
3172 NSRectFill (r);
3173 }
3174
3175 /* Do strike-through. We follow other terms for thickness and
3176 vertical position.*/
3177 if (face->strike_through_p)
3178 {
3179 NSRect r;
3180 unsigned long dy;
3181
3182 dy = lrint ((s->height - 1) / 2);
3183 r = NSMakeRect (x, s->y + dy, width, 1);
3184
3185 if (face->strike_through_color_defaulted_p)
3186 [defaultCol set];
3187 else
3188 [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
3189 NSRectFill (r);
3190 }
3191 }
3192
3193 static void
3194 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
3195 char left_p, char right_p)
3196 /* --------------------------------------------------------------------------
3197 Draw an unfilled rect inside r, optionally leaving left and/or right open.
3198 Note we can't just use an NSDrawRect command, because of the possibility
3199 of some sides not being drawn, and because the rect will be filled.
3200 -------------------------------------------------------------------------- */
3201 {
3202 NSRect s = r;
3203 [col set];
3204
3205 /* top, bottom */
3206 s.size.height = thickness;
3207 NSRectFill (s);
3208 s.origin.y += r.size.height - thickness;
3209 NSRectFill (s);
3210
3211 s.size.height = r.size.height;
3212 s.origin.y = r.origin.y;
3213
3214 /* left, right (optional) */
3215 s.size.width = thickness;
3216 if (left_p)
3217 NSRectFill (s);
3218 if (right_p)
3219 {
3220 s.origin.x += r.size.width - thickness;
3221 NSRectFill (s);
3222 }
3223 }
3224
3225
3226 static void
3227 ns_draw_relief (NSRect r, int thickness, char raised_p,
3228 char top_p, char bottom_p, char left_p, char right_p,
3229 struct glyph_string *s)
3230 /* --------------------------------------------------------------------------
3231 Draw a relief rect inside r, optionally leaving some sides open.
3232 Note we can't just use an NSDrawBezel command, because of the possibility
3233 of some sides not being drawn, and because the rect will be filled.
3234 -------------------------------------------------------------------------- */
3235 {
3236 static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3237 NSColor *newBaseCol = nil;
3238 NSRect sr = r;
3239
3240 NSTRACE ("ns_draw_relief");
3241
3242 /* set up colors */
3243
3244 if (s->face->use_box_color_for_shadows_p)
3245 {
3246 newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
3247 }
3248 /* else if (s->first_glyph->type == IMAGE_GLYPH
3249 && s->img->pixmap
3250 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3251 {
3252 newBaseCol = IMAGE_BACKGROUND (s->img, s->f, 0);
3253 } */
3254 else
3255 {
3256 newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
3257 }
3258
3259 if (newBaseCol == nil)
3260 newBaseCol = [NSColor grayColor];
3261
3262 if (newBaseCol != baseCol) /* TODO: better check */
3263 {
3264 [baseCol release];
3265 baseCol = [newBaseCol retain];
3266 [lightCol release];
3267 lightCol = [[baseCol highlightWithLevel: 0.2] retain];
3268 [darkCol release];
3269 darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3270 }
3271
3272 [(raised_p ? lightCol : darkCol) set];
3273
3274 /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
3275
3276 /* top */
3277 sr.size.height = thickness;
3278 if (top_p) NSRectFill (sr);
3279
3280 /* left */
3281 sr.size.height = r.size.height;
3282 sr.size.width = thickness;
3283 if (left_p) NSRectFill (sr);
3284
3285 [(raised_p ? darkCol : lightCol) set];
3286
3287 /* bottom */
3288 sr.size.width = r.size.width;
3289 sr.size.height = thickness;
3290 sr.origin.y += r.size.height - thickness;
3291 if (bottom_p) NSRectFill (sr);
3292
3293 /* right */
3294 sr.size.height = r.size.height;
3295 sr.origin.y = r.origin.y;
3296 sr.size.width = thickness;
3297 sr.origin.x += r.size.width - thickness;
3298 if (right_p) NSRectFill (sr);
3299 }
3300
3301
3302 static void
3303 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3304 /* --------------------------------------------------------------------------
3305 Function modeled after x_draw_glyph_string_box ().
3306 Sets up parameters for drawing.
3307 -------------------------------------------------------------------------- */
3308 {
3309 int right_x, last_x;
3310 char left_p, right_p;
3311 struct glyph *last_glyph;
3312 NSRect r;
3313 int thickness;
3314 struct face *face;
3315
3316 if (s->hl == DRAW_MOUSE_FACE)
3317 {
3318 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3319 if (!face)
3320 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3321 }
3322 else
3323 face = s->face;
3324
3325 thickness = face->box_line_width;
3326
3327 NSTRACE ("ns_dumpglyphs_box_or_relief");
3328
3329 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3330 ? WINDOW_RIGHT_EDGE_X (s->w)
3331 : window_box_right (s->w, s->area));
3332 last_glyph = (s->cmp || s->img
3333 ? s->first_glyph : s->first_glyph + s->nchars-1);
3334
3335 right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3336 ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3337
3338 left_p = (s->first_glyph->left_box_line_p
3339 || (s->hl == DRAW_MOUSE_FACE
3340 && (s->prev == NULL || s->prev->hl != s->hl)));
3341 right_p = (last_glyph->right_box_line_p
3342 || (s->hl == DRAW_MOUSE_FACE
3343 && (s->next == NULL || s->next->hl != s->hl)));
3344
3345 r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3346
3347 /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
3348 if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3349 {
3350 ns_draw_box (r, abs (thickness),
3351 ns_lookup_indexed_color (face->box_color, s->f),
3352 left_p, right_p);
3353 }
3354 else
3355 {
3356 ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3357 1, 1, left_p, right_p, s);
3358 }
3359 }
3360
3361
3362 static void
3363 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3364 /* --------------------------------------------------------------------------
3365 Modeled after x_draw_glyph_string_background, which draws BG in
3366 certain cases. Others are left to the text rendering routine.
3367 -------------------------------------------------------------------------- */
3368 {
3369 NSTRACE ("ns_maybe_dumpglyphs_background");
3370
3371 if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3372 {
3373 int box_line_width = max (s->face->box_line_width, 0);
3374 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3375 /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3376 dimensions, since the actual glyphs might be much
3377 smaller. So in that case we always clear the rectangle
3378 with background color. */
3379 || FONT_TOO_HIGH (s->font)
3380 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3381 {
3382 struct face *face;
3383 if (s->hl == DRAW_MOUSE_FACE)
3384 {
3385 face = FACE_FROM_ID (s->f,
3386 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3387 if (!face)
3388 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3389 }
3390 else
3391 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3392 if (!face->stipple)
3393 [(NS_FACE_BACKGROUND (face) != 0
3394 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3395 : FRAME_BACKGROUND_COLOR (s->f)) set];
3396 else
3397 {
3398 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3399 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3400 }
3401
3402 if (s->hl != DRAW_CURSOR)
3403 {
3404 NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3405 s->background_width,
3406 s->height-2*box_line_width);
3407 NSRectFill (r);
3408 }
3409
3410 s->background_filled_p = 1;
3411 }
3412 }
3413 }
3414
3415
3416 static void
3417 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3418 /* --------------------------------------------------------------------------
3419 Renders an image and associated borders.
3420 -------------------------------------------------------------------------- */
3421 {
3422 EmacsImage *img = s->img->pixmap;
3423 int box_line_vwidth = max (s->face->box_line_width, 0);
3424 int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3425 int bg_x, bg_y, bg_height;
3426 int th;
3427 char raised_p;
3428 NSRect br;
3429 struct face *face;
3430 NSColor *tdCol;
3431
3432 NSTRACE ("ns_dumpglyphs_image");
3433
3434 if (s->face->box != FACE_NO_BOX
3435 && s->first_glyph->left_box_line_p && s->slice.x == 0)
3436 x += abs (s->face->box_line_width);
3437
3438 bg_x = x;
3439 bg_y = s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3440 bg_height = s->height;
3441 /* other terms have this, but was causing problems w/tabbar mode */
3442 /* - 2 * box_line_vwidth; */
3443
3444 if (s->slice.x == 0) x += s->img->hmargin;
3445 if (s->slice.y == 0) y += s->img->vmargin;
3446
3447 /* Draw BG: if we need larger area than image itself cleared, do that,
3448 otherwise, since we composite the image under NS (instead of mucking
3449 with its background color), we must clear just the image area. */
3450 if (s->hl == DRAW_MOUSE_FACE)
3451 {
3452 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3453 if (!face)
3454 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3455 }
3456 else
3457 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3458
3459 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3460
3461 if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3462 || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3463 {
3464 br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3465 s->background_filled_p = 1;
3466 }
3467 else
3468 {
3469 br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3470 }
3471
3472 NSRectFill (br);
3473
3474 /* Draw the image.. do we need to draw placeholder if img ==nil? */
3475 if (img != nil)
3476 {
3477 #ifdef NS_IMPL_COCOA
3478 NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3479 NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3480 s->slice.width, s->slice.height);
3481 [img drawInRect: dr
3482 fromRect: ir
3483 operation: NSCompositeSourceOver
3484 fraction: 1.0
3485 respectFlipped: YES
3486 hints: nil];
3487 #else
3488 [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3489 operation: NSCompositeSourceOver];
3490 #endif
3491 }
3492
3493 if (s->hl == DRAW_CURSOR)
3494 {
3495 [FRAME_CURSOR_COLOR (s->f) set];
3496 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3497 tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3498 else
3499 /* Currently on NS img->mask is always 0. Since
3500 get_window_cursor_type specifies a hollow box cursor when on
3501 a non-masked image we never reach this clause. But we put it
3502 in in anticipation of better support for image masks on
3503 NS. */
3504 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3505 }
3506 else
3507 {
3508 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3509 }
3510
3511 /* Draw underline, overline, strike-through. */
3512 ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3513
3514 /* Draw relief, if requested */
3515 if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3516 {
3517 if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3518 {
3519 th = tool_bar_button_relief >= 0 ?
3520 tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3521 raised_p = (s->hl == DRAW_IMAGE_RAISED);
3522 }
3523 else
3524 {
3525 th = abs (s->img->relief);
3526 raised_p = (s->img->relief > 0);
3527 }
3528
3529 r.origin.x = x - th;
3530 r.origin.y = y - th;
3531 r.size.width = s->slice.width + 2*th-1;
3532 r.size.height = s->slice.height + 2*th-1;
3533 ns_draw_relief (r, th, raised_p,
3534 s->slice.y == 0,
3535 s->slice.y + s->slice.height == s->img->height,
3536 s->slice.x == 0,
3537 s->slice.x + s->slice.width == s->img->width, s);
3538 }
3539
3540 /* If there is no mask, the background won't be seen,
3541 so draw a rectangle on the image for the cursor.
3542 Do this for all images, getting transparency right is not reliable. */
3543 if (s->hl == DRAW_CURSOR)
3544 {
3545 int thickness = abs (s->img->relief);
3546 if (thickness == 0) thickness = 1;
3547 ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3548 }
3549 }
3550
3551
3552 static void
3553 ns_dumpglyphs_stretch (struct glyph_string *s)
3554 {
3555 NSRect r[2];
3556 int n, i;
3557 struct face *face;
3558 NSColor *fgCol, *bgCol;
3559
3560 if (!s->background_filled_p)
3561 {
3562 n = ns_get_glyph_string_clip_rect (s, r);
3563 *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3564
3565 ns_focus (s->f, r, n);
3566
3567 if (s->hl == DRAW_MOUSE_FACE)
3568 {
3569 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3570 if (!face)
3571 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3572 }
3573 else
3574 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3575
3576 bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3577 fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3578
3579 for (i = 0; i < n; ++i)
3580 {
3581 if (!s->row->full_width_p)
3582 {
3583 int overrun, leftoverrun;
3584
3585 /* truncate to avoid overwriting fringe and/or scrollbar */
3586 overrun = max (0, (s->x + s->background_width)
3587 - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3588 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3589 r[i].size.width -= overrun;
3590
3591 /* truncate to avoid overwriting to left of the window box */
3592 leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3593 + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3594
3595 if (leftoverrun > 0)
3596 {
3597 r[i].origin.x += leftoverrun;
3598 r[i].size.width -= leftoverrun;
3599 }
3600
3601 /* XXX: Try to work between problem where a stretch glyph on
3602 a partially-visible bottom row will clear part of the
3603 modeline, and another where list-buffers headers and similar
3604 rows erroneously have visible_height set to 0. Not sure
3605 where this is coming from as other terms seem not to show. */
3606 r[i].size.height = min (s->height, s->row->visible_height);
3607 }
3608
3609 [bgCol set];
3610
3611 /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3612 overwriting cursor (usually when cursor on a tab) */
3613 if (s->hl == DRAW_CURSOR)
3614 {
3615 CGFloat x, width;
3616
3617 x = r[i].origin.x;
3618 width = s->w->phys_cursor_width;
3619 r[i].size.width -= width;
3620 r[i].origin.x += width;
3621
3622 NSRectFill (r[i]);
3623
3624 /* Draw overlining, etc. on the cursor. */
3625 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3626 ns_draw_text_decoration (s, face, bgCol, width, x);
3627 else
3628 ns_draw_text_decoration (s, face, fgCol, width, x);
3629 }
3630 else
3631 {
3632 NSRectFill (r[i]);
3633 }
3634
3635 /* Draw overlining, etc. on the stretch glyph (or the part
3636 of the stretch glyph after the cursor). */
3637 ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3638 r[i].origin.x);
3639 }
3640 ns_unfocus (s->f);
3641 s->background_filled_p = 1;
3642 }
3643 }
3644
3645
3646 static void
3647 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
3648 {
3649 int i, j, x;
3650 struct font *font = s->font;
3651
3652 /* If first glyph of S has a left box line, start drawing the text
3653 of S to the right of that box line. */
3654 if (s->face && s->face->box != FACE_NO_BOX
3655 && s->first_glyph->left_box_line_p)
3656 x = s->x + eabs (s->face->box_line_width);
3657 else
3658 x = s->x;
3659
3660 /* S is a glyph string for a composition. S->cmp_from is the index
3661 of the first character drawn for glyphs of this composition.
3662 S->cmp_from == 0 means we are drawing the very first character of
3663 this composition. */
3664
3665 /* Draw a rectangle for the composition if the font for the very
3666 first character of the composition could not be loaded. */
3667 if (s->font_not_found_p)
3668 {
3669 if (s->cmp_from == 0)
3670 {
3671 NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
3672 ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
3673 }
3674 }
3675 else if (! s->first_glyph->u.cmp.automatic)
3676 {
3677 int y = s->ybase;
3678
3679 for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
3680 /* TAB in a composition means display glyphs with padding
3681 space on the left or right. */
3682 if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
3683 {
3684 int xx = x + s->cmp->offsets[j * 2];
3685 int yy = y - s->cmp->offsets[j * 2 + 1];
3686
3687 font->driver->draw (s, j, j + 1, xx, yy, false);
3688 if (s->face->overstrike)
3689 font->driver->draw (s, j, j + 1, xx + 1, yy, false);
3690 }
3691 }
3692 else
3693 {
3694 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
3695 Lisp_Object glyph;
3696 int y = s->ybase;
3697 int width = 0;
3698
3699 for (i = j = s->cmp_from; i < s->cmp_to; i++)
3700 {
3701 glyph = LGSTRING_GLYPH (gstring, i);
3702 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
3703 width += LGLYPH_WIDTH (glyph);
3704 else
3705 {
3706 int xoff, yoff, wadjust;
3707
3708 if (j < i)
3709 {
3710 font->driver->draw (s, j, i, x, y, false);
3711 if (s->face->overstrike)
3712 font->driver->draw (s, j, i, x + 1, y, false);
3713 x += width;
3714 }
3715 xoff = LGLYPH_XOFF (glyph);
3716 yoff = LGLYPH_YOFF (glyph);
3717 wadjust = LGLYPH_WADJUST (glyph);
3718 font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
3719 if (s->face->overstrike)
3720 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
3721 false);
3722 x += wadjust;
3723 j = i + 1;
3724 width = 0;
3725 }
3726 }
3727 if (j < i)
3728 {
3729 font->driver->draw (s, j, i, x, y, false);
3730 if (s->face->overstrike)
3731 font->driver->draw (s, j, i, x + 1, y, false);
3732 }
3733 }
3734 }
3735
3736 static void
3737 ns_draw_glyph_string (struct glyph_string *s)
3738 /* --------------------------------------------------------------------------
3739 External (RIF): Main draw-text call.
3740 -------------------------------------------------------------------------- */
3741 {
3742 /* TODO (optimize): focus for box and contents draw */
3743 NSRect r[2];
3744 int n, flags;
3745 char box_drawn_p = 0;
3746 struct font *font = s->face->font;
3747 if (! font) font = FRAME_FONT (s->f);
3748
3749 NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
3750
3751 if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3752 {
3753 int width;
3754 struct glyph_string *next;
3755
3756 for (width = 0, next = s->next;
3757 next && width < s->right_overhang;
3758 width += next->width, next = next->next)
3759 if (next->first_glyph->type != IMAGE_GLYPH)
3760 {
3761 if (next->first_glyph->type != STRETCH_GLYPH)
3762 {
3763 n = ns_get_glyph_string_clip_rect (s->next, r);
3764 ns_focus (s->f, r, n);
3765 ns_maybe_dumpglyphs_background (s->next, 1);
3766 ns_unfocus (s->f);
3767 }
3768 else
3769 {
3770 ns_dumpglyphs_stretch (s->next);
3771 }
3772 next->num_clips = 0;
3773 }
3774 }
3775
3776 if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3777 && (s->first_glyph->type == CHAR_GLYPH
3778 || s->first_glyph->type == COMPOSITE_GLYPH))
3779 {
3780 n = ns_get_glyph_string_clip_rect (s, r);
3781 ns_focus (s->f, r, n);
3782 ns_maybe_dumpglyphs_background (s, 1);
3783 ns_dumpglyphs_box_or_relief (s);
3784 ns_unfocus (s->f);
3785 box_drawn_p = 1;
3786 }
3787
3788 switch (s->first_glyph->type)
3789 {
3790
3791 case IMAGE_GLYPH:
3792 n = ns_get_glyph_string_clip_rect (s, r);
3793 ns_focus (s->f, r, n);
3794 ns_dumpglyphs_image (s, r[0]);
3795 ns_unfocus (s->f);
3796 break;
3797
3798 case STRETCH_GLYPH:
3799 ns_dumpglyphs_stretch (s);
3800 break;
3801
3802 case CHAR_GLYPH:
3803 case COMPOSITE_GLYPH:
3804 n = ns_get_glyph_string_clip_rect (s, r);
3805 ns_focus (s->f, r, n);
3806
3807 if (s->for_overlaps || (s->cmp_from > 0
3808 && ! s->first_glyph->u.cmp.automatic))
3809 s->background_filled_p = 1;
3810 else
3811 ns_maybe_dumpglyphs_background
3812 (s, s->first_glyph->type == COMPOSITE_GLYPH);
3813
3814 flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3815 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3816 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3817 NS_DUMPGLYPH_NORMAL));
3818
3819 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3820 {
3821 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3822 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3823 NS_FACE_FOREGROUND (s->face) = tmp;
3824 }
3825
3826 {
3827 BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
3828
3829 if (isComposite)
3830 ns_draw_composite_glyph_string_foreground (s);
3831 else
3832 font->driver->draw
3833 (s, s->cmp_from, s->nchars, s->x, s->ybase,
3834 (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3835 || flags == NS_DUMPGLYPH_MOUSEFACE);
3836 }
3837
3838 {
3839 NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3840 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3841 s->f)
3842 : FRAME_FOREGROUND_COLOR (s->f));
3843 [col set];
3844
3845 /* Draw underline, overline, strike-through. */
3846 ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3847 }
3848
3849 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3850 {
3851 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3852 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3853 NS_FACE_FOREGROUND (s->face) = tmp;
3854 }
3855
3856 ns_unfocus (s->f);
3857 break;
3858
3859 case GLYPHLESS_GLYPH:
3860 n = ns_get_glyph_string_clip_rect (s, r);
3861 ns_focus (s->f, r, n);
3862
3863 if (s->for_overlaps || (s->cmp_from > 0
3864 && ! s->first_glyph->u.cmp.automatic))
3865 s->background_filled_p = 1;
3866 else
3867 ns_maybe_dumpglyphs_background
3868 (s, s->first_glyph->type == COMPOSITE_GLYPH);
3869 /* ... */
3870 /* Not yet implemented. */
3871 /* ... */
3872 ns_unfocus (s->f);
3873 break;
3874
3875 default:
3876 emacs_abort ();
3877 }
3878
3879 /* Draw box if not done already. */
3880 if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3881 {
3882 n = ns_get_glyph_string_clip_rect (s, r);
3883 ns_focus (s->f, r, n);
3884 ns_dumpglyphs_box_or_relief (s);
3885 ns_unfocus (s->f);
3886 }
3887
3888 s->num_clips = 0;
3889 }
3890
3891
3892
3893 /* ==========================================================================
3894
3895 Event loop
3896
3897 ========================================================================== */
3898
3899
3900 static void
3901 ns_send_appdefined (int value)
3902 /* --------------------------------------------------------------------------
3903 Internal: post an appdefined event which EmacsApp-sendEvent will
3904 recognize and take as a command to halt the event loop.
3905 -------------------------------------------------------------------------- */
3906 {
3907 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value);
3908
3909 #ifdef NS_IMPL_GNUSTEP
3910 // GNUstep needs postEvent to happen on the main thread.
3911 if (! [[NSThread currentThread] isMainThread])
3912 {
3913 EmacsApp *app = (EmacsApp *)NSApp;
3914 app->nextappdefined = value;
3915 [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3916 withObject:nil
3917 waitUntilDone:YES];
3918 return;
3919 }
3920 #endif
3921
3922 /* Only post this event if we haven't already posted one. This will end
3923 the [NXApp run] main loop after having processed all events queued at
3924 this moment. */
3925
3926 #ifdef NS_IMPL_COCOA
3927 if (! send_appdefined)
3928 {
3929 /* OSX 10.10.1 swallows the AppDefined event we are sending ourselves
3930 in certain situations (rapid incoming events).
3931 So check if we have one, if not add one. */
3932 NSEvent *appev = [NSApp nextEventMatchingMask:NSApplicationDefinedMask
3933 untilDate:[NSDate distantPast]
3934 inMode:NSDefaultRunLoopMode
3935 dequeue:NO];
3936 if (! appev) send_appdefined = YES;
3937 }
3938 #endif
3939
3940 if (send_appdefined)
3941 {
3942 NSEvent *nxev;
3943
3944 /* We only need one NX_APPDEFINED event to stop NXApp from running. */
3945 send_appdefined = NO;
3946
3947 /* Don't need wakeup timer any more */
3948 if (timed_entry)
3949 {
3950 [timed_entry invalidate];
3951 [timed_entry release];
3952 timed_entry = nil;
3953 }
3954
3955 nxev = [NSEvent otherEventWithType: NSApplicationDefined
3956 location: NSMakePoint (0, 0)
3957 modifierFlags: 0
3958 timestamp: 0
3959 windowNumber: [[NSApp mainWindow] windowNumber]
3960 context: [NSApp context]
3961 subtype: 0
3962 data1: value
3963 data2: 0];
3964
3965 /* Post an application defined event on the event queue. When this is
3966 received the [NXApp run] will return, thus having processed all
3967 events which are currently queued. */
3968 [NSApp postEvent: nxev atStart: NO];
3969 }
3970 }
3971
3972 #ifdef HAVE_NATIVE_FS
3973 static void
3974 check_native_fs ()
3975 {
3976 Lisp_Object frame, tail;
3977
3978 if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3979 return;
3980
3981 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3982
3983 FOR_EACH_FRAME (tail, frame)
3984 {
3985 struct frame *f = XFRAME (frame);
3986 if (FRAME_NS_P (f))
3987 {
3988 EmacsView *view = FRAME_NS_VIEW (f);
3989 [view updateCollectionBehavior];
3990 }
3991 }
3992 }
3993 #endif
3994
3995 /* GNUstep does not have cancelTracking. */
3996 #ifdef NS_IMPL_COCOA
3997 /* Check if menu open should be canceled or continued as normal. */
3998 void
3999 ns_check_menu_open (NSMenu *menu)
4000 {
4001 /* Click in menu bar? */
4002 NSArray *a = [[NSApp mainMenu] itemArray];
4003 int i;
4004 BOOL found = NO;
4005
4006 if (menu == nil) // Menu tracking ended.
4007 {
4008 if (menu_will_open_state == MENU_OPENING)
4009 menu_will_open_state = MENU_NONE;
4010 return;
4011 }
4012
4013 for (i = 0; ! found && i < [a count]; i++)
4014 found = menu == [[a objectAtIndex:i] submenu];
4015 if (found)
4016 {
4017 if (menu_will_open_state == MENU_NONE && emacs_event)
4018 {
4019 NSEvent *theEvent = [NSApp currentEvent];
4020 struct frame *emacsframe = SELECTED_FRAME ();
4021
4022 [menu cancelTracking];
4023 menu_will_open_state = MENU_PENDING;
4024 emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
4025 EV_TRAILER (theEvent);
4026
4027 CGEventRef ourEvent = CGEventCreate (NULL);
4028 menu_mouse_point = CGEventGetLocation (ourEvent);
4029 CFRelease (ourEvent);
4030 }
4031 else if (menu_will_open_state == MENU_OPENING)
4032 {
4033 menu_will_open_state = MENU_NONE;
4034 }
4035 }
4036 }
4037
4038 /* Redo saved menu click if state is MENU_PENDING. */
4039 void
4040 ns_check_pending_open_menu ()
4041 {
4042 if (menu_will_open_state == MENU_PENDING)
4043 {
4044 CGEventSourceRef source
4045 = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
4046
4047 CGEventRef event = CGEventCreateMouseEvent (source,
4048 kCGEventLeftMouseDown,
4049 menu_mouse_point,
4050 kCGMouseButtonLeft);
4051 CGEventSetType (event, kCGEventLeftMouseDown);
4052 CGEventPost (kCGHIDEventTap, event);
4053 CFRelease (event);
4054 CFRelease (source);
4055
4056 menu_will_open_state = MENU_OPENING;
4057 }
4058 }
4059 #endif /* NS_IMPL_COCOA */
4060
4061 static void
4062 unwind_apploopnr (Lisp_Object not_used)
4063 {
4064 --apploopnr;
4065 n_emacs_events_pending = 0;
4066 ns_finish_events ();
4067 q_event_ptr = NULL;
4068 }
4069
4070 static int
4071 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4072 /* --------------------------------------------------------------------------
4073 External (hook): Post an event to ourself and keep reading events until
4074 we read it back again. In effect process all events which were waiting.
4075 From 21+ we have to manage the event buffer ourselves.
4076 -------------------------------------------------------------------------- */
4077 {
4078 struct input_event ev;
4079 int nevents;
4080
4081 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
4082
4083 #ifdef HAVE_NATIVE_FS
4084 check_native_fs ();
4085 #endif
4086
4087 if ([NSApp modalWindow] != nil)
4088 return -1;
4089
4090 if (hold_event_q.nr > 0)
4091 {
4092 int i;
4093 for (i = 0; i < hold_event_q.nr; ++i)
4094 kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
4095 hold_event_q.nr = 0;
4096 return i;
4097 }
4098
4099 block_input ();
4100 n_emacs_events_pending = 0;
4101 ns_init_events (&ev);
4102 q_event_ptr = hold_quit;
4103
4104 /* we manage autorelease pools by allocate/reallocate each time around
4105 the loop; strict nesting is occasionally violated but seems not to
4106 matter.. earlier methods using full nesting caused major memory leaks */
4107 [outerpool release];
4108 outerpool = [[NSAutoreleasePool alloc] init];
4109
4110 /* If have pending open-file requests, attend to the next one of those. */
4111 if (ns_pending_files && [ns_pending_files count] != 0
4112 && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
4113 {
4114 [ns_pending_files removeObjectAtIndex: 0];
4115 }
4116 /* Deal with pending service requests. */
4117 else if (ns_pending_service_names && [ns_pending_service_names count] != 0
4118 && [(EmacsApp *)
4119 NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
4120 withArg: [ns_pending_service_args objectAtIndex: 0]])
4121 {
4122 [ns_pending_service_names removeObjectAtIndex: 0];
4123 [ns_pending_service_args removeObjectAtIndex: 0];
4124 }
4125 else
4126 {
4127 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
4128 /* Run and wait for events. We must always send one NX_APPDEFINED event
4129 to ourself, otherwise [NXApp run] will never exit. */
4130 send_appdefined = YES;
4131 ns_send_appdefined (-1);
4132
4133 if (++apploopnr != 1)
4134 {
4135 emacs_abort ();
4136 }
4137 record_unwind_protect (unwind_apploopnr, Qt);
4138 [NSApp run];
4139 unbind_to (specpdl_count, Qnil); /* calls unwind_apploopnr */
4140 }
4141
4142 nevents = n_emacs_events_pending;
4143 n_emacs_events_pending = 0;
4144 ns_finish_events ();
4145 q_event_ptr = NULL;
4146 unblock_input ();
4147
4148 return nevents;
4149 }
4150
4151
4152 int
4153 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
4154 fd_set *exceptfds, struct timespec const *timeout,
4155 sigset_t const *sigmask)
4156 /* --------------------------------------------------------------------------
4157 Replacement for select, checking for events
4158 -------------------------------------------------------------------------- */
4159 {
4160 int result;
4161 int t, k, nr = 0;
4162 struct input_event event;
4163 char c;
4164
4165 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
4166
4167 #ifdef HAVE_NATIVE_FS
4168 check_native_fs ();
4169 #endif
4170
4171 if (hold_event_q.nr > 0)
4172 {
4173 /* We already have events pending. */
4174 raise (SIGIO);
4175 errno = EINTR;
4176 return -1;
4177 }
4178
4179 for (k = 0; k < nfds+1; k++)
4180 {
4181 if (readfds && FD_ISSET(k, readfds)) ++nr;
4182 if (writefds && FD_ISSET(k, writefds)) ++nr;
4183 }
4184
4185 if (NSApp == nil
4186 || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
4187 return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
4188
4189 [outerpool release];
4190 outerpool = [[NSAutoreleasePool alloc] init];
4191
4192
4193 send_appdefined = YES;
4194 if (nr > 0)
4195 {
4196 pthread_mutex_lock (&select_mutex);
4197 select_nfds = nfds;
4198 select_valid = 0;
4199 if (readfds)
4200 {
4201 select_readfds = *readfds;
4202 select_valid += SELECT_HAVE_READ;
4203 }
4204 if (writefds)
4205 {
4206 select_writefds = *writefds;
4207 select_valid += SELECT_HAVE_WRITE;
4208 }
4209
4210 if (timeout)
4211 {
4212 select_timeout = *timeout;
4213 select_valid += SELECT_HAVE_TMO;
4214 }
4215
4216 pthread_mutex_unlock (&select_mutex);
4217
4218 /* Inform fd_handler that select should be called */
4219 c = 'g';
4220 emacs_write_sig (selfds[1], &c, 1);
4221 }
4222 else if (nr == 0 && timeout)
4223 {
4224 /* No file descriptor, just a timeout, no need to wake fd_handler */
4225 double time = timespectod (*timeout);
4226 timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
4227 target: NSApp
4228 selector:
4229 @selector (timeout_handler:)
4230 userInfo: 0
4231 repeats: NO]
4232 retain];
4233 }
4234 else /* No timeout and no file descriptors, can this happen? */
4235 {
4236 /* Send appdefined so we exit from the loop */
4237 ns_send_appdefined (-1);
4238 }
4239
4240 block_input ();
4241 ns_init_events (&event);
4242 if (++apploopnr != 1)
4243 {
4244 emacs_abort ();
4245 }
4246
4247 {
4248 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
4249 record_unwind_protect (unwind_apploopnr, Qt);
4250 [NSApp run];
4251 unbind_to (specpdl_count, Qnil); /* calls unwind_apploopnr */
4252 }
4253
4254 ns_finish_events ();
4255 if (nr > 0 && readfds)
4256 {
4257 c = 's';
4258 emacs_write_sig (selfds[1], &c, 1);
4259 }
4260 unblock_input ();
4261
4262 t = last_appdefined_event_data;
4263
4264 if (t != NO_APPDEFINED_DATA)
4265 {
4266 last_appdefined_event_data = NO_APPDEFINED_DATA;
4267
4268 if (t == -2)
4269 {
4270 /* The NX_APPDEFINED event we received was a timeout. */
4271 result = 0;
4272 }
4273 else if (t == -1)
4274 {
4275 /* The NX_APPDEFINED event we received was the result of
4276 at least one real input event arriving. */
4277 errno = EINTR;
4278 result = -1;
4279 }
4280 else
4281 {
4282 /* Received back from select () in fd_handler; copy the results */
4283 pthread_mutex_lock (&select_mutex);
4284 if (readfds) *readfds = select_readfds;
4285 if (writefds) *writefds = select_writefds;
4286 pthread_mutex_unlock (&select_mutex);
4287 result = t;
4288 }
4289 }
4290 else
4291 {
4292 errno = EINTR;
4293 result = -1;
4294 }
4295
4296 return result;
4297 }
4298
4299
4300
4301 /* ==========================================================================
4302
4303 Scrollbar handling
4304
4305 ========================================================================== */
4306
4307
4308 static void
4309 ns_set_vertical_scroll_bar (struct window *window,
4310 int portion, int whole, int position)
4311 /* --------------------------------------------------------------------------
4312 External (hook): Update or add scrollbar
4313 -------------------------------------------------------------------------- */
4314 {
4315 Lisp_Object win;
4316 NSRect r, v;
4317 struct frame *f = XFRAME (WINDOW_FRAME (window));
4318 EmacsView *view = FRAME_NS_VIEW (f);
4319 EmacsScroller *bar;
4320 int window_y, window_height;
4321 int top, left, height, width;
4322 BOOL update_p = YES;
4323
4324 /* optimization; display engine sends WAY too many of these.. */
4325 if (!NILP (window->vertical_scroll_bar))
4326 {
4327 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4328 if ([bar checkSamePosition: position portion: portion whole: whole])
4329 {
4330 if (view->scrollbarsNeedingUpdate == 0)
4331 {
4332 if (!windows_or_buffers_changed)
4333 return;
4334 }
4335 else
4336 view->scrollbarsNeedingUpdate--;
4337 update_p = NO;
4338 }
4339 }
4340
4341 NSTRACE ("ns_set_vertical_scroll_bar");
4342
4343 /* Get dimensions. */
4344 window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4345 top = window_y;
4346 height = window_height;
4347 width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
4348 left = WINDOW_SCROLL_BAR_AREA_X (window);
4349
4350 r = NSMakeRect (left, top, width, height);
4351 /* the parent view is flipped, so we need to flip y value */
4352 v = [view frame];
4353 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4354
4355 XSETWINDOW (win, window);
4356 block_input ();
4357
4358 /* we want at least 5 lines to display a scrollbar */
4359 if (WINDOW_TOTAL_LINES (window) < 5)
4360 {
4361 if (!NILP (window->vertical_scroll_bar))
4362 {
4363 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4364 [bar removeFromSuperview];
4365 wset_vertical_scroll_bar (window, Qnil);
4366 [bar release];
4367 }
4368 ns_clear_frame_area (f, left, top, width, height);
4369 unblock_input ();
4370 return;
4371 }
4372
4373 if (NILP (window->vertical_scroll_bar))
4374 {
4375 if (width > 0 && height > 0)
4376 ns_clear_frame_area (f, left, top, width, height);
4377
4378 bar = [[EmacsScroller alloc] initFrame: r window: win];
4379 wset_vertical_scroll_bar (window, make_save_ptr (bar));
4380 update_p = YES;
4381 }
4382 else
4383 {
4384 NSRect oldRect;
4385 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4386 oldRect = [bar frame];
4387 r.size.width = oldRect.size.width;
4388 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4389 {
4390 if (oldRect.origin.x != r.origin.x)
4391 ns_clear_frame_area (f, left, top, width, height);
4392 [bar setFrame: r];
4393 }
4394 }
4395
4396 if (update_p)
4397 [bar setPosition: position portion: portion whole: whole];
4398 unblock_input ();
4399 }
4400
4401
4402 static void
4403 ns_set_horizontal_scroll_bar (struct window *window,
4404 int portion, int whole, int position)
4405 /* --------------------------------------------------------------------------
4406 External (hook): Update or add scrollbar
4407 -------------------------------------------------------------------------- */
4408 {
4409 Lisp_Object win;
4410 NSRect r, v;
4411 struct frame *f = XFRAME (WINDOW_FRAME (window));
4412 EmacsView *view = FRAME_NS_VIEW (f);
4413 EmacsScroller *bar;
4414 int top, height, left, width;
4415 int window_x, window_width;
4416 BOOL update_p = YES;
4417
4418 /* optimization; display engine sends WAY too many of these.. */
4419 if (!NILP (window->horizontal_scroll_bar))
4420 {
4421 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4422 if ([bar checkSamePosition: position portion: portion whole: whole])
4423 {
4424 if (view->scrollbarsNeedingUpdate == 0)
4425 {
4426 if (!windows_or_buffers_changed)
4427 return;
4428 }
4429 else
4430 view->scrollbarsNeedingUpdate--;
4431 update_p = NO;
4432 }
4433 }
4434
4435 NSTRACE ("ns_set_horizontal_scroll_bar");
4436
4437 /* Get dimensions. */
4438 window_box (window, ANY_AREA, 0, &window_x, &window_width, 0);
4439 left = window_x;
4440 width = window_width;
4441 height = WINDOW_CONFIG_SCROLL_BAR_LINES (window) * FRAME_LINE_HEIGHT (f);
4442 top = WINDOW_SCROLL_BAR_AREA_Y (window);
4443
4444 r = NSMakeRect (left, top, width, height);
4445 /* the parent view is flipped, so we need to flip y value */
4446 v = [view frame];
4447 /* ??????? PXW/scrollbars !!!!!!!!!!!!!!!!!!!! */
4448 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4449
4450 XSETWINDOW (win, window);
4451 block_input ();
4452
4453 if (WINDOW_TOTAL_COLS (window) < 5)
4454 {
4455 if (!NILP (window->horizontal_scroll_bar))
4456 {
4457 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4458 [bar removeFromSuperview];
4459 wset_horizontal_scroll_bar (window, Qnil);
4460 }
4461 ns_clear_frame_area (f, left, top, width, height);
4462 unblock_input ();
4463 return;
4464 }
4465
4466 if (NILP (window->horizontal_scroll_bar))
4467 {
4468 if (width > 0 && height > 0)
4469 ns_clear_frame_area (f, left, top, width, height);
4470
4471 bar = [[EmacsScroller alloc] initFrame: r window: win];
4472 wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4473 update_p = YES;
4474 }
4475 else
4476 {
4477 NSRect oldRect;
4478 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4479 oldRect = [bar frame];
4480 r.size.width = oldRect.size.width;
4481 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4482 {
4483 if (oldRect.origin.x != r.origin.x)
4484 ns_clear_frame_area (f, left, top, width, height);
4485 [bar setFrame: r];
4486 update_p = YES;
4487 }
4488 }
4489
4490 if (update_p)
4491 [bar setPosition: position portion: portion whole: whole];
4492 unblock_input ();
4493 }
4494
4495
4496 static void
4497 ns_condemn_scroll_bars (struct frame *f)
4498 /* --------------------------------------------------------------------------
4499 External (hook): arrange for all frame's scrollbars to be removed
4500 at next call to judge_scroll_bars, except for those redeemed.
4501 -------------------------------------------------------------------------- */
4502 {
4503 int i;
4504 id view;
4505 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4506
4507 NSTRACE ("ns_condemn_scroll_bars");
4508
4509 for (i =[subviews count]-1; i >= 0; i--)
4510 {
4511 view = [subviews objectAtIndex: i];
4512 if ([view isKindOfClass: [EmacsScroller class]])
4513 [view condemn];
4514 }
4515 }
4516
4517
4518 static void
4519 ns_redeem_scroll_bar (struct window *window)
4520 /* --------------------------------------------------------------------------
4521 External (hook): arrange to spare this window's scrollbar
4522 at next call to judge_scroll_bars.
4523 -------------------------------------------------------------------------- */
4524 {
4525 id bar;
4526 NSTRACE ("ns_redeem_scroll_bar");
4527 if (!NILP (window->vertical_scroll_bar))
4528 {
4529 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4530 [bar reprieve];
4531 }
4532
4533 if (!NILP (window->horizontal_scroll_bar))
4534 {
4535 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4536 [bar reprieve];
4537 }
4538 }
4539
4540
4541 static void
4542 ns_judge_scroll_bars (struct frame *f)
4543 /* --------------------------------------------------------------------------
4544 External (hook): destroy all scrollbars on frame that weren't
4545 redeemed after call to condemn_scroll_bars.
4546 -------------------------------------------------------------------------- */
4547 {
4548 int i;
4549 id view;
4550 EmacsView *eview = FRAME_NS_VIEW (f);
4551 NSArray *subviews = [[eview superview] subviews];
4552 BOOL removed = NO;
4553
4554 NSTRACE ("ns_judge_scroll_bars");
4555 for (i = [subviews count]-1; i >= 0; --i)
4556 {
4557 view = [subviews objectAtIndex: i];
4558 if (![view isKindOfClass: [EmacsScroller class]]) continue;
4559 if ([view judge])
4560 removed = YES;
4561 }
4562
4563 if (removed)
4564 [eview updateFrameSize: NO];
4565 }
4566
4567 /* ==========================================================================
4568
4569 Initialization
4570
4571 ========================================================================== */
4572
4573 int
4574 x_display_pixel_height (struct ns_display_info *dpyinfo)
4575 {
4576 NSArray *screens = [NSScreen screens];
4577 NSEnumerator *enumerator = [screens objectEnumerator];
4578 NSScreen *screen;
4579 NSRect frame;
4580
4581 frame = NSZeroRect;
4582 while ((screen = [enumerator nextObject]) != nil)
4583 frame = NSUnionRect (frame, [screen frame]);
4584
4585 return NSHeight (frame);
4586 }
4587
4588 int
4589 x_display_pixel_width (struct ns_display_info *dpyinfo)
4590 {
4591 NSArray *screens = [NSScreen screens];
4592 NSEnumerator *enumerator = [screens objectEnumerator];
4593 NSScreen *screen;
4594 NSRect frame;
4595
4596 frame = NSZeroRect;
4597 while ((screen = [enumerator nextObject]) != nil)
4598 frame = NSUnionRect (frame, [screen frame]);
4599
4600 return NSWidth (frame);
4601 }
4602
4603
4604 static Lisp_Object ns_string_to_lispmod (const char *s)
4605 /* --------------------------------------------------------------------------
4606 Convert modifier name to lisp symbol
4607 -------------------------------------------------------------------------- */
4608 {
4609 if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4610 return Qmeta;
4611 else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4612 return Qsuper;
4613 else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4614 return Qcontrol;
4615 else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4616 return Qalt;
4617 else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4618 return Qhyper;
4619 else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4620 return Qnone;
4621 else
4622 return Qnil;
4623 }
4624
4625
4626 static void
4627 ns_default (const char *parameter, Lisp_Object *result,
4628 Lisp_Object yesval, Lisp_Object noval,
4629 BOOL is_float, BOOL is_modstring)
4630 /* --------------------------------------------------------------------------
4631 Check a parameter value in user's preferences
4632 -------------------------------------------------------------------------- */
4633 {
4634 const char *value = ns_get_defaults_value (parameter);
4635
4636 if (value)
4637 {
4638 double f;
4639 char *pos;
4640 if (c_strcasecmp (value, "YES") == 0)
4641 *result = yesval;
4642 else if (c_strcasecmp (value, "NO") == 0)
4643 *result = noval;
4644 else if (is_float && (f = strtod (value, &pos), pos != value))
4645 *result = make_float (f);
4646 else if (is_modstring && value)
4647 *result = ns_string_to_lispmod (value);
4648 else fprintf (stderr,
4649 "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4650 }
4651 }
4652
4653
4654 static void
4655 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4656 /* --------------------------------------------------------------------------
4657 Initialize global info and storage for display.
4658 -------------------------------------------------------------------------- */
4659 {
4660 NSScreen *screen = [NSScreen mainScreen];
4661 NSWindowDepth depth = [screen depth];
4662
4663 dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4664 dpyinfo->resy = 72.27;
4665 dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4666 NSColorSpaceFromDepth (depth)]
4667 && ![NSCalibratedWhiteColorSpace isEqualToString:
4668 NSColorSpaceFromDepth (depth)];
4669 dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4670 dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4671 dpyinfo->color_table->colors = NULL;
4672 dpyinfo->root_window = 42; /* a placeholder.. */
4673 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4674 dpyinfo->n_fonts = 0;
4675 dpyinfo->smallest_font_height = 1;
4676 dpyinfo->smallest_char_width = 1;
4677
4678 reset_mouse_highlight (&dpyinfo->mouse_highlight);
4679 }
4680
4681
4682 /* This and next define (many of the) public functions in this file. */
4683 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4684 with using despite presence in the "system dependent" redisplay
4685 interface. In addition, many of the ns_ methods have code that is
4686 shared with all terms, indicating need for further refactoring. */
4687 extern frame_parm_handler ns_frame_parm_handlers[];
4688 static struct redisplay_interface ns_redisplay_interface =
4689 {
4690 ns_frame_parm_handlers,
4691 x_produce_glyphs,
4692 x_write_glyphs,
4693 x_insert_glyphs,
4694 x_clear_end_of_line,
4695 ns_scroll_run,
4696 ns_after_update_window_line,
4697 ns_update_window_begin,
4698 ns_update_window_end,
4699 0, /* flush_display */
4700 x_clear_window_mouse_face,
4701 x_get_glyph_overhangs,
4702 x_fix_overlapping_area,
4703 ns_draw_fringe_bitmap,
4704 0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4705 0, /* destroy_fringe_bitmap */
4706 ns_compute_glyph_string_overhangs,
4707 ns_draw_glyph_string,
4708 ns_define_frame_cursor,
4709 ns_clear_frame_area,
4710 ns_draw_window_cursor,
4711 ns_draw_vertical_window_border,
4712 ns_draw_window_divider,
4713 ns_shift_glyphs_for_insert,
4714 ns_show_hourglass,
4715 ns_hide_hourglass
4716 };
4717
4718
4719 static void
4720 ns_delete_display (struct ns_display_info *dpyinfo)
4721 {
4722 /* TODO... */
4723 }
4724
4725
4726 /* This function is called when the last frame on a display is deleted. */
4727 static void
4728 ns_delete_terminal (struct terminal *terminal)
4729 {
4730 struct ns_display_info *dpyinfo = terminal->display_info.ns;
4731
4732 NSTRACE ("ns_delete_terminal");
4733
4734 /* Protect against recursive calls. delete_frame in
4735 delete_terminal calls us back when it deletes our last frame. */
4736 if (!terminal->name)
4737 return;
4738
4739 block_input ();
4740
4741 x_destroy_all_bitmaps (dpyinfo);
4742 ns_delete_display (dpyinfo);
4743 unblock_input ();
4744 }
4745
4746
4747 static struct terminal *
4748 ns_create_terminal (struct ns_display_info *dpyinfo)
4749 /* --------------------------------------------------------------------------
4750 Set up use of NS before we make the first connection.
4751 -------------------------------------------------------------------------- */
4752 {
4753 struct terminal *terminal;
4754
4755 NSTRACE ("ns_create_terminal");
4756
4757 terminal = create_terminal (output_ns, &ns_redisplay_interface);
4758
4759 terminal->display_info.ns = dpyinfo;
4760 dpyinfo->terminal = terminal;
4761
4762 terminal->clear_frame_hook = ns_clear_frame;
4763 terminal->ring_bell_hook = ns_ring_bell;
4764 terminal->update_begin_hook = ns_update_begin;
4765 terminal->update_end_hook = ns_update_end;
4766 terminal->read_socket_hook = ns_read_socket;
4767 terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4768 terminal->mouse_position_hook = ns_mouse_position;
4769 terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4770 terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4771 terminal->fullscreen_hook = ns_fullscreen_hook;
4772 terminal->menu_show_hook = ns_menu_show;
4773 terminal->popup_dialog_hook = ns_popup_dialog;
4774 terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4775 terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
4776 terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4777 terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4778 terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4779 terminal->delete_frame_hook = x_destroy_window;
4780 terminal->delete_terminal_hook = ns_delete_terminal;
4781 /* Other hooks are NULL by default. */
4782
4783 return terminal;
4784 }
4785
4786
4787 struct ns_display_info *
4788 ns_term_init (Lisp_Object display_name)
4789 /* --------------------------------------------------------------------------
4790 Start the Application and get things rolling.
4791 -------------------------------------------------------------------------- */
4792 {
4793 struct terminal *terminal;
4794 struct ns_display_info *dpyinfo;
4795 static int ns_initialized = 0;
4796 Lisp_Object tmp;
4797
4798 if (ns_initialized) return x_display_list;
4799 ns_initialized = 1;
4800
4801 block_input ();
4802
4803 NSTRACE ("ns_term_init");
4804
4805 [outerpool release];
4806 outerpool = [[NSAutoreleasePool alloc] init];
4807
4808 /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4809 /*GSDebugAllocationActive (YES); */
4810 block_input ();
4811
4812 baud_rate = 38400;
4813 Fset_input_interrupt_mode (Qnil);
4814
4815 if (selfds[0] == -1)
4816 {
4817 if (emacs_pipe (selfds) != 0)
4818 {
4819 fprintf (stderr, "Failed to create pipe: %s\n",
4820 emacs_strerror (errno));
4821 emacs_abort ();
4822 }
4823
4824 fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4825 FD_ZERO (&select_readfds);
4826 FD_ZERO (&select_writefds);
4827 pthread_mutex_init (&select_mutex, NULL);
4828 }
4829
4830 ns_pending_files = [[NSMutableArray alloc] init];
4831 ns_pending_service_names = [[NSMutableArray alloc] init];
4832 ns_pending_service_args = [[NSMutableArray alloc] init];
4833
4834 /* Start app and create the main menu, window, view.
4835 Needs to be here because ns_initialize_display_info () uses AppKit classes.
4836 The view will then ask the NSApp to stop and return to Emacs. */
4837 [EmacsApp sharedApplication];
4838 if (NSApp == nil)
4839 return NULL;
4840 [NSApp setDelegate: NSApp];
4841
4842 /* Start the select thread. */
4843 [NSThread detachNewThreadSelector:@selector (fd_handler:)
4844 toTarget:NSApp
4845 withObject:nil];
4846
4847 /* debugging: log all notifications */
4848 /* [[NSNotificationCenter defaultCenter] addObserver: NSApp
4849 selector: @selector (logNotification:)
4850 name: nil object: nil]; */
4851
4852 dpyinfo = xzalloc (sizeof *dpyinfo);
4853
4854 ns_initialize_display_info (dpyinfo);
4855 terminal = ns_create_terminal (dpyinfo);
4856
4857 terminal->kboard = allocate_kboard (Qns);
4858 /* Don't let the initial kboard remain current longer than necessary.
4859 That would cause problems if a file loaded on startup tries to
4860 prompt in the mini-buffer. */
4861 if (current_kboard == initial_kboard)
4862 current_kboard = terminal->kboard;
4863 terminal->kboard->reference_count++;
4864
4865 dpyinfo->next = x_display_list;
4866 x_display_list = dpyinfo;
4867
4868 dpyinfo->name_list_element = Fcons (display_name, Qnil);
4869
4870 terminal->name = xlispstrdup (display_name);
4871
4872 unblock_input ();
4873
4874 if (!inhibit_x_resources)
4875 {
4876 ns_default ("GSFontAntiAlias", &ns_antialias_text,
4877 Qt, Qnil, NO, NO);
4878 tmp = Qnil;
4879 /* this is a standard variable */
4880 ns_default ("AppleAntiAliasingThreshold", &tmp,
4881 make_float (10.0), make_float (6.0), YES, NO);
4882 ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4883 }
4884
4885 NSTRACE_MSG ("Colors");
4886
4887 {
4888 NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4889
4890 if ( cl == nil )
4891 {
4892 Lisp_Object color_file, color_map, color;
4893 unsigned long c;
4894 char *name;
4895
4896 color_file = Fexpand_file_name (build_string ("rgb.txt"),
4897 Fsymbol_value (intern ("data-directory")));
4898
4899 color_map = Fx_load_color_file (color_file);
4900 if (NILP (color_map))
4901 fatal ("Could not read %s.\n", SDATA (color_file));
4902
4903 cl = [[NSColorList alloc] initWithName: @"Emacs"];
4904 for ( ; CONSP (color_map); color_map = XCDR (color_map))
4905 {
4906 color = XCAR (color_map);
4907 name = SSDATA (XCAR (color));
4908 c = XINT (XCDR (color));
4909 [cl setColor:
4910 [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
4911 green: GREEN_FROM_ULONG (c) / 255.0
4912 blue: BLUE_FROM_ULONG (c) / 255.0
4913 alpha: 1.0]
4914 forKey: [NSString stringWithUTF8String: name]];
4915 }
4916 [cl writeToFile: nil];
4917 }
4918 }
4919
4920 NSTRACE_MSG ("Versions");
4921
4922 {
4923 #ifdef NS_IMPL_GNUSTEP
4924 Vwindow_system_version = build_string (gnustep_base_version);
4925 #else
4926 /*PSnextrelease (128, c); */
4927 char c[DBL_BUFSIZE_BOUND];
4928 int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4929 Vwindow_system_version = make_unibyte_string (c, len);
4930 #endif
4931 }
4932
4933 delete_keyboard_wait_descriptor (0);
4934
4935 ns_app_name = [[NSProcessInfo processInfo] processName];
4936
4937 /* Set up OS X app menu */
4938
4939 NSTRACE_MSG ("Menu init");
4940
4941 #ifdef NS_IMPL_COCOA
4942 {
4943 NSMenu *appMenu;
4944 NSMenuItem *item;
4945 /* set up the application menu */
4946 svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4947 [svcsMenu setAutoenablesItems: NO];
4948 appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4949 [appMenu setAutoenablesItems: NO];
4950 mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4951 dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4952
4953 [appMenu insertItemWithTitle: @"About Emacs"
4954 action: @selector (orderFrontStandardAboutPanel:)
4955 keyEquivalent: @""
4956 atIndex: 0];
4957 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4958 [appMenu insertItemWithTitle: @"Preferences..."
4959 action: @selector (showPreferencesWindow:)
4960 keyEquivalent: @","
4961 atIndex: 2];
4962 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4963 item = [appMenu insertItemWithTitle: @"Services"
4964 action: @selector (menuDown:)
4965 keyEquivalent: @""
4966 atIndex: 4];
4967 [appMenu setSubmenu: svcsMenu forItem: item];
4968 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4969 [appMenu insertItemWithTitle: @"Hide Emacs"
4970 action: @selector (hide:)
4971 keyEquivalent: @"h"
4972 atIndex: 6];
4973 item = [appMenu insertItemWithTitle: @"Hide Others"
4974 action: @selector (hideOtherApplications:)
4975 keyEquivalent: @"h"
4976 atIndex: 7];
4977 [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4978 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4979 [appMenu insertItemWithTitle: @"Quit Emacs"
4980 action: @selector (terminate:)
4981 keyEquivalent: @"q"
4982 atIndex: 9];
4983
4984 item = [mainMenu insertItemWithTitle: ns_app_name
4985 action: @selector (menuDown:)
4986 keyEquivalent: @""
4987 atIndex: 0];
4988 [mainMenu setSubmenu: appMenu forItem: item];
4989 [dockMenu insertItemWithTitle: @"New Frame"
4990 action: @selector (newFrame:)
4991 keyEquivalent: @""
4992 atIndex: 0];
4993
4994 [NSApp setMainMenu: mainMenu];
4995 [NSApp setAppleMenu: appMenu];
4996 [NSApp setServicesMenu: svcsMenu];
4997 /* Needed at least on Cocoa, to get dock menu to show windows */
4998 [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4999
5000 [[NSNotificationCenter defaultCenter]
5001 addObserver: mainMenu
5002 selector: @selector (trackingNotification:)
5003 name: NSMenuDidBeginTrackingNotification object: mainMenu];
5004 [[NSNotificationCenter defaultCenter]
5005 addObserver: mainMenu
5006 selector: @selector (trackingNotification:)
5007 name: NSMenuDidEndTrackingNotification object: mainMenu];
5008 }
5009 #endif /* MAC OS X menu setup */
5010
5011 /* Register our external input/output types, used for determining
5012 applicable services and also drag/drop eligibility. */
5013
5014 NSTRACE_MSG ("Input/output types");
5015
5016 ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
5017 ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
5018 retain];
5019 ns_drag_types = [[NSArray arrayWithObjects:
5020 NSStringPboardType,
5021 NSTabularTextPboardType,
5022 NSFilenamesPboardType,
5023 NSURLPboardType, nil] retain];
5024
5025 /* If fullscreen is in init/default-frame-alist, focus isn't set
5026 right for fullscreen windows, so set this. */
5027 [NSApp activateIgnoringOtherApps:YES];
5028
5029 NSTRACE_MSG ("Call NSApp run");
5030
5031 [NSApp run];
5032 ns_do_open_file = YES;
5033
5034 #ifdef NS_IMPL_GNUSTEP
5035 /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
5036 We must re-catch it so subprocess works. */
5037 catch_child_signal ();
5038 #endif
5039
5040 NSTRACE_MSG ("ns_term_init done");
5041
5042 unblock_input ();
5043
5044 return dpyinfo;
5045 }
5046
5047
5048 void
5049 ns_term_shutdown (int sig)
5050 {
5051 [[NSUserDefaults standardUserDefaults] synchronize];
5052
5053 /* code not reached in emacs.c after this is called by shut_down_emacs: */
5054 if (STRINGP (Vauto_save_list_file_name))
5055 unlink (SSDATA (Vauto_save_list_file_name));
5056
5057 if (sig == 0 || sig == SIGTERM)
5058 {
5059 [NSApp terminate: NSApp];
5060 }
5061 else // force a stack trace to happen
5062 {
5063 emacs_abort ();
5064 }
5065 }
5066
5067
5068 /* ==========================================================================
5069
5070 EmacsApp implementation
5071
5072 ========================================================================== */
5073
5074
5075 @implementation EmacsApp
5076
5077 - (id)init
5078 {
5079 NSTRACE ("[EmacsApp init]");
5080
5081 if ((self = [super init]))
5082 {
5083 #ifdef NS_IMPL_COCOA
5084 self->isFirst = YES;
5085 #endif
5086 #ifdef NS_IMPL_GNUSTEP
5087 self->applicationDidFinishLaunchingCalled = NO;
5088 #endif
5089 }
5090
5091 return self;
5092 }
5093
5094 #ifdef NS_IMPL_COCOA
5095 - (void)run
5096 {
5097 NSTRACE ("[EmacsApp run]");
5098
5099 #ifndef NSAppKitVersionNumber10_9
5100 #define NSAppKitVersionNumber10_9 1265
5101 #endif
5102
5103 if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
5104 {
5105 [super run];
5106 return;
5107 }
5108
5109 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5110
5111 if (isFirst) [self finishLaunching];
5112 isFirst = NO;
5113
5114 shouldKeepRunning = YES;
5115 do
5116 {
5117 [pool release];
5118 pool = [[NSAutoreleasePool alloc] init];
5119
5120 NSEvent *event =
5121 [self nextEventMatchingMask:NSAnyEventMask
5122 untilDate:[NSDate distantFuture]
5123 inMode:NSDefaultRunLoopMode
5124 dequeue:YES];
5125
5126 [self sendEvent:event];
5127 [self updateWindows];
5128 } while (shouldKeepRunning);
5129
5130 [pool release];
5131 }
5132
5133 - (void)stop: (id)sender
5134 {
5135 NSTRACE ("[EmacsApp stop:]");
5136
5137 shouldKeepRunning = NO;
5138 // Stop possible dialog also. Noop if no dialog present.
5139 // The file dialog still leaks 7k - 10k on 10.9 though.
5140 [super stop:sender];
5141 }
5142 #endif /* NS_IMPL_COCOA */
5143
5144 - (void)logNotification: (NSNotification *)notification
5145 {
5146 NSTRACE ("[EmacsApp logNotification:]");
5147
5148 const char *name = [[notification name] UTF8String];
5149 if (!strstr (name, "Update") && !strstr (name, "NSMenu")
5150 && !strstr (name, "WindowNumber"))
5151 NSLog (@"notification: '%@'", [notification name]);
5152 }
5153
5154
5155 - (void)sendEvent: (NSEvent *)theEvent
5156 /* --------------------------------------------------------------------------
5157 Called when NSApp is running for each event received. Used to stop
5158 the loop when we choose, since there's no way to just run one iteration.
5159 -------------------------------------------------------------------------- */
5160 {
5161 int type = [theEvent type];
5162 NSWindow *window = [theEvent window];
5163
5164 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]");
5165 NSTRACE_MSG ("Type: %d", type);
5166
5167 #ifdef NS_IMPL_GNUSTEP
5168 // Keyboard events aren't propagated to file dialogs for some reason.
5169 if ([NSApp modalWindow] != nil &&
5170 (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
5171 {
5172 [[NSApp modalWindow] sendEvent: theEvent];
5173 return;
5174 }
5175 #endif
5176
5177 if (represented_filename != nil && represented_frame)
5178 {
5179 NSString *fstr = represented_filename;
5180 NSView *view = FRAME_NS_VIEW (represented_frame);
5181 #ifdef NS_IMPL_COCOA
5182 /* work around a bug observed on 10.3 and later where
5183 setTitleWithRepresentedFilename does not clear out previous state
5184 if given filename does not exist */
5185 if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
5186 [[view window] setRepresentedFilename: @""];
5187 #endif
5188 [[view window] setRepresentedFilename: fstr];
5189 [represented_filename release];
5190 represented_filename = nil;
5191 represented_frame = NULL;
5192 }
5193
5194 if (type == NSApplicationDefined)
5195 {
5196 switch ([theEvent data2])
5197 {
5198 #ifdef NS_IMPL_COCOA
5199 case NSAPP_DATA2_RUNASSCRIPT:
5200 ns_run_ascript ();
5201 [self stop: self];
5202 return;
5203 #endif
5204 case NSAPP_DATA2_RUNFILEDIALOG:
5205 ns_run_file_dialog ();
5206 [self stop: self];
5207 return;
5208 }
5209 }
5210
5211 if (type == NSCursorUpdate && window == nil)
5212 {
5213 fprintf (stderr, "Dropping external cursor update event.\n");
5214 return;
5215 }
5216
5217 if (type == NSApplicationDefined)
5218 {
5219 /* Events posted by ns_send_appdefined interrupt the run loop here.
5220 But, if a modal window is up, an appdefined can still come through,
5221 (e.g., from a makeKeyWindow event) but stopping self also stops the
5222 modal loop. Just defer it until later. */
5223 if ([NSApp modalWindow] == nil)
5224 {
5225 last_appdefined_event_data = [theEvent data1];
5226 [self stop: self];
5227 }
5228 else
5229 {
5230 send_appdefined = YES;
5231 }
5232 }
5233
5234
5235 #ifdef NS_IMPL_COCOA
5236 /* If no dialog and none of our frames have focus and it is a move, skip it.
5237 It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
5238 such as Wifi, sound, date or similar.
5239 This prevents "spooky" highlighting in the frame under the menu. */
5240 if (type == NSMouseMoved && [NSApp modalWindow] == nil)
5241 {
5242 struct ns_display_info *di;
5243 BOOL has_focus = NO;
5244 for (di = x_display_list; ! has_focus && di; di = di->next)
5245 has_focus = di->x_focus_frame != 0;
5246 if (! has_focus)
5247 return;
5248 }
5249 #endif
5250
5251 NSTRACE_UNSILENCE();
5252
5253 [super sendEvent: theEvent];
5254 }
5255
5256
5257 - (void)showPreferencesWindow: (id)sender
5258 {
5259 struct frame *emacsframe = SELECTED_FRAME ();
5260 NSEvent *theEvent = [NSApp currentEvent];
5261
5262 if (!emacs_event)
5263 return;
5264 emacs_event->kind = NS_NONKEY_EVENT;
5265 emacs_event->code = KEY_NS_SHOW_PREFS;
5266 emacs_event->modifiers = 0;
5267 EV_TRAILER (theEvent);
5268 }
5269
5270
5271 - (void)newFrame: (id)sender
5272 {
5273 NSTRACE ("[EmacsApp newFrame:]");
5274
5275 struct frame *emacsframe = SELECTED_FRAME ();
5276 NSEvent *theEvent = [NSApp currentEvent];
5277
5278 if (!emacs_event)
5279 return;
5280 emacs_event->kind = NS_NONKEY_EVENT;
5281 emacs_event->code = KEY_NS_NEW_FRAME;
5282 emacs_event->modifiers = 0;
5283 EV_TRAILER (theEvent);
5284 }
5285
5286
5287 /* Open a file (used by below, after going into queue read by ns_read_socket) */
5288 - (BOOL) openFile: (NSString *)fileName
5289 {
5290 NSTRACE ("[EmacsApp openFile:]");
5291
5292 struct frame *emacsframe = SELECTED_FRAME ();
5293 NSEvent *theEvent = [NSApp currentEvent];
5294
5295 if (!emacs_event)
5296 return NO;
5297
5298 emacs_event->kind = NS_NONKEY_EVENT;
5299 emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5300 ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5301 ns_input_line = Qnil; /* can be start or cons start,end */
5302 emacs_event->modifiers =0;
5303 EV_TRAILER (theEvent);
5304
5305 return YES;
5306 }
5307
5308
5309 /* **************************************************************************
5310
5311 EmacsApp delegate implementation
5312
5313 ************************************************************************** */
5314
5315 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5316 /* --------------------------------------------------------------------------
5317 When application is loaded, terminate event loop in ns_term_init
5318 -------------------------------------------------------------------------- */
5319 {
5320 NSTRACE ("[EmacsApp applicationDidFinishLaunching:]");
5321
5322 #ifdef NS_IMPL_GNUSTEP
5323 ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5324 #endif
5325 [NSApp setServicesProvider: NSApp];
5326
5327 [self antialiasThresholdDidChange:nil];
5328 #ifdef NS_IMPL_COCOA
5329 [[NSNotificationCenter defaultCenter]
5330 addObserver:self
5331 selector:@selector(antialiasThresholdDidChange:)
5332 name:NSAntialiasThresholdChangedNotification
5333 object:nil];
5334 #endif
5335
5336 ns_send_appdefined (-2);
5337 }
5338
5339 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5340 {
5341 #ifdef NS_IMPL_COCOA
5342 macfont_update_antialias_threshold ();
5343 #endif
5344 }
5345
5346
5347 /* Termination sequences:
5348 C-x C-c:
5349 Cmd-Q:
5350 MenuBar | File | Exit:
5351 Select Quit from App menubar:
5352 -terminate
5353 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5354 ns_term_shutdown()
5355
5356 Select Quit from Dock menu:
5357 Logout attempt:
5358 -appShouldTerminate
5359 Cancel -> Nothing else
5360 Accept ->
5361
5362 -terminate
5363 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5364 ns_term_shutdown()
5365
5366 */
5367
5368 - (void) terminate: (id)sender
5369 {
5370 NSTRACE ("[EmacsApp terminate:]");
5371
5372 struct frame *emacsframe = SELECTED_FRAME ();
5373
5374 if (!emacs_event)
5375 return;
5376
5377 emacs_event->kind = NS_NONKEY_EVENT;
5378 emacs_event->code = KEY_NS_POWER_OFF;
5379 emacs_event->arg = Qt; /* mark as non-key event */
5380 EV_TRAILER ((id)nil);
5381 }
5382
5383 static bool
5384 runAlertPanel(NSString *title,
5385 NSString *msgFormat,
5386 NSString *defaultButton,
5387 NSString *alternateButton)
5388 {
5389 #if !defined (NS_IMPL_COCOA) || \
5390 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
5391 return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5392 == NSAlertDefaultReturn;
5393 #else
5394 NSAlert *alert = [[NSAlert alloc] init];
5395 [alert setAlertStyle: NSCriticalAlertStyle];
5396 [alert setMessageText: msgFormat];
5397 [alert addButtonWithTitle: defaultButton];
5398 [alert addButtonWithTitle: alternateButton];
5399 NSInteger ret = [alert runModal];
5400 [alert release];
5401 return ret == NSAlertFirstButtonReturn;
5402 #endif
5403 }
5404
5405
5406 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5407 {
5408 NSTRACE ("[EmacsApp applicationShouldTerminate:]");
5409
5410 bool ret;
5411
5412 if (NILP (ns_confirm_quit)) // || ns_shutdown_properly --> TO DO
5413 return NSTerminateNow;
5414
5415 ret = runAlertPanel(ns_app_name,
5416 @"Exit requested. Would you like to Save Buffers and Exit, or Cancel the request?",
5417 @"Save Buffers and Exit", @"Cancel");
5418
5419 if (ret)
5420 return NSTerminateNow;
5421 else
5422 return NSTerminateCancel;
5423 return NSTerminateNow; /* just in case */
5424 }
5425
5426 static int
5427 not_in_argv (NSString *arg)
5428 {
5429 int k;
5430 const char *a = [arg UTF8String];
5431 for (k = 1; k < initial_argc; ++k)
5432 if (strcmp (a, initial_argv[k]) == 0) return 0;
5433 return 1;
5434 }
5435
5436 /* Notification from the Workspace to open a file */
5437 - (BOOL)application: sender openFile: (NSString *)file
5438 {
5439 if (ns_do_open_file || not_in_argv (file))
5440 [ns_pending_files addObject: file];
5441 return YES;
5442 }
5443
5444
5445 /* Open a file as a temporary file */
5446 - (BOOL)application: sender openTempFile: (NSString *)file
5447 {
5448 if (ns_do_open_file || not_in_argv (file))
5449 [ns_pending_files addObject: file];
5450 return YES;
5451 }
5452
5453
5454 /* Notification from the Workspace to open a file noninteractively (?) */
5455 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5456 {
5457 if (ns_do_open_file || not_in_argv (file))
5458 [ns_pending_files addObject: file];
5459 return YES;
5460 }
5461
5462 /* Notification from the Workspace to open multiple files */
5463 - (void)application: sender openFiles: (NSArray *)fileList
5464 {
5465 NSEnumerator *files = [fileList objectEnumerator];
5466 NSString *file;
5467 /* Don't open files from the command line unconditionally,
5468 Cocoa parses the command line wrong, --option value tries to open value
5469 if --option is the last option. */
5470 while ((file = [files nextObject]) != nil)
5471 if (ns_do_open_file || not_in_argv (file))
5472 [ns_pending_files addObject: file];
5473
5474 [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5475
5476 }
5477
5478
5479 /* Handle dock menu requests. */
5480 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5481 {
5482 return dockMenu;
5483 }
5484
5485
5486 /* TODO: these may help w/IO switching btwn terminal and NSApp */
5487 - (void)applicationWillBecomeActive: (NSNotification *)notification
5488 {
5489 NSTRACE ("[EmacsApp applicationWillBecomeActive:]");
5490 //ns_app_active=YES;
5491 }
5492
5493 - (void)applicationDidBecomeActive: (NSNotification *)notification
5494 {
5495 NSTRACE ("[EmacsApp applicationDidBecomeActive:]");
5496
5497 #ifdef NS_IMPL_GNUSTEP
5498 if (! applicationDidFinishLaunchingCalled)
5499 [self applicationDidFinishLaunching:notification];
5500 #endif
5501 //ns_app_active=YES;
5502
5503 ns_update_auto_hide_menu_bar ();
5504 // No constraining takes place when the application is not active.
5505 ns_constrain_all_frames ();
5506 }
5507 - (void)applicationDidResignActive: (NSNotification *)notification
5508 {
5509 NSTRACE ("[EmacsApp applicationDidResignActive:]");
5510
5511 //ns_app_active=NO;
5512 ns_send_appdefined (-1);
5513 }
5514
5515
5516
5517 /* ==========================================================================
5518
5519 EmacsApp aux handlers for managing event loop
5520
5521 ========================================================================== */
5522
5523
5524 - (void)timeout_handler: (NSTimer *)timedEntry
5525 /* --------------------------------------------------------------------------
5526 The timeout specified to ns_select has passed.
5527 -------------------------------------------------------------------------- */
5528 {
5529 /*NSTRACE ("timeout_handler"); */
5530 ns_send_appdefined (-2);
5531 }
5532
5533 #ifdef NS_IMPL_GNUSTEP
5534 - (void)sendFromMainThread:(id)unused
5535 {
5536 ns_send_appdefined (nextappdefined);
5537 }
5538 #endif
5539
5540 - (void)fd_handler:(id)unused
5541 /* --------------------------------------------------------------------------
5542 Check data waiting on file descriptors and terminate if so
5543 -------------------------------------------------------------------------- */
5544 {
5545 int result;
5546 int waiting = 1, nfds;
5547 char c;
5548
5549 fd_set readfds, writefds, *wfds;
5550 struct timespec timeout, *tmo;
5551 NSAutoreleasePool *pool = nil;
5552
5553 /* NSTRACE ("fd_handler"); */
5554
5555 for (;;)
5556 {
5557 [pool release];
5558 pool = [[NSAutoreleasePool alloc] init];
5559
5560 if (waiting)
5561 {
5562 fd_set fds;
5563 FD_ZERO (&fds);
5564 FD_SET (selfds[0], &fds);
5565 result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5566 if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5567 waiting = 0;
5568 }
5569 else
5570 {
5571 pthread_mutex_lock (&select_mutex);
5572 nfds = select_nfds;
5573
5574 if (select_valid & SELECT_HAVE_READ)
5575 readfds = select_readfds;
5576 else
5577 FD_ZERO (&readfds);
5578
5579 if (select_valid & SELECT_HAVE_WRITE)
5580 {
5581 writefds = select_writefds;
5582 wfds = &writefds;
5583 }
5584 else
5585 wfds = NULL;
5586 if (select_valid & SELECT_HAVE_TMO)
5587 {
5588 timeout = select_timeout;
5589 tmo = &timeout;
5590 }
5591 else
5592 tmo = NULL;
5593
5594 pthread_mutex_unlock (&select_mutex);
5595
5596 FD_SET (selfds[0], &readfds);
5597 if (selfds[0] >= nfds) nfds = selfds[0]+1;
5598
5599 result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5600
5601 if (result == 0)
5602 ns_send_appdefined (-2);
5603 else if (result > 0)
5604 {
5605 if (FD_ISSET (selfds[0], &readfds))
5606 {
5607 if (read (selfds[0], &c, 1) == 1 && c == 's')
5608 waiting = 1;
5609 }
5610 else
5611 {
5612 pthread_mutex_lock (&select_mutex);
5613 if (select_valid & SELECT_HAVE_READ)
5614 select_readfds = readfds;
5615 if (select_valid & SELECT_HAVE_WRITE)
5616 select_writefds = writefds;
5617 if (select_valid & SELECT_HAVE_TMO)
5618 select_timeout = timeout;
5619 pthread_mutex_unlock (&select_mutex);
5620
5621 ns_send_appdefined (result);
5622 }
5623 }
5624 waiting = 1;
5625 }
5626 }
5627 }
5628
5629
5630
5631 /* ==========================================================================
5632
5633 Service provision
5634
5635 ========================================================================== */
5636
5637 /* called from system: queue for next pass through event loop */
5638 - (void)requestService: (NSPasteboard *)pboard
5639 userData: (NSString *)userData
5640 error: (NSString **)error
5641 {
5642 [ns_pending_service_names addObject: userData];
5643 [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5644 SSDATA (ns_string_from_pasteboard (pboard))]];
5645 }
5646
5647
5648 /* called from ns_read_socket to clear queue */
5649 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5650 {
5651 struct frame *emacsframe = SELECTED_FRAME ();
5652 NSEvent *theEvent = [NSApp currentEvent];
5653
5654 NSTRACE ("[EmacsApp fulfillService:withArg:]");
5655
5656 if (!emacs_event)
5657 return NO;
5658
5659 emacs_event->kind = NS_NONKEY_EVENT;
5660 emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5661 ns_input_spi_name = build_string ([name UTF8String]);
5662 ns_input_spi_arg = build_string ([arg UTF8String]);
5663 emacs_event->modifiers = EV_MODIFIERS (theEvent);
5664 EV_TRAILER (theEvent);
5665
5666 return YES;
5667 }
5668
5669
5670 @end /* EmacsApp */
5671
5672
5673
5674 /* ==========================================================================
5675
5676 EmacsView implementation
5677
5678 ========================================================================== */
5679
5680
5681 @implementation EmacsView
5682
5683 /* needed to inform when window closed from LISP */
5684 - (void) setWindowClosing: (BOOL)closing
5685 {
5686 NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
5687
5688 windowClosing = closing;
5689 }
5690
5691
5692 - (void)dealloc
5693 {
5694 NSTRACE ("[EmacsView dealloc]");
5695 [toolbar release];
5696 if (fs_state == FULLSCREEN_BOTH)
5697 [nonfs_window release];
5698 [super dealloc];
5699 }
5700
5701
5702 /* called on font panel selection */
5703 - (void)changeFont: (id)sender
5704 {
5705 NSEvent *e = [[self window] currentEvent];
5706 struct face *face = FRAME_DEFAULT_FACE (emacsframe);
5707 struct font *font = face->font;
5708 id newFont;
5709 CGFloat size;
5710 NSFont *nsfont;
5711
5712 NSTRACE ("[EmacsView changeFont:]");
5713
5714 if (!emacs_event)
5715 return;
5716
5717 #ifdef NS_IMPL_GNUSTEP
5718 nsfont = ((struct nsfont_info *)font)->nsfont;
5719 #endif
5720 #ifdef NS_IMPL_COCOA
5721 nsfont = (NSFont *) macfont_get_nsctfont (font);
5722 #endif
5723
5724 if ((newFont = [sender convertFont: nsfont]))
5725 {
5726 SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5727
5728 emacs_event->kind = NS_NONKEY_EVENT;
5729 emacs_event->modifiers = 0;
5730 emacs_event->code = KEY_NS_CHANGE_FONT;
5731
5732 size = [newFont pointSize];
5733 ns_input_fontsize = make_number (lrint (size));
5734 ns_input_font = build_string ([[newFont familyName] UTF8String]);
5735 EV_TRAILER (e);
5736 }
5737 }
5738
5739
5740 - (BOOL)acceptsFirstResponder
5741 {
5742 NSTRACE ("[EmacsView acceptsFirstResponder]");
5743 return YES;
5744 }
5745
5746
5747 - (void)resetCursorRects
5748 {
5749 NSRect visible = [self visibleRect];
5750 NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5751 NSTRACE ("[EmacsView resetCursorRects]");
5752
5753 if (currentCursor == nil)
5754 currentCursor = [NSCursor arrowCursor];
5755
5756 if (!NSIsEmptyRect (visible))
5757 [self addCursorRect: visible cursor: currentCursor];
5758 [currentCursor setOnMouseEntered: YES];
5759 }
5760
5761
5762
5763 /*****************************************************************************/
5764 /* Keyboard handling. */
5765 #define NS_KEYLOG 0
5766
5767 - (void)keyDown: (NSEvent *)theEvent
5768 {
5769 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5770 int code;
5771 unsigned fnKeysym = 0;
5772 static NSMutableArray *nsEvArray;
5773 int left_is_none;
5774 unsigned int flags = [theEvent modifierFlags];
5775
5776 NSTRACE ("[EmacsView keyDown:]");
5777
5778 /* Rhapsody and OS X give up and down events for the arrow keys */
5779 if (ns_fake_keydown == YES)
5780 ns_fake_keydown = NO;
5781 else if ([theEvent type] != NSKeyDown)
5782 return;
5783
5784 if (!emacs_event)
5785 return;
5786
5787 if (![[self window] isKeyWindow]
5788 && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5789 /* we must avoid an infinite loop here. */
5790 && (EmacsView *)[[theEvent window] delegate] != self)
5791 {
5792 /* XXX: There is an occasional condition in which, when Emacs display
5793 updates a different frame from the current one, and temporarily
5794 selects it, then processes some interrupt-driven input
5795 (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5796 for some reason that window has its first responder set to the NSView
5797 most recently updated (I guess), which is not the correct one. */
5798 [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5799 return;
5800 }
5801
5802 if (nsEvArray == nil)
5803 nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5804
5805 [NSCursor setHiddenUntilMouseMoves: YES];
5806
5807 if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5808 {
5809 clear_mouse_face (hlinfo);
5810 hlinfo->mouse_face_hidden = 1;
5811 }
5812
5813 if (!processingCompose)
5814 {
5815 /* When using screen sharing, no left or right information is sent,
5816 so use Left key in those cases. */
5817 int is_left_key, is_right_key;
5818
5819 code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5820 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5821
5822 /* (Carbon way: [theEvent keyCode]) */
5823
5824 /* is it a "function key"? */
5825 /* Note: Sometimes a plain key will have the NSNumericPadKeyMask
5826 flag set (this is probably a bug in the OS).
5827 */
5828 if (code < 0x00ff && (flags&NSNumericPadKeyMask))
5829 {
5830 fnKeysym = ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask);
5831 }
5832 if (fnKeysym == 0)
5833 {
5834 fnKeysym = ns_convert_key (code);
5835 }
5836
5837 if (fnKeysym)
5838 {
5839 /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5840 because Emacs treats Delete and KP-Delete same (in simple.el). */
5841 if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5842 #ifdef NS_IMPL_GNUSTEP
5843 /* GNUstep uses incompatible keycodes, even for those that are
5844 supposed to be hardware independent. Just check for delete.
5845 Keypad delete does not have keysym 0xFFFF.
5846 See http://savannah.gnu.org/bugs/?25395
5847 */
5848 || (fnKeysym == 0xFFFF && code == 127)
5849 #endif
5850 )
5851 code = 0xFF08; /* backspace */
5852 else
5853 code = fnKeysym;
5854 }
5855
5856 /* are there modifiers? */
5857 emacs_event->modifiers = 0;
5858
5859 if (flags & NSHelpKeyMask)
5860 emacs_event->modifiers |= hyper_modifier;
5861
5862 if (flags & NSShiftKeyMask)
5863 emacs_event->modifiers |= shift_modifier;
5864
5865 is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5866 is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5867 || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
5868
5869 if (is_right_key)
5870 emacs_event->modifiers |= parse_solitary_modifier
5871 (EQ (ns_right_command_modifier, Qleft)
5872 ? ns_command_modifier
5873 : ns_right_command_modifier);
5874
5875 if (is_left_key)
5876 {
5877 emacs_event->modifiers |= parse_solitary_modifier
5878 (ns_command_modifier);
5879
5880 /* if super (default), take input manager's word so things like
5881 dvorak / qwerty layout work */
5882 if (EQ (ns_command_modifier, Qsuper)
5883 && !fnKeysym
5884 && [[theEvent characters] length] != 0)
5885 {
5886 /* XXX: the code we get will be unshifted, so if we have
5887 a shift modifier, must convert ourselves */
5888 if (!(flags & NSShiftKeyMask))
5889 code = [[theEvent characters] characterAtIndex: 0];
5890 #if 0
5891 /* this is ugly and also requires linking w/Carbon framework
5892 (for LMGetKbdType) so for now leave this rare (?) case
5893 undealt with.. in future look into CGEvent methods */
5894 else
5895 {
5896 long smv = GetScriptManagerVariable (smKeyScript);
5897 Handle uchrHandle = GetResource
5898 ('uchr', GetScriptVariable (smv, smScriptKeys));
5899 UInt32 dummy = 0;
5900 UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5901 [[theEvent characters] characterAtIndex: 0],
5902 kUCKeyActionDisplay,
5903 (flags & ~NSCommandKeyMask) >> 8,
5904 LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5905 &dummy, 1, &dummy, &code);
5906 code &= 0xFF;
5907 }
5908 #endif
5909 }
5910 }
5911
5912 is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5913 is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5914 || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5915
5916 if (is_right_key)
5917 emacs_event->modifiers |= parse_solitary_modifier
5918 (EQ (ns_right_control_modifier, Qleft)
5919 ? ns_control_modifier
5920 : ns_right_control_modifier);
5921
5922 if (is_left_key)
5923 emacs_event->modifiers |= parse_solitary_modifier
5924 (ns_control_modifier);
5925
5926 if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5927 emacs_event->modifiers |=
5928 parse_solitary_modifier (ns_function_modifier);
5929
5930 left_is_none = NILP (ns_alternate_modifier)
5931 || EQ (ns_alternate_modifier, Qnone);
5932
5933 is_right_key = (flags & NSRightAlternateKeyMask)
5934 == NSRightAlternateKeyMask;
5935 is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5936 || (! is_right_key
5937 && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5938
5939 if (is_right_key)
5940 {
5941 if ((NILP (ns_right_alternate_modifier)
5942 || EQ (ns_right_alternate_modifier, Qnone)
5943 || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5944 && !fnKeysym)
5945 { /* accept pre-interp alt comb */
5946 if ([[theEvent characters] length] > 0)
5947 code = [[theEvent characters] characterAtIndex: 0];
5948 /*HACK: clear lone shift modifier to stop next if from firing */
5949 if (emacs_event->modifiers == shift_modifier)
5950 emacs_event->modifiers = 0;
5951 }
5952 else
5953 emacs_event->modifiers |= parse_solitary_modifier
5954 (EQ (ns_right_alternate_modifier, Qleft)
5955 ? ns_alternate_modifier
5956 : ns_right_alternate_modifier);
5957 }
5958
5959 if (is_left_key) /* default = meta */
5960 {
5961 if (left_is_none && !fnKeysym)
5962 { /* accept pre-interp alt comb */
5963 if ([[theEvent characters] length] > 0)
5964 code = [[theEvent characters] characterAtIndex: 0];
5965 /*HACK: clear lone shift modifier to stop next if from firing */
5966 if (emacs_event->modifiers == shift_modifier)
5967 emacs_event->modifiers = 0;
5968 }
5969 else
5970 emacs_event->modifiers |=
5971 parse_solitary_modifier (ns_alternate_modifier);
5972 }
5973
5974 if (NS_KEYLOG)
5975 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5976 code, fnKeysym, flags, emacs_event->modifiers);
5977
5978 /* if it was a function key or had modifiers, pass it directly to emacs */
5979 if (fnKeysym || (emacs_event->modifiers
5980 && (emacs_event->modifiers != shift_modifier)
5981 && [[theEvent charactersIgnoringModifiers] length] > 0))
5982 /*[[theEvent characters] length] */
5983 {
5984 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5985 if (code < 0x20)
5986 code |= (1<<28)|(3<<16);
5987 else if (code == 0x7f)
5988 code |= (1<<28)|(3<<16);
5989 else if (!fnKeysym)
5990 emacs_event->kind = code > 0xFF
5991 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5992
5993 emacs_event->code = code;
5994 EV_TRAILER (theEvent);
5995 processingCompose = NO;
5996 return;
5997 }
5998 }
5999
6000
6001 if (NS_KEYLOG && !processingCompose)
6002 fprintf (stderr, "keyDown: Begin compose sequence.\n");
6003
6004 processingCompose = YES;
6005 [nsEvArray addObject: theEvent];
6006 [self interpretKeyEvents: nsEvArray];
6007 [nsEvArray removeObject: theEvent];
6008 }
6009
6010
6011 #ifdef NS_IMPL_COCOA
6012 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
6013 decided not to send key-down for.
6014 See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
6015 This only applies on Tiger and earlier.
6016 If it matches one of these, send it on to keyDown. */
6017 -(void)keyUp: (NSEvent *)theEvent
6018 {
6019 int flags = [theEvent modifierFlags];
6020 int code = [theEvent keyCode];
6021
6022 NSTRACE ("[EmacsView keyUp:]");
6023
6024 if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
6025 code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
6026 {
6027 if (NS_KEYLOG)
6028 fprintf (stderr, "keyUp: passed test");
6029 ns_fake_keydown = YES;
6030 [self keyDown: theEvent];
6031 }
6032 }
6033 #endif
6034
6035
6036 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
6037
6038
6039 /* <NSTextInput>: called when done composing;
6040 NOTE: also called when we delete over working text, followed immed.
6041 by doCommandBySelector: deleteBackward: */
6042 - (void)insertText: (id)aString
6043 {
6044 int code;
6045 int len = [(NSString *)aString length];
6046 int i;
6047
6048 NSTRACE ("[EmacsView insertText:]");
6049
6050 if (NS_KEYLOG)
6051 NSLog (@"insertText '%@'\tlen = %d", aString, len);
6052 processingCompose = NO;
6053
6054 if (!emacs_event)
6055 return;
6056
6057 /* first, clear any working text */
6058 if (workingText != nil)
6059 [self deleteWorkingText];
6060
6061 /* now insert the string as keystrokes */
6062 for (i =0; i<len; i++)
6063 {
6064 code = [aString characterAtIndex: i];
6065 /* TODO: still need this? */
6066 if (code == 0x2DC)
6067 code = '~'; /* 0x7E */
6068 if (code != 32) /* Space */
6069 emacs_event->modifiers = 0;
6070 emacs_event->kind
6071 = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6072 emacs_event->code = code;
6073 EV_TRAILER ((id)nil);
6074 }
6075 }
6076
6077
6078 /* <NSTextInput>: inserts display of composing characters */
6079 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
6080 {
6081 NSString *str = [aString respondsToSelector: @selector (string)] ?
6082 [aString string] : aString;
6083
6084 NSTRACE ("[EmacsView setMarkedText:selectedRange:]");
6085
6086 if (NS_KEYLOG)
6087 NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
6088 str, (unsigned long)[str length],
6089 (unsigned long)selRange.length,
6090 (unsigned long)selRange.location);
6091
6092 if (workingText != nil)
6093 [self deleteWorkingText];
6094 if ([str length] == 0)
6095 return;
6096
6097 if (!emacs_event)
6098 return;
6099
6100 processingCompose = YES;
6101 workingText = [str copy];
6102 ns_working_text = build_string ([workingText UTF8String]);
6103
6104 emacs_event->kind = NS_TEXT_EVENT;
6105 emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
6106 EV_TRAILER ((id)nil);
6107 }
6108
6109
6110 /* delete display of composing characters [not in <NSTextInput>] */
6111 - (void)deleteWorkingText
6112 {
6113 NSTRACE ("[EmacsView deleteWorkingText]");
6114
6115 if (workingText == nil)
6116 return;
6117 if (NS_KEYLOG)
6118 NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
6119 [workingText release];
6120 workingText = nil;
6121 processingCompose = NO;
6122
6123 if (!emacs_event)
6124 return;
6125
6126 emacs_event->kind = NS_TEXT_EVENT;
6127 emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
6128 EV_TRAILER ((id)nil);
6129 }
6130
6131
6132 - (BOOL)hasMarkedText
6133 {
6134 NSTRACE ("[EmacsView hasMarkedText]");
6135
6136 return workingText != nil;
6137 }
6138
6139
6140 - (NSRange)markedRange
6141 {
6142 NSTRACE ("[EmacsView markedRange]");
6143
6144 NSRange rng = workingText != nil
6145 ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
6146 if (NS_KEYLOG)
6147 NSLog (@"markedRange request");
6148 return rng;
6149 }
6150
6151
6152 - (void)unmarkText
6153 {
6154 NSTRACE ("[EmacsView unmarkText]");
6155
6156 if (NS_KEYLOG)
6157 NSLog (@"unmark (accept) text");
6158 [self deleteWorkingText];
6159 processingCompose = NO;
6160 }
6161
6162
6163 /* used to position char selection windows, etc. */
6164 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
6165 {
6166 NSRect rect;
6167 NSPoint pt;
6168 struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
6169
6170 NSTRACE ("[EmacsView firstRectForCharacterRange:]");
6171
6172 if (NS_KEYLOG)
6173 NSLog (@"firstRectForCharRange request");
6174
6175 rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
6176 rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
6177 pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
6178 pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
6179 +FRAME_LINE_HEIGHT (emacsframe));
6180
6181 pt = [self convertPoint: pt toView: nil];
6182 pt = [[self window] convertBaseToScreen: pt];
6183 rect.origin = pt;
6184 return rect;
6185 }
6186
6187
6188 - (NSInteger)conversationIdentifier
6189 {
6190 return (NSInteger)self;
6191 }
6192
6193
6194 - (void)doCommandBySelector: (SEL)aSelector
6195 {
6196 NSTRACE ("[EmacsView doCommandBySelector:]");
6197
6198 if (NS_KEYLOG)
6199 NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
6200
6201 processingCompose = NO;
6202 if (aSelector == @selector (deleteBackward:))
6203 {
6204 /* happens when user backspaces over an ongoing composition:
6205 throw a 'delete' into the event queue */
6206 if (!emacs_event)
6207 return;
6208 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6209 emacs_event->code = 0xFF08;
6210 EV_TRAILER ((id)nil);
6211 }
6212 }
6213
6214 - (NSArray *)validAttributesForMarkedText
6215 {
6216 static NSArray *arr = nil;
6217 if (arr == nil) arr = [NSArray new];
6218 /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
6219 return arr;
6220 }
6221
6222 - (NSRange)selectedRange
6223 {
6224 if (NS_KEYLOG)
6225 NSLog (@"selectedRange request");
6226 return NSMakeRange (NSNotFound, 0);
6227 }
6228
6229 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
6230 GNUSTEP_GUI_MINOR_VERSION > 22
6231 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
6232 #else
6233 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
6234 #endif
6235 {
6236 if (NS_KEYLOG)
6237 NSLog (@"characterIndexForPoint request");
6238 return 0;
6239 }
6240
6241 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
6242 {
6243 static NSAttributedString *str = nil;
6244 if (str == nil) str = [NSAttributedString new];
6245 if (NS_KEYLOG)
6246 NSLog (@"attributedSubstringFromRange request");
6247 return str;
6248 }
6249
6250 /* End <NSTextInput> impl. */
6251 /*****************************************************************************/
6252
6253
6254 /* This is what happens when the user presses a mouse button. */
6255 - (void)mouseDown: (NSEvent *)theEvent
6256 {
6257 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6258 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
6259
6260 NSTRACE ("[EmacsView mouseDown:]");
6261
6262 [self deleteWorkingText];
6263
6264 if (!emacs_event)
6265 return;
6266
6267 dpyinfo->last_mouse_frame = emacsframe;
6268 /* appears to be needed to prevent spurious movement events generated on
6269 button clicks */
6270 emacsframe->mouse_moved = 0;
6271
6272 if ([theEvent type] == NSScrollWheel)
6273 {
6274 CGFloat delta = [theEvent deltaY];
6275 /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
6276 if (delta == 0)
6277 {
6278 delta = [theEvent deltaX];
6279 if (delta == 0)
6280 {
6281 NSTRACE_MSG ("deltaIsZero");
6282 return;
6283 }
6284 emacs_event->kind = HORIZ_WHEEL_EVENT;
6285 }
6286 else
6287 emacs_event->kind = WHEEL_EVENT;
6288
6289 emacs_event->code = 0;
6290 emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6291 ((delta > 0) ? up_modifier : down_modifier);
6292 }
6293 else
6294 {
6295 emacs_event->kind = MOUSE_CLICK_EVENT;
6296 emacs_event->code = EV_BUTTON (theEvent);
6297 emacs_event->modifiers = EV_MODIFIERS (theEvent)
6298 | EV_UDMODIFIERS (theEvent);
6299 }
6300 XSETINT (emacs_event->x, lrint (p.x));
6301 XSETINT (emacs_event->y, lrint (p.y));
6302 EV_TRAILER (theEvent);
6303 }
6304
6305
6306 - (void)rightMouseDown: (NSEvent *)theEvent
6307 {
6308 NSTRACE ("[EmacsView rightMouseDown:]");
6309 [self mouseDown: theEvent];
6310 }
6311
6312
6313 - (void)otherMouseDown: (NSEvent *)theEvent
6314 {
6315 NSTRACE ("[EmacsView otherMouseDown:]");
6316 [self mouseDown: theEvent];
6317 }
6318
6319
6320 - (void)mouseUp: (NSEvent *)theEvent
6321 {
6322 NSTRACE ("[EmacsView mouseUp:]");
6323 [self mouseDown: theEvent];
6324 }
6325
6326
6327 - (void)rightMouseUp: (NSEvent *)theEvent
6328 {
6329 NSTRACE ("[EmacsView rightMouseUp:]");
6330 [self mouseDown: theEvent];
6331 }
6332
6333
6334 - (void)otherMouseUp: (NSEvent *)theEvent
6335 {
6336 NSTRACE ("[EmacsView otherMouseUp:]");
6337 [self mouseDown: theEvent];
6338 }
6339
6340
6341 - (void) scrollWheel: (NSEvent *)theEvent
6342 {
6343 NSTRACE ("[EmacsView scrollWheel:]");
6344 [self mouseDown: theEvent];
6345 }
6346
6347
6348 /* Tell emacs the mouse has moved. */
6349 - (void)mouseMoved: (NSEvent *)e
6350 {
6351 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6352 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6353 Lisp_Object frame;
6354 NSPoint pt;
6355
6356 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
6357
6358 dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6359 pt = [self convertPoint: [e locationInWindow] fromView: nil];
6360 dpyinfo->last_mouse_motion_x = pt.x;
6361 dpyinfo->last_mouse_motion_y = pt.y;
6362
6363 /* update any mouse face */
6364 if (hlinfo->mouse_face_hidden)
6365 {
6366 hlinfo->mouse_face_hidden = 0;
6367 clear_mouse_face (hlinfo);
6368 }
6369
6370 /* tooltip handling */
6371 previous_help_echo_string = help_echo_string;
6372 help_echo_string = Qnil;
6373
6374 if (!NILP (Vmouse_autoselect_window))
6375 {
6376 NSTRACE_MSG ("mouse_autoselect_window");
6377 static Lisp_Object last_mouse_window;
6378 Lisp_Object window
6379 = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6380
6381 if (WINDOWP (window)
6382 && !EQ (window, last_mouse_window)
6383 && !EQ (window, selected_window)
6384 && (focus_follows_mouse
6385 || (EQ (XWINDOW (window)->frame,
6386 XWINDOW (selected_window)->frame))))
6387 {
6388 NSTRACE_MSG ("in_window");
6389 emacs_event->kind = SELECT_WINDOW_EVENT;
6390 emacs_event->frame_or_window = window;
6391 EV_TRAILER2 (e);
6392 }
6393 /* Remember the last window where we saw the mouse. */
6394 last_mouse_window = window;
6395 }
6396
6397 if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6398 help_echo_string = previous_help_echo_string;
6399
6400 XSETFRAME (frame, emacsframe);
6401 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6402 {
6403 /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6404 (note_mouse_highlight), which is called through the
6405 note_mouse_movement () call above */
6406 any_help_event_p = YES;
6407 gen_help_event (help_echo_string, frame, help_echo_window,
6408 help_echo_object, help_echo_pos);
6409 }
6410
6411 if (emacsframe->mouse_moved && send_appdefined)
6412 ns_send_appdefined (-1);
6413 }
6414
6415
6416 - (void)mouseDragged: (NSEvent *)e
6417 {
6418 NSTRACE ("[EmacsView mouseDragged:]");
6419 [self mouseMoved: e];
6420 }
6421
6422
6423 - (void)rightMouseDragged: (NSEvent *)e
6424 {
6425 NSTRACE ("[EmacsView rightMouseDragged:]");
6426 [self mouseMoved: e];
6427 }
6428
6429
6430 - (void)otherMouseDragged: (NSEvent *)e
6431 {
6432 NSTRACE ("[EmacsView otherMouseDragged:]");
6433 [self mouseMoved: e];
6434 }
6435
6436
6437 - (BOOL)windowShouldClose: (id)sender
6438 {
6439 NSEvent *e =[[self window] currentEvent];
6440
6441 NSTRACE ("[EmacsView windowShouldClose:]");
6442 windowClosing = YES;
6443 if (!emacs_event)
6444 return NO;
6445 emacs_event->kind = DELETE_WINDOW_EVENT;
6446 emacs_event->modifiers = 0;
6447 emacs_event->code = 0;
6448 EV_TRAILER (e);
6449 /* Don't close this window, let this be done from lisp code. */
6450 return NO;
6451 }
6452
6453 - (void) updateFrameSize: (BOOL) delay;
6454 {
6455 NSWindow *window = [self window];
6456 NSRect wr = [window frame];
6457 int extra = 0;
6458 int oldc = cols, oldr = rows;
6459 int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6460 int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6461 int neww, newh;
6462
6463 NSTRACE ("[EmacsView updateFrameSize:]");
6464 NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6465 NSTRACE_RECT ("Original frame", wr);
6466 NSTRACE_MSG ("Original columns: %d", cols);
6467 NSTRACE_MSG ("Original rows: %d", rows);
6468
6469 if (! [self isFullscreen])
6470 {
6471 #ifdef NS_IMPL_GNUSTEP
6472 // GNUstep does not always update the tool bar height. Force it.
6473 if (toolbar && [toolbar isVisible])
6474 update_frame_tool_bar (emacsframe);
6475 #endif
6476
6477 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6478 + FRAME_TOOLBAR_HEIGHT (emacsframe);
6479 }
6480
6481 if (wait_for_tool_bar)
6482 {
6483 if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0)
6484 {
6485 NSTRACE_MSG ("Waiting for toolbar");
6486 return;
6487 }
6488 wait_for_tool_bar = NO;
6489 }
6490
6491 neww = (int)wr.size.width - emacsframe->border_width;
6492 newh = (int)wr.size.height - extra;
6493
6494 NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6495 NSTRACE_MSG ("tool_bar_height: %d", emacsframe->tool_bar_height);
6496
6497 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6498 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6499
6500 if (cols < MINWIDTH)
6501 cols = MINWIDTH;
6502
6503 if (rows < MINHEIGHT)
6504 rows = MINHEIGHT;
6505
6506 NSTRACE_MSG ("New columns: %d", cols);
6507 NSTRACE_MSG ("New rows: %d", rows);
6508
6509 if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6510 {
6511 NSView *view = FRAME_NS_VIEW (emacsframe);
6512
6513 change_frame_size (emacsframe,
6514 FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
6515 FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
6516 0, delay, 0, 1);
6517 SET_FRAME_GARBAGED (emacsframe);
6518 cancel_mouse_face (emacsframe);
6519
6520 wr = NSMakeRect (0, 0, neww, newh);
6521
6522 [view setFrame: wr];
6523
6524 // to do: consider using [NSNotificationCenter postNotificationName:].
6525 [self windowDidMove: // Update top/left.
6526 [NSNotification notificationWithName:NSWindowDidMoveNotification
6527 object:[view window]]];
6528 }
6529 else
6530 {
6531 NSTRACE_MSG ("No change");
6532 }
6533 }
6534
6535 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6536 /* normalize frame to gridded text size */
6537 {
6538 int extra = 0;
6539
6540 NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
6541 NSTRACE_ARG_SIZE (frameSize));
6542 NSTRACE_RECT ("[sender frame]", [sender frame]);
6543 NSTRACE_FSTYPE ("fs_state", fs_state);
6544
6545 if (fs_state == FULLSCREEN_MAXIMIZED
6546 && (maximized_width != (int)frameSize.width
6547 || maximized_height != (int)frameSize.height))
6548 [self setFSValue: FULLSCREEN_NONE];
6549 else if (fs_state == FULLSCREEN_WIDTH
6550 && maximized_width != (int)frameSize.width)
6551 [self setFSValue: FULLSCREEN_NONE];
6552 else if (fs_state == FULLSCREEN_HEIGHT
6553 && maximized_height != (int)frameSize.height)
6554 [self setFSValue: FULLSCREEN_NONE];
6555
6556 if (fs_state == FULLSCREEN_NONE)
6557 maximized_width = maximized_height = -1;
6558
6559 if (! [self isFullscreen])
6560 {
6561 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6562 + FRAME_TOOLBAR_HEIGHT (emacsframe);
6563 }
6564
6565 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6566 if (cols < MINWIDTH)
6567 cols = MINWIDTH;
6568
6569 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6570 frameSize.height - extra);
6571 if (rows < MINHEIGHT)
6572 rows = MINHEIGHT;
6573 #ifdef NS_IMPL_COCOA
6574 {
6575 /* this sets window title to have size in it; the wm does this under GS */
6576 NSRect r = [[self window] frame];
6577 if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6578 {
6579 if (old_title != 0)
6580 {
6581 xfree (old_title);
6582 old_title = 0;
6583 }
6584 }
6585 else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
6586 {
6587 char *size_title;
6588 NSWindow *window = [self window];
6589 if (old_title == 0)
6590 {
6591 char *t = strdup ([[[self window] title] UTF8String]);
6592 char *pos = strstr (t, " — ");
6593 if (pos)
6594 *pos = '\0';
6595 old_title = t;
6596 }
6597 size_title = xmalloc (strlen (old_title) + 40);
6598 esprintf (size_title, "%s — (%d x %d)", old_title, cols, rows);
6599 [window setTitle: [NSString stringWithUTF8String: size_title]];
6600 [window display];
6601 xfree (size_title);
6602 }
6603 }
6604 #endif /* NS_IMPL_COCOA */
6605
6606 NSTRACE_MSG ("cols: %d rows: %d", cols, rows);
6607
6608 /* Restrict the new size to the text gird.
6609
6610 Don't restrict the width if the user only adjusted the height, and
6611 vice versa. (Without this, the frame would shrink, and move
6612 slightly, if the window was resized by dragging one of its
6613 borders.) */
6614 if (!frame_resize_pixelwise)
6615 {
6616 NSRect r = [[self window] frame];
6617
6618 if (r.size.width != frameSize.width)
6619 {
6620 frameSize.width =
6621 FRAME_TEXT_COLS_TO_PIXEL_WIDTH (emacsframe, cols);
6622 }
6623
6624 if (r.size.height != frameSize.height)
6625 {
6626 frameSize.height =
6627 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
6628 }
6629 }
6630
6631 NSTRACE_RETURN_SIZE (frameSize);
6632
6633 return frameSize;
6634 }
6635
6636
6637 - (void)windowDidResize: (NSNotification *)notification
6638 {
6639 NSTRACE ("[EmacsView windowDidResize:]");
6640 if (!FRAME_LIVE_P (emacsframe))
6641 {
6642 NSTRACE_MSG ("Ignored (frame dead)");
6643 return;
6644 }
6645 if (emacsframe->output_data.ns->in_animation)
6646 {
6647 NSTRACE_MSG ("Ignored (in animation)");
6648 return;
6649 }
6650
6651 if (! [self fsIsNative])
6652 {
6653 NSWindow *theWindow = [notification object];
6654 /* We can get notification on the non-FS window when in
6655 fullscreen mode. */
6656 if ([self window] != theWindow) return;
6657 }
6658
6659 NSTRACE_RECT ("frame", [[notification object] frame]);
6660
6661 #ifdef NS_IMPL_GNUSTEP
6662 NSWindow *theWindow = [notification object];
6663
6664 /* In GNUstep, at least currently, it's possible to get a didResize
6665 without getting a willResize.. therefore we need to act as if we got
6666 the willResize now */
6667 NSSize sz = [theWindow frame].size;
6668 sz = [self windowWillResize: theWindow toSize: sz];
6669 #endif /* NS_IMPL_GNUSTEP */
6670
6671 if (cols > 0 && rows > 0)
6672 {
6673 [self updateFrameSize: YES];
6674 }
6675
6676 ns_send_appdefined (-1);
6677 }
6678
6679 #ifdef NS_IMPL_COCOA
6680 - (void)viewDidEndLiveResize
6681 {
6682 NSTRACE ("[EmacsView viewDidEndLiveResize]");
6683
6684 [super viewDidEndLiveResize];
6685 if (old_title != 0)
6686 {
6687 [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
6688 xfree (old_title);
6689 old_title = 0;
6690 }
6691 maximizing_resize = NO;
6692 }
6693 #endif /* NS_IMPL_COCOA */
6694
6695
6696 - (void)windowDidBecomeKey: (NSNotification *)notification
6697 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6698 {
6699 [self windowDidBecomeKey];
6700 }
6701
6702
6703 - (void)windowDidBecomeKey /* for direct calls */
6704 {
6705 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6706 struct frame *old_focus = dpyinfo->x_focus_frame;
6707
6708 NSTRACE ("[EmacsView windowDidBecomeKey]");
6709
6710 if (emacsframe != old_focus)
6711 dpyinfo->x_focus_frame = emacsframe;
6712
6713 ns_frame_rehighlight (emacsframe);
6714
6715 if (emacs_event)
6716 {
6717 emacs_event->kind = FOCUS_IN_EVENT;
6718 EV_TRAILER ((id)nil);
6719 }
6720 }
6721
6722
6723 - (void)windowDidResignKey: (NSNotification *)notification
6724 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6725 {
6726 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6727 BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6728 NSTRACE ("[EmacsView windowDidResignKey:]");
6729
6730 if (is_focus_frame)
6731 dpyinfo->x_focus_frame = 0;
6732
6733 emacsframe->mouse_moved = 0;
6734 ns_frame_rehighlight (emacsframe);
6735
6736 /* FIXME: for some reason needed on second and subsequent clicks away
6737 from sole-frame Emacs to get hollow box to show */
6738 if (!windowClosing && [[self window] isVisible] == YES)
6739 {
6740 x_update_cursor (emacsframe, 1);
6741 x_set_frame_alpha (emacsframe);
6742 }
6743
6744 if (any_help_event_p)
6745 {
6746 Lisp_Object frame;
6747 XSETFRAME (frame, emacsframe);
6748 help_echo_string = Qnil;
6749 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
6750 }
6751
6752 if (emacs_event && is_focus_frame)
6753 {
6754 [self deleteWorkingText];
6755 emacs_event->kind = FOCUS_OUT_EVENT;
6756 EV_TRAILER ((id)nil);
6757 }
6758 }
6759
6760
6761 - (void)windowWillMiniaturize: sender
6762 {
6763 NSTRACE ("[EmacsView windowWillMiniaturize:]");
6764 }
6765
6766
6767 - (void)setFrame:(NSRect)frameRect;
6768 {
6769 NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
6770 NSTRACE_ARG_RECT (frameRect));
6771
6772 [super setFrame:(NSRect)frameRect];
6773 }
6774
6775
6776 - (BOOL)isFlipped
6777 {
6778 return YES;
6779 }
6780
6781
6782 - (BOOL)isOpaque
6783 {
6784 return NO;
6785 }
6786
6787
6788 - initFrameFromEmacs: (struct frame *)f
6789 {
6790 NSRect r, wr;
6791 Lisp_Object tem;
6792 NSWindow *win;
6793 NSColor *col;
6794 NSString *name;
6795
6796 NSTRACE ("[EmacsView initFrameFromEmacs:]");
6797 NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
6798
6799 windowClosing = NO;
6800 processingCompose = NO;
6801 scrollbarsNeedingUpdate = 0;
6802 fs_state = FULLSCREEN_NONE;
6803 fs_before_fs = next_maximized = -1;
6804 #ifdef HAVE_NATIVE_FS
6805 fs_is_native = ns_use_native_fullscreen;
6806 #else
6807 fs_is_native = NO;
6808 #endif
6809 maximized_width = maximized_height = -1;
6810 nonfs_window = nil;
6811
6812 ns_userRect = NSMakeRect (0, 0, 0, 0);
6813 r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
6814 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
6815 [self initWithFrame: r];
6816 [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
6817
6818 FRAME_NS_VIEW (f) = self;
6819 emacsframe = f;
6820 #ifdef NS_IMPL_COCOA
6821 old_title = 0;
6822 maximizing_resize = NO;
6823 #endif
6824
6825 win = [[EmacsWindow alloc]
6826 initWithContentRect: r
6827 styleMask: (NSResizableWindowMask |
6828 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6829 NSTitledWindowMask |
6830 #endif
6831 NSMiniaturizableWindowMask |
6832 NSClosableWindowMask)
6833 backing: NSBackingStoreBuffered
6834 defer: YES];
6835
6836 #ifdef HAVE_NATIVE_FS
6837 [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
6838 #endif
6839
6840 wr = [win frame];
6841 bwidth = f->border_width = wr.size.width - r.size.width;
6842 tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
6843
6844 [win setAcceptsMouseMovedEvents: YES];
6845 [win setDelegate: self];
6846 #if !defined (NS_IMPL_COCOA) || \
6847 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6848 [win useOptimizedDrawing: YES];
6849 #endif
6850
6851 [[win contentView] addSubview: self];
6852
6853 if (ns_drag_types)
6854 [self registerForDraggedTypes: ns_drag_types];
6855
6856 tem = f->name;
6857 name = [NSString stringWithUTF8String:
6858 NILP (tem) ? "Emacs" : SSDATA (tem)];
6859 [win setTitle: name];
6860
6861 /* toolbar support */
6862 toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6863 [NSString stringWithFormat: @"Emacs Frame %d",
6864 ns_window_num]];
6865 [win setToolbar: toolbar];
6866 [toolbar setVisible: NO];
6867
6868 /* Don't set frame garbaged until tool bar is up to date?
6869 This avoids an extra clear and redraw (flicker) at frame creation. */
6870 if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6871 else wait_for_tool_bar = NO;
6872
6873
6874 #ifdef NS_IMPL_COCOA
6875 {
6876 NSButton *toggleButton;
6877 toggleButton = [win standardWindowButton: NSWindowToolbarButton];
6878 [toggleButton setTarget: self];
6879 [toggleButton setAction: @selector (toggleToolbar: )];
6880 }
6881 #endif
6882 FRAME_TOOLBAR_HEIGHT (f) = 0;
6883
6884 tem = f->icon_name;
6885 if (!NILP (tem))
6886 [win setMiniwindowTitle:
6887 [NSString stringWithUTF8String: SSDATA (tem)]];
6888
6889 {
6890 NSScreen *screen = [win screen];
6891
6892 if (screen != 0)
6893 {
6894 NSPoint pt = NSMakePoint
6895 (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
6896 IN_BOUND (-SCREENMAX,
6897 [screen frame].size.height - NS_TOP_POS (f), SCREENMAX));
6898
6899 [win setFrameTopLeftPoint: pt];
6900
6901 NSTRACE_RECT ("new frame", [win frame]);
6902 }
6903 }
6904
6905 [win makeFirstResponder: self];
6906
6907 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6908 (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
6909 [win setBackgroundColor: col];
6910 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6911 [win setOpaque: NO];
6912
6913 #if !defined (NS_IMPL_COCOA) || \
6914 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6915 [self allocateGState];
6916 #endif
6917 [NSApp registerServicesMenuSendTypes: ns_send_types
6918 returnTypes: nil];
6919
6920 ns_window_num++;
6921 return self;
6922 }
6923
6924
6925 - (void)windowDidMove: sender
6926 {
6927 NSWindow *win = [self window];
6928 NSRect r = [win frame];
6929 NSArray *screens = [NSScreen screens];
6930 NSScreen *screen = [screens objectAtIndex: 0];
6931
6932 NSTRACE ("[EmacsView windowDidMove:]");
6933
6934 if (!emacsframe->output_data.ns)
6935 return;
6936 if (screen != nil)
6937 {
6938 emacsframe->left_pos = r.origin.x;
6939 emacsframe->top_pos =
6940 [screen frame].size.height - (r.origin.y + r.size.height);
6941 }
6942 }
6943
6944
6945 /* Called AFTER method below, but before our windowWillResize call there leads
6946 to windowDidResize -> x_set_window_size. Update emacs' notion of frame
6947 location so set_window_size moves the frame. */
6948 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
6949 {
6950 NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
6951 NSTRACE_FMT_RETURN "YES"),
6952 NSTRACE_ARG_RECT (newFrame));
6953
6954 emacsframe->output_data.ns->zooming = 1;
6955 return YES;
6956 }
6957
6958
6959 /* Override to do something slightly nonstandard, but nice. First click on
6960 zoom button will zoom vertically. Second will zoom completely. Third
6961 returns to original. */
6962 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
6963 defaultFrame:(NSRect)defaultFrame
6964 {
6965 // TODO: Rename to "currentFrame" and assign "result" properly in
6966 // all paths.
6967 NSRect result = [sender frame];
6968
6969 NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
6970 NSTRACE_FMT_RECT "]"),
6971 NSTRACE_ARG_RECT (defaultFrame));
6972 NSTRACE_FSTYPE ("fs_state", fs_state);
6973 NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
6974 NSTRACE_FSTYPE ("next_maximized", next_maximized);
6975 NSTRACE_RECT ("ns_userRect", ns_userRect);
6976 NSTRACE_RECT ("[sender frame]", [sender frame]);
6977
6978 if (fs_before_fs != -1) /* Entering fullscreen */
6979 {
6980 NSTRACE_MSG ("Entering fullscreen");
6981 result = defaultFrame;
6982 }
6983 else
6984 {
6985 // Save the window size and position (frame) before the resize.
6986 if (fs_state != FULLSCREEN_MAXIMIZED
6987 && fs_state != FULLSCREEN_WIDTH)
6988 {
6989 ns_userRect.size.width = result.size.width;
6990 ns_userRect.origin.x = result.origin.x;
6991 }
6992
6993 if (fs_state != FULLSCREEN_MAXIMIZED
6994 && fs_state != FULLSCREEN_HEIGHT)
6995 {
6996 ns_userRect.size.height = result.size.height;
6997 ns_userRect.origin.y = result.origin.y;
6998 }
6999
7000 NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
7001
7002 if (next_maximized == FULLSCREEN_HEIGHT
7003 || (next_maximized == -1
7004 && abs ((int)(defaultFrame.size.height - result.size.height))
7005 > FRAME_LINE_HEIGHT (emacsframe)))
7006 {
7007 /* first click */
7008 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7009 maximized_height = result.size.height = defaultFrame.size.height;
7010 maximized_width = -1;
7011 result.origin.y = defaultFrame.origin.y;
7012 if (ns_userRect.size.height != 0)
7013 {
7014 result.origin.x = ns_userRect.origin.x;
7015 result.size.width = ns_userRect.size.width;
7016 }
7017 [self setFSValue: FULLSCREEN_HEIGHT];
7018 #ifdef NS_IMPL_COCOA
7019 maximizing_resize = YES;
7020 #endif
7021 }
7022 else if (next_maximized == FULLSCREEN_WIDTH)
7023 {
7024 NSTRACE_MSG ("FULLSCREEN_WIDTH");
7025 maximized_width = result.size.width = defaultFrame.size.width;
7026 maximized_height = -1;
7027 result.origin.x = defaultFrame.origin.x;
7028 if (ns_userRect.size.width != 0)
7029 {
7030 result.origin.y = ns_userRect.origin.y;
7031 result.size.height = ns_userRect.size.height;
7032 }
7033 [self setFSValue: FULLSCREEN_WIDTH];
7034 }
7035 else if (next_maximized == FULLSCREEN_MAXIMIZED
7036 || (next_maximized == -1
7037 && abs ((int)(defaultFrame.size.width - result.size.width))
7038 > FRAME_COLUMN_WIDTH (emacsframe)))
7039 {
7040 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7041
7042 result = defaultFrame; /* second click */
7043 maximized_width = result.size.width;
7044 maximized_height = result.size.height;
7045 [self setFSValue: FULLSCREEN_MAXIMIZED];
7046 #ifdef NS_IMPL_COCOA
7047 maximizing_resize = YES;
7048 #endif
7049 }
7050 else
7051 {
7052 /* restore */
7053 NSTRACE_MSG ("Restore");
7054 result = ns_userRect.size.height ? ns_userRect : result;
7055 NSTRACE_RECT ("restore (2)", result);
7056 ns_userRect = NSMakeRect (0, 0, 0, 0);
7057 #ifdef NS_IMPL_COCOA
7058 maximizing_resize = fs_state != FULLSCREEN_NONE;
7059 #endif
7060 [self setFSValue: FULLSCREEN_NONE];
7061 maximized_width = maximized_height = -1;
7062 }
7063 }
7064
7065 if (fs_before_fs == -1) next_maximized = -1;
7066
7067 NSTRACE_RECT ("Final ns_userRect", ns_userRect);
7068 NSTRACE_MSG ("Final maximized_width: %d", maximized_width);
7069 NSTRACE_MSG ("Final maximized_height: %d", maximized_height);
7070 NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
7071
7072 [self windowWillResize: sender toSize: result.size];
7073
7074 NSTRACE_RETURN_RECT (result);
7075
7076 return result;
7077 }
7078
7079
7080 - (void)windowDidDeminiaturize: sender
7081 {
7082 NSTRACE ("[EmacsView windowDidDeminiaturize:]");
7083 if (!emacsframe->output_data.ns)
7084 return;
7085
7086 SET_FRAME_ICONIFIED (emacsframe, 0);
7087 SET_FRAME_VISIBLE (emacsframe, 1);
7088 windows_or_buffers_changed = 63;
7089
7090 if (emacs_event)
7091 {
7092 emacs_event->kind = DEICONIFY_EVENT;
7093 EV_TRAILER ((id)nil);
7094 }
7095 }
7096
7097
7098 - (void)windowDidExpose: sender
7099 {
7100 NSTRACE ("[EmacsView windowDidExpose:]");
7101 if (!emacsframe->output_data.ns)
7102 return;
7103
7104 SET_FRAME_VISIBLE (emacsframe, 1);
7105 SET_FRAME_GARBAGED (emacsframe);
7106
7107 if (send_appdefined)
7108 ns_send_appdefined (-1);
7109 }
7110
7111
7112 - (void)windowDidMiniaturize: sender
7113 {
7114 NSTRACE ("[EmacsView windowDidMiniaturize:]");
7115 if (!emacsframe->output_data.ns)
7116 return;
7117
7118 SET_FRAME_ICONIFIED (emacsframe, 1);
7119 SET_FRAME_VISIBLE (emacsframe, 0);
7120
7121 if (emacs_event)
7122 {
7123 emacs_event->kind = ICONIFY_EVENT;
7124 EV_TRAILER ((id)nil);
7125 }
7126 }
7127
7128 #ifdef HAVE_NATIVE_FS
7129 - (NSApplicationPresentationOptions)window:(NSWindow *)window
7130 willUseFullScreenPresentationOptions:
7131 (NSApplicationPresentationOptions)proposedOptions
7132 {
7133 return proposedOptions|NSApplicationPresentationAutoHideToolbar;
7134 }
7135 #endif
7136
7137 - (void)windowWillEnterFullScreen:(NSNotification *)notification
7138 {
7139 NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
7140 [self windowWillEnterFullScreen];
7141 }
7142 - (void)windowWillEnterFullScreen /* provided for direct calls */
7143 {
7144 NSTRACE ("[EmacsView windowWillEnterFullScreen]");
7145 fs_before_fs = fs_state;
7146 }
7147
7148 - (void)windowDidEnterFullScreen:(NSNotification *)notification
7149 {
7150 NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
7151 [self windowDidEnterFullScreen];
7152 }
7153
7154 - (void)windowDidEnterFullScreen /* provided for direct calls */
7155 {
7156 NSTRACE ("[EmacsView windowDidEnterFullScreen]");
7157 [self setFSValue: FULLSCREEN_BOTH];
7158 if (! [self fsIsNative])
7159 {
7160 [self windowDidBecomeKey];
7161 [nonfs_window orderOut:self];
7162 }
7163 else
7164 {
7165 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
7166 #ifdef NS_IMPL_COCOA
7167 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
7168 unsigned val = (unsigned)[NSApp presentationOptions];
7169
7170 // OSX 10.7 bug fix, the menu won't appear without this.
7171 // val is non-zero on other OSX versions.
7172 if (val == 0)
7173 {
7174 NSApplicationPresentationOptions options
7175 = NSApplicationPresentationAutoHideDock
7176 | NSApplicationPresentationAutoHideMenuBar
7177 | NSApplicationPresentationFullScreen
7178 | NSApplicationPresentationAutoHideToolbar;
7179
7180 [NSApp setPresentationOptions: options];
7181 }
7182 #endif
7183 #endif
7184 [toolbar setVisible:tbar_visible];
7185 }
7186 }
7187
7188 - (void)windowWillExitFullScreen:(NSNotification *)notification
7189 {
7190 NSTRACE ("[EmacsView windowWillExitFullScreen:]");
7191 [self windowWillExitFullScreen];
7192 }
7193
7194 - (void)windowWillExitFullScreen /* provided for direct calls */
7195 {
7196 NSTRACE ("[EmacsView windowWillExitFullScreen]");
7197 if (!FRAME_LIVE_P (emacsframe))
7198 {
7199 NSTRACE_MSG ("Ignored (frame dead)");
7200 return;
7201 }
7202 if (next_maximized != -1)
7203 fs_before_fs = next_maximized;
7204 }
7205
7206 - (void)windowDidExitFullScreen:(NSNotification *)notification
7207 {
7208 NSTRACE ("[EmacsView windowDidExitFullScreen:]");
7209 [self windowDidExitFullScreen];
7210 }
7211
7212 - (void)windowDidExitFullScreen /* provided for direct calls */
7213 {
7214 NSTRACE ("[EmacsView windowDidExitFullScreen]");
7215 if (!FRAME_LIVE_P (emacsframe))
7216 {
7217 NSTRACE_MSG ("Ignored (frame dead)");
7218 return;
7219 }
7220 [self setFSValue: fs_before_fs];
7221 fs_before_fs = -1;
7222 #ifdef HAVE_NATIVE_FS
7223 [self updateCollectionBehavior];
7224 #endif
7225 if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7226 {
7227 [toolbar setVisible:YES];
7228 update_frame_tool_bar (emacsframe);
7229 [self updateFrameSize:YES];
7230 [[self window] display];
7231 }
7232 else
7233 [toolbar setVisible:NO];
7234
7235 if (next_maximized != -1)
7236 [[self window] performZoom:self];
7237 }
7238
7239 - (BOOL)fsIsNative
7240 {
7241 return fs_is_native;
7242 }
7243
7244 - (BOOL)isFullscreen
7245 {
7246 BOOL res;
7247
7248 if (! fs_is_native)
7249 {
7250 res = (nonfs_window != nil);
7251 }
7252 else
7253 {
7254 #ifdef HAVE_NATIVE_FS
7255 res = (([[self window] styleMask] & NSFullScreenWindowMask) != 0);
7256 #else
7257 res = NO;
7258 #endif
7259 }
7260
7261 NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
7262 (int) res);
7263
7264 return res;
7265 }
7266
7267 #ifdef HAVE_NATIVE_FS
7268 - (void)updateCollectionBehavior
7269 {
7270 NSTRACE ("[EmacsView updateCollectionBehavior]");
7271
7272 if (! [self isFullscreen])
7273 {
7274 NSWindow *win = [self window];
7275 NSWindowCollectionBehavior b = [win collectionBehavior];
7276 if (ns_use_native_fullscreen)
7277 b |= NSWindowCollectionBehaviorFullScreenPrimary;
7278 else
7279 b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7280
7281 [win setCollectionBehavior: b];
7282 fs_is_native = ns_use_native_fullscreen;
7283 }
7284 }
7285 #endif
7286
7287 - (void)toggleFullScreen: (id)sender
7288 {
7289 NSWindow *w, *fw;
7290 BOOL onFirstScreen;
7291 struct frame *f;
7292 NSRect r, wr;
7293 NSColor *col;
7294
7295 NSTRACE ("[EmacsView toggleFullScreen:]");
7296
7297 if (fs_is_native)
7298 {
7299 #ifdef HAVE_NATIVE_FS
7300 [[self window] toggleFullScreen:sender];
7301 #endif
7302 return;
7303 }
7304
7305 w = [self window];
7306 onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7307 f = emacsframe;
7308 wr = [w frame];
7309 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7310 (FRAME_DEFAULT_FACE (f)),
7311 f);
7312
7313 if (fs_state != FULLSCREEN_BOTH)
7314 {
7315 NSScreen *screen = [w screen];
7316
7317 #if defined (NS_IMPL_COCOA) && \
7318 MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7319 /* Hide ghost menu bar on secondary monitor? */
7320 if (! onFirstScreen)
7321 onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7322 #endif
7323 /* Hide dock and menubar if we are on the primary screen. */
7324 if (onFirstScreen)
7325 {
7326 #ifdef NS_IMPL_COCOA
7327 NSApplicationPresentationOptions options
7328 = NSApplicationPresentationAutoHideDock
7329 | NSApplicationPresentationAutoHideMenuBar;
7330
7331 [NSApp setPresentationOptions: options];
7332 #else
7333 [NSMenu setMenuBarVisible:NO];
7334 #endif
7335 }
7336
7337 fw = [[EmacsFSWindow alloc]
7338 initWithContentRect:[w contentRectForFrameRect:wr]
7339 styleMask:NSBorderlessWindowMask
7340 backing:NSBackingStoreBuffered
7341 defer:YES
7342 screen:screen];
7343
7344 [fw setContentView:[w contentView]];
7345 [fw setTitle:[w title]];
7346 [fw setDelegate:self];
7347 [fw setAcceptsMouseMovedEvents: YES];
7348 #if !defined (NS_IMPL_COCOA) || \
7349 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
7350 [fw useOptimizedDrawing: YES];
7351 #endif
7352 [fw setBackgroundColor: col];
7353 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7354 [fw setOpaque: NO];
7355
7356 f->border_width = 0;
7357 FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
7358 tobar_height = FRAME_TOOLBAR_HEIGHT (f);
7359 FRAME_TOOLBAR_HEIGHT (f) = 0;
7360
7361 nonfs_window = w;
7362
7363 [self windowWillEnterFullScreen];
7364 [fw makeKeyAndOrderFront:NSApp];
7365 [fw makeFirstResponder:self];
7366 [w orderOut:self];
7367 r = [fw frameRectForContentRect:[screen frame]];
7368 [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7369 [self windowDidEnterFullScreen];
7370 [fw display];
7371 }
7372 else
7373 {
7374 fw = w;
7375 w = nonfs_window;
7376 nonfs_window = nil;
7377
7378 if (onFirstScreen)
7379 {
7380 #ifdef NS_IMPL_COCOA
7381 [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7382 #else
7383 [NSMenu setMenuBarVisible:YES];
7384 #endif
7385 }
7386
7387 [w setContentView:[fw contentView]];
7388 [w setBackgroundColor: col];
7389 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7390 [w setOpaque: NO];
7391
7392 f->border_width = bwidth;
7393 FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
7394 if (FRAME_EXTERNAL_TOOL_BAR (f))
7395 FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
7396
7397 // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
7398
7399 [self windowWillExitFullScreen];
7400 [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7401 [fw close];
7402 [w makeKeyAndOrderFront:NSApp];
7403 [self windowDidExitFullScreen];
7404 [self updateFrameSize:YES];
7405 }
7406 }
7407
7408 - (void)handleFS
7409 {
7410 NSTRACE ("[EmacsView handleFS]");
7411
7412 if (fs_state != emacsframe->want_fullscreen)
7413 {
7414 if (fs_state == FULLSCREEN_BOTH)
7415 {
7416 NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7417 [self toggleFullScreen:self];
7418 }
7419
7420 switch (emacsframe->want_fullscreen)
7421 {
7422 case FULLSCREEN_BOTH:
7423 NSTRACE_MSG ("FULLSCREEN_BOTH");
7424 [self toggleFullScreen:self];
7425 break;
7426 case FULLSCREEN_WIDTH:
7427 NSTRACE_MSG ("FULLSCREEN_WIDTH");
7428 next_maximized = FULLSCREEN_WIDTH;
7429 if (fs_state != FULLSCREEN_BOTH)
7430 [[self window] performZoom:self];
7431 break;
7432 case FULLSCREEN_HEIGHT:
7433 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7434 next_maximized = FULLSCREEN_HEIGHT;
7435 if (fs_state != FULLSCREEN_BOTH)
7436 [[self window] performZoom:self];
7437 break;
7438 case FULLSCREEN_MAXIMIZED:
7439 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7440 next_maximized = FULLSCREEN_MAXIMIZED;
7441 if (fs_state != FULLSCREEN_BOTH)
7442 [[self window] performZoom:self];
7443 break;
7444 case FULLSCREEN_NONE:
7445 NSTRACE_MSG ("FULLSCREEN_NONE");
7446 if (fs_state != FULLSCREEN_BOTH)
7447 {
7448 next_maximized = FULLSCREEN_NONE;
7449 [[self window] performZoom:self];
7450 }
7451 break;
7452 }
7453
7454 emacsframe->want_fullscreen = FULLSCREEN_NONE;
7455 }
7456
7457 }
7458
7459 - (void) setFSValue: (int)value
7460 {
7461 NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
7462 NSTRACE_ARG_FSTYPE(value));
7463
7464 Lisp_Object lval = Qnil;
7465 switch (value)
7466 {
7467 case FULLSCREEN_BOTH:
7468 lval = Qfullboth;
7469 break;
7470 case FULLSCREEN_WIDTH:
7471 lval = Qfullwidth;
7472 break;
7473 case FULLSCREEN_HEIGHT:
7474 lval = Qfullheight;
7475 break;
7476 case FULLSCREEN_MAXIMIZED:
7477 lval = Qmaximized;
7478 break;
7479 }
7480 store_frame_param (emacsframe, Qfullscreen, lval);
7481 fs_state = value;
7482 }
7483
7484 - (void)mouseEntered: (NSEvent *)theEvent
7485 {
7486 NSTRACE ("[EmacsView mouseEntered:]");
7487 if (emacsframe)
7488 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7489 = EV_TIMESTAMP (theEvent);
7490 }
7491
7492
7493 - (void)mouseExited: (NSEvent *)theEvent
7494 {
7495 Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
7496
7497 NSTRACE ("[EmacsView mouseExited:]");
7498
7499 if (!hlinfo)
7500 return;
7501
7502 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7503 = EV_TIMESTAMP (theEvent);
7504
7505 if (emacsframe == hlinfo->mouse_face_mouse_frame)
7506 {
7507 clear_mouse_face (hlinfo);
7508 hlinfo->mouse_face_mouse_frame = 0;
7509 }
7510 }
7511
7512
7513 - menuDown: sender
7514 {
7515 NSTRACE ("[EmacsView menuDown:]");
7516 if (context_menu_value == -1)
7517 context_menu_value = [sender tag];
7518 else
7519 {
7520 NSInteger tag = [sender tag];
7521 find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
7522 emacsframe->menu_bar_vector,
7523 (void *)tag);
7524 }
7525
7526 ns_send_appdefined (-1);
7527 return self;
7528 }
7529
7530
7531 - (EmacsToolbar *)toolbar
7532 {
7533 return toolbar;
7534 }
7535
7536
7537 /* this gets called on toolbar button click */
7538 - toolbarClicked: (id)item
7539 {
7540 NSEvent *theEvent;
7541 int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
7542
7543 NSTRACE ("[EmacsView toolbarClicked:]");
7544
7545 if (!emacs_event)
7546 return self;
7547
7548 /* send first event (for some reason two needed) */
7549 theEvent = [[self window] currentEvent];
7550 emacs_event->kind = TOOL_BAR_EVENT;
7551 XSETFRAME (emacs_event->arg, emacsframe);
7552 EV_TRAILER (theEvent);
7553
7554 emacs_event->kind = TOOL_BAR_EVENT;
7555 /* XSETINT (emacs_event->code, 0); */
7556 emacs_event->arg = AREF (emacsframe->tool_bar_items,
7557 idx + TOOL_BAR_ITEM_KEY);
7558 emacs_event->modifiers = EV_MODIFIERS (theEvent);
7559 EV_TRAILER (theEvent);
7560 return self;
7561 }
7562
7563
7564 - toggleToolbar: (id)sender
7565 {
7566 NSTRACE ("[EmacsView toggleToolbar:]");
7567
7568 if (!emacs_event)
7569 return self;
7570
7571 emacs_event->kind = NS_NONKEY_EVENT;
7572 emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
7573 EV_TRAILER ((id)nil);
7574 return self;
7575 }
7576
7577
7578 - (void)drawRect: (NSRect)rect
7579 {
7580 int x = NSMinX (rect), y = NSMinY (rect);
7581 int width = NSWidth (rect), height = NSHeight (rect);
7582
7583 NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
7584 NSTRACE_ARG_RECT(rect));
7585
7586 if (!emacsframe || !emacsframe->output_data.ns)
7587 return;
7588
7589 ns_clear_frame_area (emacsframe, x, y, width, height);
7590 block_input ();
7591 expose_frame (emacsframe, x, y, width, height);
7592 unblock_input ();
7593
7594 /*
7595 drawRect: may be called (at least in OS X 10.5) for invisible
7596 views as well for some reason. Thus, do not infer visibility
7597 here.
7598
7599 emacsframe->async_visible = 1;
7600 emacsframe->async_iconified = 0;
7601 */
7602 }
7603
7604
7605 /* NSDraggingDestination protocol methods. Actually this is not really a
7606 protocol, but a category of Object. O well... */
7607
7608 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
7609 {
7610 NSTRACE ("[EmacsView draggingEntered:]");
7611 return NSDragOperationGeneric;
7612 }
7613
7614
7615 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
7616 {
7617 return YES;
7618 }
7619
7620
7621 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
7622 {
7623 id pb;
7624 int x, y;
7625 NSString *type;
7626 NSEvent *theEvent = [[self window] currentEvent];
7627 NSPoint position;
7628 NSDragOperation op = [sender draggingSourceOperationMask];
7629 int modifiers = 0;
7630
7631 NSTRACE ("[EmacsView performDragOperation:]");
7632
7633 if (!emacs_event)
7634 return NO;
7635
7636 position = [self convertPoint: [sender draggingLocation] fromView: nil];
7637 x = lrint (position.x); y = lrint (position.y);
7638
7639 pb = [sender draggingPasteboard];
7640 type = [pb availableTypeFromArray: ns_drag_types];
7641
7642 if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
7643 // URL drags contain all operations (0xf), don't allow all to be set.
7644 (op & 0xf) != 0xf)
7645 {
7646 if (op & NSDragOperationLink)
7647 modifiers |= NSControlKeyMask;
7648 if (op & NSDragOperationCopy)
7649 modifiers |= NSAlternateKeyMask;
7650 if (op & NSDragOperationGeneric)
7651 modifiers |= NSCommandKeyMask;
7652 }
7653
7654 modifiers = EV_MODIFIERS2 (modifiers);
7655 if (type == 0)
7656 {
7657 return NO;
7658 }
7659 else if ([type isEqualToString: NSFilenamesPboardType])
7660 {
7661 NSArray *files;
7662 NSEnumerator *fenum;
7663 NSString *file;
7664
7665 if (!(files = [pb propertyListForType: type]))
7666 return NO;
7667
7668 fenum = [files objectEnumerator];
7669 while ( (file = [fenum nextObject]) )
7670 {
7671 emacs_event->kind = DRAG_N_DROP_EVENT;
7672 XSETINT (emacs_event->x, x);
7673 XSETINT (emacs_event->y, y);
7674 ns_input_file = append2 (ns_input_file,
7675 build_string ([file UTF8String]));
7676 emacs_event->modifiers = modifiers;
7677 emacs_event->arg = list2 (Qfile, build_string ([file UTF8String]));
7678 EV_TRAILER (theEvent);
7679 }
7680 return YES;
7681 }
7682 else if ([type isEqualToString: NSURLPboardType])
7683 {
7684 NSURL *url = [NSURL URLFromPasteboard: pb];
7685 if (url == nil) return NO;
7686
7687 emacs_event->kind = DRAG_N_DROP_EVENT;
7688 XSETINT (emacs_event->x, x);
7689 XSETINT (emacs_event->y, y);
7690 emacs_event->modifiers = modifiers;
7691 emacs_event->arg = list2 (Qurl,
7692 build_string ([[url absoluteString]
7693 UTF8String]));
7694 EV_TRAILER (theEvent);
7695
7696 if ([url isFileURL] != NO)
7697 {
7698 NSString *file = [url path];
7699 ns_input_file = append2 (ns_input_file,
7700 build_string ([file UTF8String]));
7701 }
7702 return YES;
7703 }
7704 else if ([type isEqualToString: NSStringPboardType]
7705 || [type isEqualToString: NSTabularTextPboardType])
7706 {
7707 NSString *data;
7708
7709 if (! (data = [pb stringForType: type]))
7710 return NO;
7711
7712 emacs_event->kind = DRAG_N_DROP_EVENT;
7713 XSETINT (emacs_event->x, x);
7714 XSETINT (emacs_event->y, y);
7715 emacs_event->modifiers = modifiers;
7716 emacs_event->arg = list2 (Qnil, build_string ([data UTF8String]));
7717 EV_TRAILER (theEvent);
7718 return YES;
7719 }
7720 else
7721 {
7722 fprintf (stderr, "Invalid data type in dragging pasteboard");
7723 return NO;
7724 }
7725 }
7726
7727
7728 - (id) validRequestorForSendType: (NSString *)typeSent
7729 returnType: (NSString *)typeReturned
7730 {
7731 NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
7732 if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
7733 && typeReturned == nil)
7734 {
7735 if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
7736 return self;
7737 }
7738
7739 return [super validRequestorForSendType: typeSent
7740 returnType: typeReturned];
7741 }
7742
7743
7744 /* The next two methods are part of NSServicesRequests informal protocol,
7745 supposedly called when a services menu item is chosen from this app.
7746 But this should not happen because we override the services menu with our
7747 own entries which call ns-perform-service.
7748 Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
7749 So let's at least stub them out until further investigation can be done. */
7750
7751 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
7752 {
7753 /* we could call ns_string_from_pasteboard(pboard) here but then it should
7754 be written into the buffer in place of the existing selection..
7755 ordinary service calls go through functions defined in ns-win.el */
7756 return NO;
7757 }
7758
7759 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
7760 {
7761 NSArray *typesDeclared;
7762 Lisp_Object val;
7763
7764 NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
7765
7766 /* We only support NSStringPboardType */
7767 if ([types containsObject:NSStringPboardType] == NO) {
7768 return NO;
7769 }
7770
7771 val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7772 if (CONSP (val) && SYMBOLP (XCAR (val)))
7773 {
7774 val = XCDR (val);
7775 if (CONSP (val) && NILP (XCDR (val)))
7776 val = XCAR (val);
7777 }
7778 if (! STRINGP (val))
7779 return NO;
7780
7781 typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
7782 [pb declareTypes:typesDeclared owner:nil];
7783 ns_string_to_pasteboard (pb, val);
7784 return YES;
7785 }
7786
7787
7788 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
7789 (gives a miniaturized version of the window); currently we use the latter for
7790 frames whose active buffer doesn't correspond to any file
7791 (e.g., '*scratch*') */
7792 - setMiniwindowImage: (BOOL) setMini
7793 {
7794 id image = [[self window] miniwindowImage];
7795 NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
7796
7797 /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
7798 about "AppleDockIconEnabled" notwithstanding, however the set message
7799 below has its effect nonetheless. */
7800 if (image != emacsframe->output_data.ns->miniimage)
7801 {
7802 if (image && [image isKindOfClass: [EmacsImage class]])
7803 [image release];
7804 [[self window] setMiniwindowImage:
7805 setMini ? emacsframe->output_data.ns->miniimage : nil];
7806 }
7807
7808 return self;
7809 }
7810
7811
7812 - (void) setRows: (int) r andColumns: (int) c
7813 {
7814 NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
7815 rows = r;
7816 cols = c;
7817 }
7818
7819 - (int) fullscreenState
7820 {
7821 return fs_state;
7822 }
7823
7824 @end /* EmacsView */
7825
7826
7827
7828 /* ==========================================================================
7829
7830 EmacsWindow implementation
7831
7832 ========================================================================== */
7833
7834 @implementation EmacsWindow
7835
7836 #ifdef NS_IMPL_COCOA
7837 - (id)accessibilityAttributeValue:(NSString *)attribute
7838 {
7839 Lisp_Object str = Qnil;
7840 struct frame *f = SELECTED_FRAME ();
7841 struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
7842
7843 NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
7844
7845 if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
7846 return NSAccessibilityTextFieldRole;
7847
7848 if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
7849 && curbuf && ! NILP (BVAR (curbuf, mark_active)))
7850 {
7851 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7852 }
7853 else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
7854 {
7855 if (! NILP (BVAR (curbuf, mark_active)))
7856 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7857
7858 if (NILP (str))
7859 {
7860 ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
7861 ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
7862 ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
7863
7864 if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
7865 str = make_uninit_multibyte_string (range, byte_range);
7866 else
7867 str = make_uninit_string (range);
7868 /* To check: This returns emacs-utf-8, which is a superset of utf-8.
7869 Is this a problem? */
7870 memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
7871 }
7872 }
7873
7874
7875 if (! NILP (str))
7876 {
7877 if (CONSP (str) && SYMBOLP (XCAR (str)))
7878 {
7879 str = XCDR (str);
7880 if (CONSP (str) && NILP (XCDR (str)))
7881 str = XCAR (str);
7882 }
7883 if (STRINGP (str))
7884 {
7885 const char *utfStr = SSDATA (str);
7886 NSString *nsStr = [NSString stringWithUTF8String: utfStr];
7887 return nsStr;
7888 }
7889 }
7890
7891 return [super accessibilityAttributeValue:attribute];
7892 }
7893 #endif /* NS_IMPL_COCOA */
7894
7895 /* Constrain size and placement of a frame.
7896
7897 By returning the original "frameRect", the frame is not
7898 constrained. This can lead to unwanted situations where, for
7899 example, the menu bar covers the frame.
7900
7901 The default implementation (accessed using "super") constrains the
7902 frame to the visible area of SCREEN, minus the menu bar (if
7903 present) and the Dock. Note that default implementation also calls
7904 windowWillResize, with the frame it thinks should have. (This can
7905 make the frame exit maximized mode.)
7906
7907 Note that this should work in situations where multiple monitors
7908 are present. Common configurations are side-by-side monitors and a
7909 monitor on top of another (e.g. when a laptop is placed under a
7910 large screen). */
7911 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
7912 {
7913 NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
7914 NSTRACE_ARG_RECT (frameRect));
7915
7916 #ifdef NS_IMPL_COCOA
7917 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7918 // If separate spaces is on, it is like each screen is independent. There is
7919 // no spanning of frames across screens.
7920 if ([NSScreen screensHaveSeparateSpaces])
7921 {
7922 NSTRACE_MSG ("Screens have separate spaces");
7923 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
7924 NSTRACE_RETURN_RECT (frameRect);
7925 return frameRect;
7926 }
7927 #endif
7928 #endif
7929
7930 return constrain_frame_rect(frameRect,
7931 [(EmacsView *)[self delegate] isFullscreen]);
7932 }
7933
7934
7935 - (void)performZoom:(id)sender
7936 {
7937 NSTRACE ("[EmacsWindow performZoom:]");
7938
7939 return [super performZoom:sender];
7940 }
7941
7942 - (void)zoom:(id)sender
7943 {
7944 NSTRACE ("[EmacsWindow zoom:]");
7945
7946 ns_update_auto_hide_menu_bar();
7947
7948 // Below are three zoom implementations. In the final commit, the
7949 // idea is that the last should be included.
7950
7951 #if 0
7952 // Native zoom done using the standard zoom animation. Size of the
7953 // resulting frame reduced to accommodate the Dock and, if present,
7954 // the menu-bar.
7955 [super zoom:sender];
7956
7957 #elif 0
7958 // Native zoom done using the standard zoom animation, plus an
7959 // explicit resize to cover the full screen, except the menu-bar and
7960 // dock, if present.
7961 [super zoom:sender];
7962
7963 // After the native zoom, resize the resulting frame to fill the
7964 // entire screen, except the menu-bar.
7965 //
7966 // This works for all practical purposes. (The only minor oddity is
7967 // when transiting from full-height frame to a maximized, the
7968 // animation reduces the height of the frame slightly (to the 4
7969 // pixels needed to accommodate the Doc) before it snaps back into
7970 // full height. The user would need a very trained eye to spot
7971 // this.)
7972 NSScreen * screen = [self screen];
7973 if (screen != nil)
7974 {
7975 int fs_state = [(EmacsView *)[self delegate] fullscreenState];
7976
7977 NSTRACE_FSTYPE ("fullscreenState", fs_state);
7978
7979 NSRect sr = [screen frame];
7980 struct EmacsMargins margins
7981 = ns_screen_margins_ignoring_hidden_dock(screen);
7982
7983 NSRect wr = [self frame];
7984 NSTRACE_RECT ("Rect after zoom", wr);
7985
7986 NSRect newWr = wr;
7987
7988 if (fs_state == FULLSCREEN_MAXIMIZED
7989 || fs_state == FULLSCREEN_HEIGHT)
7990 {
7991 newWr.origin.y = sr.origin.y + margins.bottom;
7992 newWr.size.height = sr.size.height - margins.top - margins.bottom;
7993 }
7994
7995 if (fs_state == FULLSCREEN_MAXIMIZED
7996 || fs_state == FULLSCREEN_WIDTH)
7997 {
7998 newWr.origin.x = sr.origin.x + margins.left;
7999 newWr.size.width = sr.size.width - margins.right - margins.left;
8000 }
8001
8002 if (newWr.size.width != wr.size.width
8003 || newWr.size.height != wr.size.height
8004 || newWr.origin.x != wr.origin.x
8005 || newWr.origin.y != wr.origin.y)
8006 {
8007 NSTRACE_MSG ("New frame different");
8008 [self setFrame: newWr display: NO];
8009 }
8010 }
8011 #else
8012 // Non-native zoom which is done instantaneously. The resulting
8013 // frame covers the entire screen, except the menu-bar and dock, if
8014 // present.
8015 NSScreen * screen = [self screen];
8016 if (screen != nil)
8017 {
8018 NSRect sr = [screen frame];
8019 struct EmacsMargins margins
8020 = ns_screen_margins_ignoring_hidden_dock(screen);
8021
8022 sr.size.height -= (margins.top + margins.bottom);
8023 sr.size.width -= (margins.left + margins.right);
8024 sr.origin.x += margins.left;
8025 sr.origin.y += margins.bottom;
8026
8027 sr = [[self delegate] windowWillUseStandardFrame:self
8028 defaultFrame:sr];
8029 [self setFrame: sr display: NO];
8030 }
8031 #endif
8032 }
8033
8034 - (void)setFrame:(NSRect)windowFrame
8035 display:(BOOL)displayViews
8036 {
8037 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
8038 NSTRACE_ARG_RECT (windowFrame), displayViews);
8039
8040 [super setFrame:windowFrame display:displayViews];
8041 }
8042
8043 - (void)setFrame:(NSRect)windowFrame
8044 display:(BOOL)displayViews
8045 animate:(BOOL)performAnimation
8046 {
8047 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
8048 " display:%d performAnimation:%d]",
8049 NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
8050
8051 [super setFrame:windowFrame display:displayViews animate:performAnimation];
8052 }
8053
8054 - (void)setFrameTopLeftPoint:(NSPoint)point
8055 {
8056 NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
8057 NSTRACE_ARG_POINT (point));
8058
8059 [super setFrameTopLeftPoint:point];
8060 }
8061 @end /* EmacsWindow */
8062
8063
8064 @implementation EmacsFSWindow
8065
8066 - (BOOL)canBecomeKeyWindow
8067 {
8068 return YES;
8069 }
8070
8071 - (BOOL)canBecomeMainWindow
8072 {
8073 return YES;
8074 }
8075
8076 @end
8077
8078 /* ==========================================================================
8079
8080 EmacsScroller implementation
8081
8082 ========================================================================== */
8083
8084
8085 @implementation EmacsScroller
8086
8087 /* for repeat button push */
8088 #define SCROLL_BAR_FIRST_DELAY 0.5
8089 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
8090
8091 + (CGFloat) scrollerWidth
8092 {
8093 /* TODO: if we want to allow variable widths, this is the place to do it,
8094 however neither GNUstep nor Cocoa support it very well */
8095 CGFloat r;
8096 #if !defined (NS_IMPL_COCOA) || \
8097 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
8098 r = [NSScroller scrollerWidth];
8099 #else
8100 r = [NSScroller scrollerWidthForControlSize: NSRegularControlSize
8101 scrollerStyle: NSScrollerStyleLegacy];
8102 #endif
8103 return r;
8104 }
8105
8106
8107 - initFrame: (NSRect )r window: (Lisp_Object)nwin
8108 {
8109 NSTRACE ("[EmacsScroller initFrame: window:]");
8110
8111 r.size.width = [EmacsScroller scrollerWidth];
8112 [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
8113 [self setContinuous: YES];
8114 [self setEnabled: YES];
8115
8116 /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
8117 locked against the top and bottom edges, and right edge on OS X, where
8118 scrollers are on right. */
8119 #ifdef NS_IMPL_GNUSTEP
8120 [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
8121 #else
8122 [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
8123 #endif
8124
8125 window = XWINDOW (nwin);
8126 condemned = NO;
8127 pixel_height = NSHeight (r);
8128 if (pixel_height == 0) pixel_height = 1;
8129 min_portion = 20 / pixel_height;
8130
8131 frame = XFRAME (window->frame);
8132 if (FRAME_LIVE_P (frame))
8133 {
8134 int i;
8135 EmacsView *view = FRAME_NS_VIEW (frame);
8136 NSView *sview = [[view window] contentView];
8137 NSArray *subs = [sview subviews];
8138
8139 /* disable optimization stopping redraw of other scrollbars */
8140 view->scrollbarsNeedingUpdate = 0;
8141 for (i =[subs count]-1; i >= 0; i--)
8142 if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
8143 view->scrollbarsNeedingUpdate++;
8144 [sview addSubview: self];
8145 }
8146
8147 /* [self setFrame: r]; */
8148
8149 return self;
8150 }
8151
8152
8153 - (void)setFrame: (NSRect)newRect
8154 {
8155 NSTRACE ("[EmacsScroller setFrame:]");
8156
8157 /* block_input (); */
8158 pixel_height = NSHeight (newRect);
8159 if (pixel_height == 0) pixel_height = 1;
8160 min_portion = 20 / pixel_height;
8161 [super setFrame: newRect];
8162 /* unblock_input (); */
8163 }
8164
8165
8166 - (void)dealloc
8167 {
8168 NSTRACE ("[EmacsScroller dealloc]");
8169 if (window)
8170 wset_vertical_scroll_bar (window, Qnil);
8171 window = 0;
8172 [super dealloc];
8173 }
8174
8175
8176 - condemn
8177 {
8178 NSTRACE ("[EmacsScroller condemn]");
8179 condemned =YES;
8180 return self;
8181 }
8182
8183
8184 - reprieve
8185 {
8186 NSTRACE ("[EmacsScroller reprieve]");
8187 condemned =NO;
8188 return self;
8189 }
8190
8191
8192 -(bool)judge
8193 {
8194 NSTRACE ("[EmacsScroller judge]");
8195 bool ret = condemned;
8196 if (condemned)
8197 {
8198 EmacsView *view;
8199 block_input ();
8200 /* ensure other scrollbar updates after deletion */
8201 view = (EmacsView *)FRAME_NS_VIEW (frame);
8202 if (view != nil)
8203 view->scrollbarsNeedingUpdate++;
8204 if (window)
8205 wset_vertical_scroll_bar (window, Qnil);
8206 window = 0;
8207 [self removeFromSuperview];
8208 [self release];
8209 unblock_input ();
8210 }
8211 return ret;
8212 }
8213
8214
8215 - (void)resetCursorRects
8216 {
8217 NSRect visible = [self visibleRect];
8218 NSTRACE ("[EmacsScroller resetCursorRects]");
8219
8220 if (!NSIsEmptyRect (visible))
8221 [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
8222 [[NSCursor arrowCursor] setOnMouseEntered: YES];
8223 }
8224
8225
8226 - (int) checkSamePosition: (int) position portion: (int) portion
8227 whole: (int) whole
8228 {
8229 return em_position ==position && em_portion ==portion && em_whole ==whole
8230 && portion != whole; /* needed for resize empty buf */
8231 }
8232
8233
8234 - setPosition: (int)position portion: (int)portion whole: (int)whole
8235 {
8236 NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
8237
8238 em_position = position;
8239 em_portion = portion;
8240 em_whole = whole;
8241
8242 if (portion >= whole)
8243 {
8244 #ifdef NS_IMPL_COCOA
8245 [self setKnobProportion: 1.0];
8246 [self setDoubleValue: 1.0];
8247 #else
8248 [self setFloatValue: 0.0 knobProportion: 1.0];
8249 #endif
8250 }
8251 else
8252 {
8253 float pos;
8254 CGFloat por;
8255 portion = max ((float)whole*min_portion/pixel_height, portion);
8256 pos = (float)position / (whole - portion);
8257 por = (CGFloat)portion/whole;
8258 #ifdef NS_IMPL_COCOA
8259 [self setKnobProportion: por];
8260 [self setDoubleValue: pos];
8261 #else
8262 [self setFloatValue: pos knobProportion: por];
8263 #endif
8264 }
8265
8266 return self;
8267 }
8268
8269 /* set up emacs_event */
8270 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8271 {
8272 Lisp_Object win;
8273
8274 NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8275
8276 if (!emacs_event)
8277 return;
8278
8279 emacs_event->part = last_hit_part;
8280 emacs_event->code = 0;
8281 emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8282 XSETWINDOW (win, window);
8283 emacs_event->frame_or_window = win;
8284 emacs_event->timestamp = EV_TIMESTAMP (e);
8285 emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8286 emacs_event->arg = Qnil;
8287 XSETINT (emacs_event->x, loc * pixel_height);
8288 XSETINT (emacs_event->y, pixel_height-20);
8289
8290 if (q_event_ptr)
8291 {
8292 n_emacs_events_pending++;
8293 kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
8294 }
8295 else
8296 hold_event (emacs_event);
8297 EVENT_INIT (*emacs_event);
8298 ns_send_appdefined (-1);
8299 }
8300
8301
8302 /* called manually thru timer to implement repeated button action w/hold-down */
8303 - repeatScroll: (NSTimer *)scrollEntry
8304 {
8305 NSEvent *e = [[self window] currentEvent];
8306 NSPoint p = [[self window] mouseLocationOutsideOfEventStream];
8307 BOOL inKnob = [self testPart: p] == NSScrollerKnob;
8308
8309 NSTRACE ("[EmacsScroller repeatScroll:]");
8310
8311 /* clear timer if need be */
8312 if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
8313 {
8314 [scroll_repeat_entry invalidate];
8315 [scroll_repeat_entry release];
8316 scroll_repeat_entry = nil;
8317
8318 if (inKnob)
8319 return self;
8320
8321 scroll_repeat_entry
8322 = [[NSTimer scheduledTimerWithTimeInterval:
8323 SCROLL_BAR_CONTINUOUS_DELAY
8324 target: self
8325 selector: @selector (repeatScroll:)
8326 userInfo: 0
8327 repeats: YES]
8328 retain];
8329 }
8330
8331 [self sendScrollEventAtLoc: 0 fromEvent: e];
8332 return self;
8333 }
8334
8335
8336 /* Asynchronous mouse tracking for scroller. This allows us to dispatch
8337 mouseDragged events without going into a modal loop. */
8338 - (void)mouseDown: (NSEvent *)e
8339 {
8340 NSRect sr, kr;
8341 /* hitPart is only updated AFTER event is passed on */
8342 NSScrollerPart part = [self testPart: [e locationInWindow]];
8343 CGFloat inc = 0.0, loc, kloc, pos;
8344 int edge = 0;
8345
8346 NSTRACE ("[EmacsScroller mouseDown:]");
8347
8348 switch (part)
8349 {
8350 case NSScrollerDecrementPage:
8351 last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
8352 case NSScrollerIncrementPage:
8353 last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
8354 case NSScrollerDecrementLine:
8355 last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
8356 case NSScrollerIncrementLine:
8357 last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
8358 case NSScrollerKnob:
8359 last_hit_part = scroll_bar_handle; break;
8360 case NSScrollerKnobSlot: /* GNUstep-only */
8361 last_hit_part = scroll_bar_move_ratio; break;
8362 default: /* NSScrollerNoPart? */
8363 fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
8364 (long) part);
8365 return;
8366 }
8367
8368 if (inc != 0.0)
8369 {
8370 pos = 0; /* ignored */
8371
8372 /* set a timer to repeat, as we can't let superclass do this modally */
8373 scroll_repeat_entry
8374 = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
8375 target: self
8376 selector: @selector (repeatScroll:)
8377 userInfo: 0
8378 repeats: YES]
8379 retain];
8380 }
8381 else
8382 {
8383 /* handle, or on GNUstep possibly slot */
8384 NSEvent *fake_event;
8385
8386 /* compute float loc in slot and mouse offset on knob */
8387 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8388 toView: nil];
8389 loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
8390 if (loc <= 0.0)
8391 {
8392 loc = 0.0;
8393 edge = -1;
8394 }
8395 else if (loc >= NSHeight (sr))
8396 {
8397 loc = NSHeight (sr);
8398 edge = 1;
8399 }
8400
8401 if (edge)
8402 kloc = 0.5 * edge;
8403 else
8404 {
8405 kr = [self convertRect: [self rectForPart: NSScrollerKnob]
8406 toView: nil];
8407 kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
8408 }
8409 last_mouse_offset = kloc;
8410
8411 /* if knob, tell emacs a location offset by knob pos
8412 (to indicate top of handle) */
8413 if (part == NSScrollerKnob)
8414 pos = (loc - last_mouse_offset) / NSHeight (sr);
8415 else
8416 /* else this is a slot click on GNUstep: go straight there */
8417 pos = loc / NSHeight (sr);
8418
8419 /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
8420 fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
8421 location: [e locationInWindow]
8422 modifierFlags: [e modifierFlags]
8423 timestamp: [e timestamp]
8424 windowNumber: [e windowNumber]
8425 context: [e context]
8426 eventNumber: [e eventNumber]
8427 clickCount: [e clickCount]
8428 pressure: [e pressure]];
8429 [super mouseUp: fake_event];
8430 }
8431
8432 if (part != NSScrollerKnob)
8433 [self sendScrollEventAtLoc: pos fromEvent: e];
8434 }
8435
8436
8437 /* Called as we manually track scroller drags, rather than superclass. */
8438 - (void)mouseDragged: (NSEvent *)e
8439 {
8440 NSRect sr;
8441 double loc, pos;
8442
8443 NSTRACE ("[EmacsScroller mouseDragged:]");
8444
8445 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8446 toView: nil];
8447 loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
8448
8449 if (loc <= 0.0)
8450 {
8451 loc = 0.0;
8452 }
8453 else if (loc >= NSHeight (sr) + last_mouse_offset)
8454 {
8455 loc = NSHeight (sr) + last_mouse_offset;
8456 }
8457
8458 pos = (loc - last_mouse_offset) / NSHeight (sr);
8459 [self sendScrollEventAtLoc: pos fromEvent: e];
8460 }
8461
8462
8463 - (void)mouseUp: (NSEvent *)e
8464 {
8465 NSTRACE ("[EmacsScroller mouseUp:]");
8466
8467 if (scroll_repeat_entry)
8468 {
8469 [scroll_repeat_entry invalidate];
8470 [scroll_repeat_entry release];
8471 scroll_repeat_entry = nil;
8472 }
8473 last_hit_part = scroll_bar_above_handle;
8474 }
8475
8476
8477 /* treat scrollwheel events in the bar as though they were in the main window */
8478 - (void) scrollWheel: (NSEvent *)theEvent
8479 {
8480 NSTRACE ("[EmacsScroller scrollWheel:]");
8481
8482 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
8483 [view mouseDown: theEvent];
8484 }
8485
8486 @end /* EmacsScroller */
8487
8488
8489 #ifdef NS_IMPL_GNUSTEP
8490 /* Dummy class to get rid of startup warnings. */
8491 @implementation EmacsDocument
8492
8493 @end
8494 #endif
8495
8496
8497 /* ==========================================================================
8498
8499 Font-related functions; these used to be in nsfaces.m
8500
8501 ========================================================================== */
8502
8503
8504 Lisp_Object
8505 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
8506 {
8507 struct font *font = XFONT_OBJECT (font_object);
8508 EmacsView *view = FRAME_NS_VIEW (f);
8509 int font_ascent, font_descent;
8510
8511 if (fontset < 0)
8512 fontset = fontset_from_font (font_object);
8513 FRAME_FONTSET (f) = fontset;
8514
8515 if (FRAME_FONT (f) == font)
8516 /* This font is already set in frame F. There's nothing more to
8517 do. */
8518 return font_object;
8519
8520 FRAME_FONT (f) = font;
8521
8522 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
8523 FRAME_COLUMN_WIDTH (f) = font->average_width;
8524 get_font_ascent_descent (font, &font_ascent, &font_descent);
8525 FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
8526
8527 /* Compute the scroll bar width in character columns. */
8528 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
8529 {
8530 int wid = FRAME_COLUMN_WIDTH (f);
8531 FRAME_CONFIG_SCROLL_BAR_COLS (f)
8532 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
8533 }
8534 else
8535 {
8536 int wid = FRAME_COLUMN_WIDTH (f);
8537 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
8538 }
8539
8540 /* Compute the scroll bar height in character lines. */
8541 if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
8542 {
8543 int height = FRAME_LINE_HEIGHT (f);
8544 FRAME_CONFIG_SCROLL_BAR_LINES (f)
8545 = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
8546 }
8547 else
8548 {
8549 int height = FRAME_LINE_HEIGHT (f);
8550 FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
8551 }
8552
8553 /* Now make the frame display the given font. */
8554 if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
8555 adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
8556 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
8557 false, Qfont);
8558
8559 return font_object;
8560 }
8561
8562
8563 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
8564 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
8565 in 1.43. */
8566
8567 const char *
8568 ns_xlfd_to_fontname (const char *xlfd)
8569 /* --------------------------------------------------------------------------
8570 Convert an X font name (XLFD) to an NS font name.
8571 Only family is used.
8572 The string returned is temporarily allocated.
8573 -------------------------------------------------------------------------- */
8574 {
8575 char *name = xmalloc (180);
8576 int i, len;
8577 const char *ret;
8578
8579 if (!strncmp (xlfd, "--", 2))
8580 sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
8581 else
8582 sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
8583
8584 /* stopgap for malformed XLFD input */
8585 if (strlen (name) == 0)
8586 strcpy (name, "Monaco");
8587
8588 /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
8589 also uppercase after '-' or ' ' */
8590 name[0] = c_toupper (name[0]);
8591 for (len =strlen (name), i =0; i<len; i++)
8592 {
8593 if (name[i] == '$')
8594 {
8595 name[i] = '-';
8596 if (i+1<len)
8597 name[i+1] = c_toupper (name[i+1]);
8598 }
8599 else if (name[i] == '_')
8600 {
8601 name[i] = ' ';
8602 if (i+1<len)
8603 name[i+1] = c_toupper (name[i+1]);
8604 }
8605 }
8606 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name); */
8607 ret = [[NSString stringWithUTF8String: name] UTF8String];
8608 xfree (name);
8609 return ret;
8610 }
8611
8612
8613 void
8614 syms_of_nsterm (void)
8615 {
8616 NSTRACE ("syms_of_nsterm");
8617
8618 ns_antialias_threshold = 10.0;
8619
8620 /* from 23+ we need to tell emacs what modifiers there are.. */
8621 DEFSYM (Qmodifier_value, "modifier-value");
8622 DEFSYM (Qalt, "alt");
8623 DEFSYM (Qhyper, "hyper");
8624 DEFSYM (Qmeta, "meta");
8625 DEFSYM (Qsuper, "super");
8626 DEFSYM (Qcontrol, "control");
8627 DEFSYM (QUTF8_STRING, "UTF8_STRING");
8628
8629 DEFSYM (Qfile, "file");
8630 DEFSYM (Qurl, "url");
8631
8632 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
8633 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
8634 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
8635 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
8636 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
8637
8638 DEFVAR_LISP ("ns-input-file", ns_input_file,
8639 "The file specified in the last NS event.");
8640 ns_input_file =Qnil;
8641
8642 DEFVAR_LISP ("ns-working-text", ns_working_text,
8643 "String for visualizing working composition sequence.");
8644 ns_working_text =Qnil;
8645
8646 DEFVAR_LISP ("ns-input-font", ns_input_font,
8647 "The font specified in the last NS event.");
8648 ns_input_font =Qnil;
8649
8650 DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
8651 "The fontsize specified in the last NS event.");
8652 ns_input_fontsize =Qnil;
8653
8654 DEFVAR_LISP ("ns-input-line", ns_input_line,
8655 "The line specified in the last NS event.");
8656 ns_input_line =Qnil;
8657
8658 DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
8659 "The service name specified in the last NS event.");
8660 ns_input_spi_name =Qnil;
8661
8662 DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
8663 "The service argument specified in the last NS event.");
8664 ns_input_spi_arg =Qnil;
8665
8666 DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
8667 "This variable describes the behavior of the alternate or option key.\n\
8668 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8669 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8670 at all, allowing it to be used at a lower level for accented character entry.");
8671 ns_alternate_modifier = Qmeta;
8672
8673 DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
8674 "This variable describes the behavior of the right alternate or option key.\n\
8675 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8676 Set to left means be the same key as `ns-alternate-modifier'.\n\
8677 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8678 at all, allowing it to be used at a lower level for accented character entry.");
8679 ns_right_alternate_modifier = Qleft;
8680
8681 DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
8682 "This variable describes the behavior of the command key.\n\
8683 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
8684 ns_command_modifier = Qsuper;
8685
8686 DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
8687 "This variable describes the behavior of the right command key.\n\
8688 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8689 Set to left means be the same key as `ns-command-modifier'.\n\
8690 Set to none means that the command / option key is not interpreted by Emacs\n\
8691 at all, allowing it to be used at a lower level for accented character entry.");
8692 ns_right_command_modifier = Qleft;
8693
8694 DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
8695 "This variable describes the behavior of the control key.\n\
8696 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
8697 ns_control_modifier = Qcontrol;
8698
8699 DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
8700 "This variable describes the behavior of the right control key.\n\
8701 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8702 Set to left means be the same key as `ns-control-modifier'.\n\
8703 Set to none means that the control / option key is not interpreted by Emacs\n\
8704 at all, allowing it to be used at a lower level for accented character entry.");
8705 ns_right_control_modifier = Qleft;
8706
8707 DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
8708 "This variable describes the behavior of the function key (on laptops).\n\
8709 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8710 Set to none means that the function key is not interpreted by Emacs at all,\n\
8711 allowing it to be used at a lower level for accented character entry.");
8712 ns_function_modifier = Qnone;
8713
8714 DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
8715 "Non-nil (the default) means to render text antialiased.");
8716 ns_antialias_text = Qt;
8717
8718 DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
8719 "Whether to confirm application quit using dialog.");
8720 ns_confirm_quit = Qnil;
8721
8722 DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
8723 doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
8724 Only works on OSX 10.6 or later. */);
8725 ns_auto_hide_menu_bar = Qnil;
8726
8727 DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
8728 doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
8729 Nil means use fullscreen the old (< 10.7) way. The old way works better with
8730 multiple monitors, but lacks tool bar. This variable is ignored on OSX < 10.7.
8731 Default is t for OSX >= 10.7, nil otherwise. */);
8732 #ifdef HAVE_NATIVE_FS
8733 ns_use_native_fullscreen = YES;
8734 #else
8735 ns_use_native_fullscreen = NO;
8736 #endif
8737 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
8738
8739 DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
8740 doc: /*Non-nil means use animation on non-native fullscreen.
8741 For native fullscreen, this does nothing.
8742 Default is nil. */);
8743 ns_use_fullscreen_animation = NO;
8744
8745 DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
8746 doc: /*Non-nil means to use sRGB colorspace on OSX >= 10.7.
8747 Note that this does not apply to images.
8748 This variable is ignored on OSX < 10.7 and GNUstep. */);
8749 ns_use_srgb_colorspace = YES;
8750
8751 /* TODO: move to common code */
8752 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
8753 doc: /* Which toolkit scroll bars Emacs uses, if any.
8754 A value of nil means Emacs doesn't use toolkit scroll bars.
8755 With the X Window system, the value is a symbol describing the
8756 X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
8757 With MS Windows or Nextstep, the value is t. */);
8758 Vx_toolkit_scroll_bars = Qt;
8759
8760 DEFVAR_BOOL ("x-use-underline-position-properties",
8761 x_use_underline_position_properties,
8762 doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
8763 A value of nil means ignore them. If you encounter fonts with bogus
8764 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
8765 to 4.1, set this to nil. */);
8766 x_use_underline_position_properties = 0;
8767
8768 DEFVAR_BOOL ("x-underline-at-descent-line",
8769 x_underline_at_descent_line,
8770 doc: /* Non-nil means to draw the underline at the same place as the descent line.
8771 A value of nil means to draw the underline according to the value of the
8772 variable `x-use-underline-position-properties', which is usually at the
8773 baseline level. The default value is nil. */);
8774 x_underline_at_descent_line = 0;
8775
8776 /* Tell Emacs about this window system. */
8777 Fprovide (Qns, Qnil);
8778
8779 DEFSYM (Qcocoa, "cocoa");
8780 DEFSYM (Qgnustep, "gnustep");
8781
8782 #ifdef NS_IMPL_COCOA
8783 Fprovide (Qcocoa, Qnil);
8784 syms_of_macfont ();
8785 #else
8786 Fprovide (Qgnustep, Qnil);
8787 syms_of_nsfont ();
8788 #endif
8789
8790 }