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