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