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