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