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