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