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