merge trunk
[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 3915{
91e8418b
YM
3916 NSArray *screens = [NSScreen screens];
3917 NSEnumerator *enumerator = [screens objectEnumerator];
3918 NSScreen *screen;
3919 NSRect frame;
3920
3921 frame = NSZeroRect;
3922 while ((screen = [enumerator nextObject]) != nil)
3923 frame = NSUnionRect (frame, [screen frame]);
3924
3925 return NSHeight (frame);
1ee27840
CY
3926}
3927
3928int
3d608a86 3929x_display_pixel_width (struct ns_display_info *dpyinfo)
1ee27840 3930{
91e8418b
YM
3931 NSArray *screens = [NSScreen screens];
3932 NSEnumerator *enumerator = [screens objectEnumerator];
3933 NSScreen *screen;
3934 NSRect frame;
3935
3936 frame = NSZeroRect;
3937 while ((screen = [enumerator nextObject]) != nil)
3938 frame = NSUnionRect (frame, [screen frame]);
3939
3940 return NSWidth (frame);
1ee27840
CY
3941}
3942
3943
15034960 3944static Lisp_Object ns_string_to_lispmod (const char *s)
edfda783
AR
3945/* --------------------------------------------------------------------------
3946 Convert modifier name to lisp symbol
3947 -------------------------------------------------------------------------- */
3948{
0dc8cf50 3949 if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
edfda783 3950 return Qmeta;
0dc8cf50 3951 else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
edfda783 3952 return Qsuper;
0dc8cf50 3953 else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
edfda783 3954 return Qcontrol;
0dc8cf50 3955 else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
edfda783 3956 return Qalt;
0dc8cf50 3957 else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
edfda783 3958 return Qhyper;
0dc8cf50 3959 else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
edfda783
AR
3960 return Qnone;
3961 else
3962 return Qnil;
3963}
3964
3965
edfda783
AR
3966static void
3967ns_default (const char *parameter, Lisp_Object *result,
3968 Lisp_Object yesval, Lisp_Object noval,
3969 BOOL is_float, BOOL is_modstring)
3970/* --------------------------------------------------------------------------
3971 Check a parameter value in user's preferences
3972 -------------------------------------------------------------------------- */
3973{
f7dfe5d6 3974 const char *value = ns_get_defaults_value (parameter);
edfda783 3975
f7dfe5d6 3976 if (value)
edfda783
AR
3977 {
3978 double f;
3979 char *pos;
fee5959d 3980 if (c_strcasecmp (value, "YES") == 0)
edfda783 3981 *result = yesval;
fee5959d 3982 else if (c_strcasecmp (value, "NO") == 0)
edfda783
AR
3983 *result = noval;
3984 else if (is_float && (f = strtod (value, &pos), pos != value))
3985 *result = make_float (f);
3986 else if (is_modstring && value)
3987 *result = ns_string_to_lispmod (value);
3988 else fprintf (stderr,
3989 "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3990 }
3991}
3992
3993
0dc8cf50 3994static void
edfda783
AR
3995ns_initialize_display_info (struct ns_display_info *dpyinfo)
3996/* --------------------------------------------------------------------------
3997 Initialize global info and storage for display.
3998 -------------------------------------------------------------------------- */
3999{
4000 NSScreen *screen = [NSScreen mainScreen];
4001 NSWindowDepth depth = [screen depth];
bbf534ce 4002 Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
edfda783 4003
edfda783
AR
4004 dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4005 dpyinfo->resy = 72.27;
4006 dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4007 NSColorSpaceFromDepth (depth)]
4008 && ![NSCalibratedWhiteColorSpace isEqualToString:
4009 NSColorSpaceFromDepth (depth)];
4010 dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4011 dpyinfo->image_cache = make_image_cache ();
38182d90 4012 dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
edfda783
AR
4013 dpyinfo->color_table->colors = NULL;
4014 dpyinfo->root_window = 42; /* a placeholder.. */
4015
bbf534ce 4016 hlinfo->mouse_face_mouse_frame = NULL;
bbf534ce
EZ
4017 hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
4018 hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
4019 hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
4020 hlinfo->mouse_face_window = hlinfo->mouse_face_overlay = Qnil;
4021 hlinfo->mouse_face_hidden = 0;
edfda783 4022
bbf534ce
EZ
4023 hlinfo->mouse_face_mouse_x = hlinfo->mouse_face_mouse_y = 0;
4024 hlinfo->mouse_face_defer = 0;
edfda783 4025
9e50ff0c 4026 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
edfda783
AR
4027
4028 dpyinfo->n_fonts = 0;
4029 dpyinfo->smallest_font_height = 1;
4030 dpyinfo->smallest_char_width = 1;
4031}
4032
4033
3fe53a83 4034/* This and next define (many of the) public functions in this file. */
edfda783
AR
4035/* x_... are generic versions in xdisp.c that we, and other terms, get away
4036 with using despite presence in the "system dependent" redisplay
4037 interface. In addition, many of the ns_ methods have code that is
4038 shared with all terms, indicating need for further refactoring. */
4039extern frame_parm_handler ns_frame_parm_handlers[];
4040static struct redisplay_interface ns_redisplay_interface =
4041{
4042 ns_frame_parm_handlers,
3fe53a83
AR
4043 x_produce_glyphs,
4044 x_write_glyphs,
4045 x_insert_glyphs,
4046 x_clear_end_of_line,
4047 ns_scroll_run,
4048 ns_after_update_window_line,
4049 ns_update_window_begin,
4050 ns_update_window_end,
4051 x_cursor_to,
edfda783
AR
4052 ns_flush,
4053 0, /* flush_display_optional */
3fe53a83
AR
4054 x_clear_window_mouse_face,
4055 x_get_glyph_overhangs,
4056 x_fix_overlapping_area,
4057 ns_draw_fringe_bitmap,
df2142db 4058 0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
edfda783 4059 0, /* destroy_fringe_bitmap */
3fe53a83
AR
4060 ns_compute_glyph_string_overhangs,
4061 ns_draw_glyph_string, /* interface to nsfont.m */
4062 ns_define_frame_cursor,
4063 ns_clear_frame_area,
4064 ns_draw_window_cursor,
edfda783
AR
4065 ns_draw_vertical_window_border,
4066 ns_shift_glyphs_for_insert
4067};
4068
4069
4070static void
4071ns_delete_display (struct ns_display_info *dpyinfo)
4072{
df2142db 4073 /* TODO... */
edfda783
AR
4074}
4075
4076
4077/* This function is called when the last frame on a display is deleted. */
4078static void
4079ns_delete_terminal (struct terminal *terminal)
4080{
4081 struct ns_display_info *dpyinfo = terminal->display_info.ns;
edfda783 4082
e2749141 4083 /* Protect against recursive calls. delete_frame in
edfda783
AR
4084 delete_terminal calls us back when it deletes our last frame. */
4085 if (!terminal->name)
4086 return;
4087
4d7e6e51 4088 block_input ();
edfda783
AR
4089
4090 x_destroy_all_bitmaps (dpyinfo);
4091 ns_delete_display (dpyinfo);
4d7e6e51 4092 unblock_input ();
edfda783
AR
4093}
4094
4095
4096static struct terminal *
4097ns_create_terminal (struct ns_display_info *dpyinfo)
4098/* --------------------------------------------------------------------------
4099 Set up use of NS before we make the first connection.
4100 -------------------------------------------------------------------------- */
4101{
4102 struct terminal *terminal;
4103
4104 NSTRACE (ns_create_terminal);
4105
4106 terminal = create_terminal ();
4107
4108 terminal->type = output_ns;
4109 terminal->display_info.ns = dpyinfo;
4110 dpyinfo->terminal = terminal;
4111
4112 terminal->rif = &ns_redisplay_interface;
4113
4114 terminal->clear_frame_hook = ns_clear_frame;
3fe53a83
AR
4115 terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
4116 terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
edfda783
AR
4117 terminal->ring_bell_hook = ns_ring_bell;
4118 terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
4119 terminal->set_terminal_modes_hook = ns_set_terminal_modes;
4120 terminal->update_begin_hook = ns_update_begin;
4121 terminal->update_end_hook = ns_update_end;
3fe53a83 4122 terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
edfda783
AR
4123 terminal->read_socket_hook = ns_read_socket;
4124 terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4125 terminal->mouse_position_hook = ns_mouse_position;
4126 terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4127 terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4128
dd946752 4129 terminal->fullscreen_hook = ns_fullscreen_hook;
edfda783
AR
4130
4131 terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4132 terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4133 terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4134 terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4135
4136 terminal->delete_frame_hook = x_destroy_window;
4137 terminal->delete_terminal_hook = ns_delete_terminal;
4138
4139 terminal->scroll_region_ok = 1;
4140 terminal->char_ins_del_ok = 1;
4141 terminal->line_ins_del_ok = 1;
4142 terminal->fast_clear_end_of_line = 1;
4143 terminal->memory_below_frame = 0;
4144
4145 return terminal;
4146}
4147
4148
edfda783
AR
4149struct ns_display_info *
4150ns_term_init (Lisp_Object display_name)
4151/* --------------------------------------------------------------------------
4152 Start the Application and get things rolling.
4153 -------------------------------------------------------------------------- */
4154{
edfda783
AR
4155 struct terminal *terminal;
4156 struct ns_display_info *dpyinfo;
4157 static int ns_initialized = 0;
4158 Lisp_Object tmp;
4159
c077c059
JD
4160 if (ns_initialized) return x_display_list;
4161 ns_initialized = 1;
4162
edfda783
AR
4163 NSTRACE (ns_term_init);
4164
c077c059
JD
4165 [outerpool release];
4166 outerpool = [[NSAutoreleasePool alloc] init];
4167
edfda783
AR
4168 /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4169 /*GSDebugAllocationActive (YES); */
4d7e6e51 4170 block_input ();
edfda783 4171
c077c059
JD
4172 baud_rate = 38400;
4173 Fset_input_interrupt_mode (Qnil);
ddee6515 4174
c077c059
JD
4175 if (selfds[0] == -1)
4176 {
4177 if (pipe (selfds) == -1)
ddee6515 4178 {
c077c059
JD
4179 fprintf (stderr, "Failed to create pipe: %s\n",
4180 emacs_strerror (errno));
4181 emacs_abort ();
ddee6515 4182 }
c077c059
JD
4183
4184 fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4185 FD_ZERO (&select_readfds);
4186 FD_ZERO (&select_writefds);
4187 pthread_mutex_init (&select_mutex, NULL);
edfda783
AR
4188 }
4189
4190 ns_pending_files = [[NSMutableArray alloc] init];
4191 ns_pending_service_names = [[NSMutableArray alloc] init];
4192 ns_pending_service_args = [[NSMutableArray alloc] init];
4193
adff3182 4194/* Start app and create the main menu, window, view.
edfda783
AR
4195 Needs to be here because ns_initialize_display_info () uses AppKit classes.
4196 The view will then ask the NSApp to stop and return to Emacs. */
4197 [EmacsApp sharedApplication];
4198 if (NSApp == nil)
4199 return NULL;
4200 [NSApp setDelegate: NSApp];
4201
ddee6515
JD
4202 /* Start the select thread. */
4203 [NSThread detachNewThreadSelector:@selector (fd_handler:)
4204 toTarget:NSApp
4205 withObject:nil];
4206
edfda783
AR
4207 /* debugging: log all notifications */
4208 /* [[NSNotificationCenter defaultCenter] addObserver: NSApp
4209 selector: @selector (logNotification:)
4210 name: nil object: nil]; */
4211
38182d90 4212 dpyinfo = xzalloc (sizeof *dpyinfo);
edfda783
AR
4213
4214 ns_initialize_display_info (dpyinfo);
4215 terminal = ns_create_terminal (dpyinfo);
4216
38182d90 4217 terminal->kboard = xmalloc (sizeof *terminal->kboard);
edfda783 4218 init_kboard (terminal->kboard);
15dbb4d6 4219 kset_window_system (terminal->kboard, Qns);
edfda783
AR
4220 terminal->kboard->next_kboard = all_kboards;
4221 all_kboards = terminal->kboard;
4222 /* Don't let the initial kboard remain current longer than necessary.
4223 That would cause problems if a file loaded on startup tries to
4224 prompt in the mini-buffer. */
4225 if (current_kboard == initial_kboard)
4226 current_kboard = terminal->kboard;
4227 terminal->kboard->reference_count++;
4228
9e50ff0c
DN
4229 dpyinfo->next = x_display_list;
4230 x_display_list = dpyinfo;
edfda783
AR
4231
4232 /* Put it on ns_display_name_list */
4233 ns_display_name_list = Fcons (Fcons (display_name, Qnil),
4234 ns_display_name_list);
edfda783
AR
4235 dpyinfo->name_list_element = XCAR (ns_display_name_list);
4236
e99a530f 4237 terminal->name = xstrdup (SSDATA (display_name));
edfda783 4238
4d7e6e51 4239 unblock_input ();
edfda783 4240
9518c243 4241 if (!inhibit_x_resources)
3436b70c 4242 {
3436b70c
AR
4243 ns_default ("GSFontAntiAlias", &ns_antialias_text,
4244 Qt, Qnil, NO, NO);
4245 tmp = Qnil;
c6c62e78 4246 /* this is a standard variable */
3436b70c
AR
4247 ns_default ("AppleAntiAliasingThreshold", &tmp,
4248 make_float (10.0), make_float (6.0), YES, NO);
4249 ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
3436b70c
AR
4250 }
4251
c6c62e78
DR
4252 ns_selection_color = [[NSUserDefaults standardUserDefaults]
4253 stringForKey: @"AppleHighlightColor"];
4254 if (ns_selection_color == nil)
edfda783 4255 ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
2c6584e8 4256
edfda783 4257 {
7ded3383 4258 NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
edfda783
AR
4259
4260 if ( cl == nil )
4261 {
7ded3383 4262 Lisp_Object color_file, color_map, color;
7ded3383
AR
4263 unsigned long c;
4264 char *name;
4265
4266 color_file = Fexpand_file_name (build_string ("rgb.txt"),
4267 Fsymbol_value (intern ("data-directory")));
7ded3383
AR
4268
4269 color_map = Fx_load_color_file (color_file);
4270 if (NILP (color_map))
4271 fatal ("Could not read %s.\n", SDATA (color_file));
4272
4273 cl = [[NSColorList alloc] initWithName: @"Emacs"];
4274 for ( ; CONSP (color_map); color_map = XCDR (color_map))
edfda783 4275 {
7ded3383 4276 color = XCAR (color_map);
0dc8cf50 4277 name = SSDATA (XCAR (color));
7ded3383
AR
4278 c = XINT (XCDR (color));
4279 [cl setColor:
4280 [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4281 green: GREEN_FROM_ULONG (c) / 255.0
4282 blue: BLUE_FROM_ULONG (c) / 255.0
4283 alpha: 1.0]
4284 forKey: [NSString stringWithUTF8String: name]];
edfda783 4285 }
edfda783
AR
4286 [cl writeToFile: nil];
4287 }
4288 }
4289
4290 {
edfda783 4291#ifdef NS_IMPL_GNUSTEP
e99a530f 4292 Vwindow_system_version = build_string (gnustep_base_version);
edfda783
AR
4293#else
4294 /*PSnextrelease (128, c); */
e99a530f
PE
4295 char c[DBL_BUFSIZE_BOUND];
4296 int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4297 Vwindow_system_version = make_unibyte_string (c, len);
edfda783 4298#endif
edfda783
AR
4299 }
4300
4301 delete_keyboard_wait_descriptor (0);
4302
f27a64a9
AR
4303 ns_app_name = [[NSProcessInfo processInfo] processName];
4304
edfda783
AR
4305/* Set up OS X app menu */
4306#ifdef NS_IMPL_COCOA
4307 {
4308 NSMenu *appMenu;
15034960 4309 NSMenuItem *item;
edfda783
AR
4310 /* set up the application menu */
4311 svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4312 [svcsMenu setAutoenablesItems: NO];
4313 appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4314 [appMenu setAutoenablesItems: NO];
4315 mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4e622592 4316 dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
edfda783
AR
4317
4318 [appMenu insertItemWithTitle: @"About Emacs"
4319 action: @selector (orderFrontStandardAboutPanel:)
4320 keyEquivalent: @""
4321 atIndex: 0];
4322 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4323 [appMenu insertItemWithTitle: @"Preferences..."
4324 action: @selector (showPreferencesWindow:)
4325 keyEquivalent: @","
4326 atIndex: 2];
4327 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4328 item = [appMenu insertItemWithTitle: @"Services"
4329 action: @selector (menuDown:)
4330 keyEquivalent: @""
4331 atIndex: 4];
4332 [appMenu setSubmenu: svcsMenu forItem: item];
edfda783
AR
4333 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4334 [appMenu insertItemWithTitle: @"Hide Emacs"
4335 action: @selector (hide:)
4336 keyEquivalent: @"h"
4337 atIndex: 6];
4338 item = [appMenu insertItemWithTitle: @"Hide Others"
4339 action: @selector (hideOtherApplications:)
4340 keyEquivalent: @"h"
4341 atIndex: 7];
4342 [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4343 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4344 [appMenu insertItemWithTitle: @"Quit Emacs"
4345 action: @selector (terminate:)
4346 keyEquivalent: @"q"
4347 atIndex: 9];
4348
2c6584e8 4349 item = [mainMenu insertItemWithTitle: ns_app_name
edfda783
AR
4350 action: @selector (menuDown:)
4351 keyEquivalent: @""
4352 atIndex: 0];
4353 [mainMenu setSubmenu: appMenu forItem: item];
4e622592
AR
4354 [dockMenu insertItemWithTitle: @"New Frame"
4355 action: @selector (newFrame:)
4356 keyEquivalent: @""
4357 atIndex: 0];
edfda783
AR
4358
4359 [NSApp setMainMenu: mainMenu];
4360 [NSApp setAppleMenu: appMenu];
4361 [NSApp setServicesMenu: svcsMenu];
4362 /* Needed at least on Cocoa, to get dock menu to show windows */
4363 [NSApp setWindowsMenu: [[NSMenu alloc] init]];
5fecd5fc
JD
4364
4365 [[NSNotificationCenter defaultCenter]
4366 addObserver: mainMenu
4367 selector: @selector (trackingNotification:)
4368 name: NSMenuDidBeginTrackingNotification object: mainMenu];
4369 [[NSNotificationCenter defaultCenter]
4370 addObserver: mainMenu
4371 selector: @selector (trackingNotification:)
4372 name: NSMenuDidEndTrackingNotification object: mainMenu];
edfda783
AR
4373 }
4374#endif /* MAC OS X menu setup */
4375
c077c059
JD
4376 /* Register our external input/output types, used for determining
4377 applicable services and also drag/drop eligibility. */
4378 ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4379 ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4380 retain];
4381 ns_drag_types = [[NSArray arrayWithObjects:
4382 NSStringPboardType,
4383 NSTabularTextPboardType,
4384 NSFilenamesPboardType,
4385 NSURLPboardType,
4386 NSColorPboardType,
4387 NSFontPboardType, nil] retain];
4388
04fafa46
JD
4389 /* If fullscreen is in init/default-frame-alist, focus isn't set
4390 right for fullscreen windows, so set this. */
4391 [NSApp activateIgnoringOtherApps:YES];
f75beb47 4392
edfda783 4393 [NSApp run];
adff3182 4394 ns_do_open_file = YES;
edfda783
AR
4395 return dpyinfo;
4396}
4397
4398
edfda783
AR
4399void
4400ns_term_shutdown (int sig)
4401{
5ba6571d
WX
4402 [[NSUserDefaults standardUserDefaults] synchronize];
4403
edfda783
AR
4404 /* code not reached in emacs.c after this is called by shut_down_emacs: */
4405 if (STRINGP (Vauto_save_list_file_name))
0dc8cf50 4406 unlink (SSDATA (Vauto_save_list_file_name));
edfda783 4407
a9b4df69
AR
4408 if (sig == 0 || sig == SIGTERM)
4409 {
a9b4df69
AR
4410 [NSApp terminate: NSApp];
4411 }
4412 else // force a stack trace to happen
4413 {
1088b922 4414 emacs_abort ();
a9b4df69 4415 }
edfda783
AR
4416}
4417
4418
edfda783
AR
4419/* ==========================================================================
4420
4421 EmacsApp implementation
4422
4423 ========================================================================== */
4424
4425
4426@implementation EmacsApp
4427
4428- (void)logNotification: (NSNotification *)notification
4429{
4430 const char *name = [[notification name] UTF8String];
4431 if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4432 && !strstr (name, "WindowNumber"))
4433 NSLog (@"notification: '%@'", [notification name]);
4434}
4435
4436
4437- (void)sendEvent: (NSEvent *)theEvent
4438/* --------------------------------------------------------------------------
3175b12a
AR
4439 Called when NSApp is running for each event received. Used to stop
4440 the loop when we choose, since there's no way to just run one iteration.
edfda783
AR
4441 -------------------------------------------------------------------------- */
4442{
4443 int type = [theEvent type];
4444 NSWindow *window = [theEvent window];
4445/* NSTRACE (sendEvent); */
8612b71a 4446/*fprintf (stderr, "received event of type %d\t%d\n", type);*/
edfda783 4447
08e3161a
JD
4448#ifdef NS_IMPL_COCOA
4449 if (type == NSApplicationDefined
4450 && [theEvent data2] == NSAPP_DATA2_RUNASSCRIPT)
4451 {
4452 ns_run_ascript ();
4453 [self stop: self];
4454 return;
4455 }
4456#endif
4457
edfda783
AR
4458 if (type == NSCursorUpdate && window == nil)
4459 {
4460 fprintf (stderr, "Dropping external cursor update event.\n");
4461 return;
4462 }
4463
edfda783
AR
4464 if (type == NSApplicationDefined)
4465 {
3175b12a
AR
4466 /* Events posted by ns_send_appdefined interrupt the run loop here.
4467 But, if a modal window is up, an appdefined can still come through,
4468 (e.g., from a makeKeyWindow event) but stopping self also stops the
4469 modal loop. Just defer it until later. */
4470 if ([NSApp modalWindow] == nil)
4471 {
64ccff5f 4472 last_appdefined_event_data = [theEvent data1];
3175b12a
AR
4473 [self stop: self];
4474 }
4475 else
4476 {
4477 send_appdefined = YES;
4478 }
edfda783
AR
4479 }
4480
4481 [super sendEvent: theEvent];
4482}
4483
4484
4485- (void)showPreferencesWindow: (id)sender
4486{
c6c62e78
DR
4487 struct frame *emacsframe = SELECTED_FRAME ();
4488 NSEvent *theEvent = [NSApp currentEvent];
4489
4490 if (!emacs_event)
4491 return;
4492 emacs_event->kind = NS_NONKEY_EVENT;
4493 emacs_event->code = KEY_NS_SHOW_PREFS;
4494 emacs_event->modifiers = 0;
4495 EV_TRAILER (theEvent);
edfda783
AR
4496}
4497
4498
4e622592
AR
4499- (void)newFrame: (id)sender
4500{
4501 struct frame *emacsframe = SELECTED_FRAME ();
4502 NSEvent *theEvent = [NSApp currentEvent];
4503
4504 if (!emacs_event)
4505 return;
a9f58614 4506 emacs_event->kind = NS_NONKEY_EVENT;
4e622592
AR
4507 emacs_event->code = KEY_NS_NEW_FRAME;
4508 emacs_event->modifiers = 0;
4509 EV_TRAILER (theEvent);
4510}
4511
4512
15034960
AR
4513/* Open a file (used by below, after going into queue read by ns_read_socket) */
4514- (BOOL) openFile: (NSString *)fileName
4515{
4516 struct frame *emacsframe = SELECTED_FRAME ();
4517 NSEvent *theEvent = [NSApp currentEvent];
4518
4519 if (!emacs_event)
4520 return NO;
4521
a9f58614 4522 emacs_event->kind = NS_NONKEY_EVENT;
15034960
AR
4523 emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4524 ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4525 ns_input_line = Qnil; /* can be start or cons start,end */
4526 emacs_event->modifiers =0;
4527 EV_TRAILER (theEvent);
4528
4529 return YES;
4530}
4531
4532
edfda783
AR
4533/* **************************************************************************
4534
4535 EmacsApp delegate implementation
4536
4537 ************************************************************************** */
4538
4539- (void)applicationDidFinishLaunching: (NSNotification *)notification
4540/* --------------------------------------------------------------------------
4541 When application is loaded, terminate event loop in ns_term_init
4542 -------------------------------------------------------------------------- */
4543{
4544 NSTRACE (applicationDidFinishLaunching);
4545 [NSApp setServicesProvider: NSApp];
4546 ns_send_appdefined (-2);
4547}
e2749141 4548
edfda783 4549
c6c62e78 4550/* Termination sequences:
8612b71a
AR
4551 C-x C-c:
4552 Cmd-Q:
4553 MenuBar | File | Exit:
8612b71a 4554 Select Quit from App menubar:
c6c62e78
DR
4555 -terminate
4556 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4557 ns_term_shutdown()
8612b71a
AR
4558
4559 Select Quit from Dock menu:
4560 Logout attempt:
c6c62e78 4561 -appShouldTerminate
8612b71a
AR
4562 Cancel -> Nothing else
4563 Accept ->
2c6584e8 4564
c6c62e78
DR
4565 -terminate
4566 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4567 ns_term_shutdown()
4568
8612b71a
AR
4569*/
4570
edfda783
AR
4571- (void) terminate: (id)sender
4572{
c6c62e78 4573 struct frame *emacsframe = SELECTED_FRAME ();
2c6584e8 4574
c6c62e78
DR
4575 if (!emacs_event)
4576 return;
2c6584e8 4577
c6c62e78
DR
4578 emacs_event->kind = NS_NONKEY_EVENT;
4579 emacs_event->code = KEY_NS_POWER_OFF;
4580 emacs_event->arg = Qt; /* mark as non-key event */
4581 EV_TRAILER ((id)nil);
edfda783
AR
4582}
4583
4584
4585- (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4586{
8612b71a
AR
4587 int ret;
4588
c6c62e78 4589 if (NILP (ns_confirm_quit)) // || ns_shutdown_properly --> TO DO
edfda783
AR
4590 return NSTerminateNow;
4591
f27a64a9 4592 ret = NSRunAlertPanel(ns_app_name,
79e721e0 4593 @"Exit requested. Would you like to Save Buffers and Exit, or Cancel the request?",
8612b71a
AR
4594 @"Save Buffers and Exit", @"Cancel", nil);
4595
4596 if (ret == NSAlertDefaultReturn)
8612b71a 4597 return NSTerminateNow;
8612b71a 4598 else if (ret == NSAlertAlternateReturn)
8612b71a 4599 return NSTerminateCancel;
3175b12a 4600 return NSTerminateNow; /* just in case */
edfda783
AR
4601}
4602
3d29b2ce
JD
4603static int
4604not_in_argv (NSString *arg)
4605{
4606 int k;
4607 const char *a = [arg UTF8String];
4608 for (k = 1; k < initial_argc; ++k)
4609 if (strcmp (a, initial_argv[k]) == 0) return 0;
4610 return 1;
4611}
edfda783 4612
edfda783
AR
4613/* Notification from the Workspace to open a file */
4614- (BOOL)application: sender openFile: (NSString *)file
4615{
3d29b2ce 4616 if (ns_do_open_file || not_in_argv (file))
adff3182 4617 [ns_pending_files addObject: file];
edfda783
AR
4618 return YES;
4619}
4620
4621
4622/* Open a file as a temporary file */
4623- (BOOL)application: sender openTempFile: (NSString *)file
4624{
3d29b2ce 4625 if (ns_do_open_file || not_in_argv (file))
adff3182 4626 [ns_pending_files addObject: file];
edfda783
AR
4627 return YES;
4628}
4629
4630
4631/* Notification from the Workspace to open a file noninteractively (?) */
4632- (BOOL)application: sender openFileWithoutUI: (NSString *)file
4633{
3d29b2ce 4634 if (ns_do_open_file || not_in_argv (file))
adff3182 4635 [ns_pending_files addObject: file];
edfda783
AR
4636 return YES;
4637}
4638
edfda783
AR
4639/* Notification from the Workspace to open multiple files */
4640- (void)application: sender openFiles: (NSArray *)fileList
4641{
3d29b2ce
JD
4642 NSEnumerator *files = [fileList objectEnumerator];
4643 NSString *file;
4644 /* Don't open files from the command line unconditionally,
4645 Cocoa parses the command line wrong, --option value tries to open value
4646 if --option is the last option. */
1088b922 4647 while ((file = [files nextObject]) != nil)
3d29b2ce
JD
4648 if (ns_do_open_file || not_in_argv (file))
4649 [ns_pending_files addObject: file];
1088b922 4650
15034960 4651 [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
98a2166a 4652
edfda783
AR
4653}
4654
4e622592
AR
4655
4656/* Handle dock menu requests. */
4657- (NSMenu *)applicationDockMenu: (NSApplication *) sender
4658{
4659 return dockMenu;
4660}
4661
4662
df2142db 4663/* TODO: these may help w/IO switching btwn terminal and NSApp */
a3b53a85
AR
4664- (void)applicationWillBecomeActive: (NSNotification *)notification
4665{
4666 //ns_app_active=YES;
4667}
edfda783
AR
4668- (void)applicationDidBecomeActive: (NSNotification *)notification
4669{
f0a1382a
JD
4670 NSTRACE (applicationDidBecomeActive);
4671
a3b53a85 4672 //ns_app_active=YES;
f0a1382a
JD
4673
4674 ns_update_auto_hide_menu_bar ();
da6062e6 4675 // No constraining takes place when the application is not active.
f0a1382a 4676 ns_constrain_all_frames ();
edfda783
AR
4677}
4678- (void)applicationDidResignActive: (NSNotification *)notification
4679{
a3b53a85 4680 //ns_app_active=NO;
edfda783
AR
4681 ns_send_appdefined (-1);
4682}
4683
4684
4685
4686/* ==========================================================================
4687
4688 EmacsApp aux handlers for managing event loop
4689
4690 ========================================================================== */
4691
4692
4693- (void)timeout_handler: (NSTimer *)timedEntry
4694/* --------------------------------------------------------------------------
4695 The timeout specified to ns_select has passed.
4696 -------------------------------------------------------------------------- */
4697{
4698 /*NSTRACE (timeout_handler); */
4699 ns_send_appdefined (-2);
4700}
4701
ddee6515 4702- (void)fd_handler:(id)unused
edfda783
AR
4703/* --------------------------------------------------------------------------
4704 Check data waiting on file descriptors and terminate if so
4705 -------------------------------------------------------------------------- */
4706{
4707 int result;
ddee6515
JD
4708 int waiting = 1, nfds;
4709 char c;
edfda783 4710
ddee6515
JD
4711 SELECT_TYPE readfds, writefds, *wfds;
4712 EMACS_TIME timeout, *tmo;
d18e2bb6 4713 NSAutoreleasePool *pool = nil;
edfda783 4714
ddee6515 4715 /* NSTRACE (fd_handler); */
edfda783 4716
1088b922 4717 for (;;)
edfda783 4718 {
d18e2bb6
JD
4719 [pool release];
4720 pool = [[NSAutoreleasePool alloc] init];
4721
ddee6515
JD
4722 if (waiting)
4723 {
4724 SELECT_TYPE fds;
a06ae17d 4725 FD_ZERO (&fds);
ddee6515
JD
4726 FD_SET (selfds[0], &fds);
4727 result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
a631d0e0
PE
4728 if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
4729 waiting = 0;
ddee6515
JD
4730 }
4731 else
4732 {
4733 pthread_mutex_lock (&select_mutex);
4734 nfds = select_nfds;
4735
4736 if (select_valid & SELECT_HAVE_READ)
4737 readfds = select_readfds;
4738 else
4739 FD_ZERO (&readfds);
4740
4741 if (select_valid & SELECT_HAVE_WRITE)
4742 {
4743 writefds = select_writefds;
4744 wfds = &writefds;
4745 }
4746 else
4747 wfds = NULL;
4748 if (select_valid & SELECT_HAVE_TMO)
4749 {
4750 timeout = select_timeout;
4751 tmo = &timeout;
4752 }
4753 else
4754 tmo = NULL;
4755
4756 pthread_mutex_unlock (&select_mutex);
4757
4758 FD_SET (selfds[0], &readfds);
4759 if (selfds[0] >= nfds) nfds = selfds[0]+1;
4760
4761 result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
4762
4763 if (result == 0)
4764 ns_send_appdefined (-2);
4765 else if (result > 0)
4766 {
4767 if (FD_ISSET (selfds[0], &readfds))
4768 {
a631d0e0
PE
4769 if (read (selfds[0], &c, 1) == 1 && c == 's')
4770 waiting = 1;
ddee6515
JD
4771 }
4772 else
4773 {
4774 pthread_mutex_lock (&select_mutex);
4775 if (select_valid & SELECT_HAVE_READ)
4776 select_readfds = readfds;
4777 if (select_valid & SELECT_HAVE_WRITE)
4778 select_writefds = writefds;
4779 if (select_valid & SELECT_HAVE_TMO)
4780 select_timeout = timeout;
4781 pthread_mutex_unlock (&select_mutex);
4782
4783 ns_send_appdefined (result);
4784 }
4785 }
4786 waiting = 1;
4787 }
edfda783
AR
4788 }
4789}
4790
4791
4792
4793/* ==========================================================================
4794
4795 Service provision
4796
4797 ========================================================================== */
4798
4799/* called from system: queue for next pass through event loop */
4800- (void)requestService: (NSPasteboard *)pboard
4801 userData: (NSString *)userData
4802 error: (NSString **)error
4803{
4804 [ns_pending_service_names addObject: userData];
4805 [ns_pending_service_args addObject: [NSString stringWithUTF8String:
0dc8cf50 4806 SSDATA (ns_string_from_pasteboard (pboard))]];
edfda783
AR
4807}
4808
4809
4810/* called from ns_read_socket to clear queue */
4811- (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4812{
4813 struct frame *emacsframe = SELECTED_FRAME ();
4814 NSEvent *theEvent = [NSApp currentEvent];
4815
4816 if (!emacs_event)
4817 return NO;
4818
a9f58614 4819 emacs_event->kind = NS_NONKEY_EVENT;
edfda783
AR
4820 emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4821 ns_input_spi_name = build_string ([name UTF8String]);
4822 ns_input_spi_arg = build_string ([arg UTF8String]);
4823 emacs_event->modifiers = EV_MODIFIERS (theEvent);
4824 EV_TRAILER (theEvent);
4825
4826 return YES;
4827}
4828
4829
4830@end /* EmacsApp */
4831
4832
4833
4834/* ==========================================================================
4835
4836 EmacsView implementation
4837
4838 ========================================================================== */
4839
4840
4841@implementation EmacsView
4842
4843/* needed to inform when window closed from LISP */
4844- (void) setWindowClosing: (BOOL)closing
4845{
4846 windowClosing = closing;
4847}
4848
4849
4850- (void)dealloc
4851{
4852 NSTRACE (EmacsView_dealloc);
4853 [toolbar release];
dd946752
JD
4854 if (fs_state == FULLSCREEN_BOTH)
4855 [nonfs_window release];
edfda783
AR
4856 [super dealloc];
4857}
4858
4859
4860/* called on font panel selection */
4861- (void)changeFont: (id)sender
4862{
4863 NSEvent *e =[[self window] currentEvent];
4864 struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4865 id newFont;
4866 float size;
4867
4868 NSTRACE (changeFont);
4869 if (!emacs_event)
4870 return;
4871
0dc8cf50
JD
4872 if ((newFont = [sender convertFont:
4873 ((struct nsfont_info *)face->font)->nsfont]))
edfda783 4874 {
c8c057de
AR
4875 SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4876
a9f58614 4877 emacs_event->kind = NS_NONKEY_EVENT;
edfda783
AR
4878 emacs_event->modifiers = 0;
4879 emacs_event->code = KEY_NS_CHANGE_FONT;
4880
4881 size = [newFont pointSize];
ed96cde8 4882 ns_input_fontsize = make_number (lrint (size));
edfda783
AR
4883 ns_input_font = build_string ([[newFont familyName] UTF8String]);
4884 EV_TRAILER (e);
4885 }
4886}
4887
4888
4889- (BOOL)acceptsFirstResponder
4890{
4891 NSTRACE (acceptsFirstResponder);
4892 return YES;
4893}
4894
4895
4896- (void)resetCursorRects
4897{
4898 NSRect visible = [self visibleRect];
4899 NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4900 NSTRACE (resetCursorRects);
4901
4902 if (currentCursor == nil)
4903 currentCursor = [NSCursor arrowCursor];
4904
4905 if (!NSIsEmptyRect (visible))
4906 [self addCursorRect: visible cursor: currentCursor];
4907 [currentCursor setOnMouseEntered: YES];
4908}
4909
4910
a9b4df69 4911
edfda783
AR
4912/*****************************************************************************/
4913/* Keyboard handling. */
4914#define NS_KEYLOG 0
4915
4916- (void)keyDown: (NSEvent *)theEvent
4917{
bbf534ce 4918 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
edfda783
AR
4919 int code;
4920 unsigned fnKeysym = 0;
edfda783 4921 static NSMutableArray *nsEvArray;
4393663b 4922#if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
edfda783 4923 static BOOL firstTime = YES;
4393663b 4924#endif
449ab399 4925 int left_is_none;
8f31e74b 4926 unsigned int flags = [theEvent modifierFlags];
edfda783
AR
4927
4928 NSTRACE (keyDown);
4929
4930 /* Rhapsody and OS X give up and down events for the arrow keys */
a9b4df69
AR
4931 if (ns_fake_keydown == YES)
4932 ns_fake_keydown = NO;
4933 else if ([theEvent type] != NSKeyDown)
edfda783
AR
4934 return;
4935
4936 if (!emacs_event)
4937 return;
4938
15891144 4939 if (![[self window] isKeyWindow]
25c5550f
DR
4940 && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4941 /* we must avoid an infinite loop here. */
4942 && (EmacsView *)[[theEvent window] delegate] != self)
edfda783 4943 {
e863926a
AR
4944 /* XXX: There is an occasional condition in which, when Emacs display
4945 updates a different frame from the current one, and temporarily
4946 selects it, then processes some interrupt-driven input
4947 (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4948 for some reason that window has its first responder set to the NSView
4949 most recently updated (I guess), which is not the correct one. */
15891144 4950 [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
edfda783
AR
4951 return;
4952 }
edfda783
AR
4953
4954 if (nsEvArray == nil)
4955 nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4956
4957 [NSCursor setHiddenUntilMouseMoves: YES];
4958
bbf534ce 4959 if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
edfda783 4960 {
bbf534ce
EZ
4961 clear_mouse_face (hlinfo);
4962 hlinfo->mouse_face_hidden = 1;
edfda783
AR
4963 }
4964
4965 if (!processingCompose)
4966 {
5d127af9
JD
4967 /* When using screen sharing, no left or right information is sent,
4968 so use Left key in those cases. */
4969 int is_left_key, is_right_key;
4970
edfda783
AR
4971 code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4972 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5d127af9 4973
edfda783 4974 /* (Carbon way: [theEvent keyCode]) */
2c6584e8 4975
edfda783 4976 /* is it a "function key"? */
8f31e74b 4977 fnKeysym = (code < 0x00ff && (flags&NSNumericPadKeyMask))
e770aad5 4978 ? ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask)
8f31e74b
MM
4979 : ns_convert_key (code);
4980
edfda783
AR
4981 if (fnKeysym)
4982 {
4983 /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4984 because Emacs treats Delete and KP-Delete same (in simple.el). */
4985 if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4986 code = 0xFF08; /* backspace */
4987 else
4988 code = fnKeysym;
4989 }
4990
4991 /* are there modifiers? */
4992 emacs_event->modifiers = 0;
edfda783
AR
4993
4994 if (flags & NSHelpKeyMask)
4995 emacs_event->modifiers |= hyper_modifier;
4996
4997 if (flags & NSShiftKeyMask)
4998 emacs_event->modifiers |= shift_modifier;
4999
5d127af9
JD
5000 is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5001 is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5002 || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
1088b922 5003
5d127af9 5004 if (is_right_key)
50795d1f
JD
5005 emacs_event->modifiers |= parse_solitary_modifier
5006 (EQ (ns_right_command_modifier, Qleft)
5007 ? ns_command_modifier
5008 : ns_right_command_modifier);
5009
5d127af9 5010 if (is_left_key)
edfda783 5011 {
50795d1f
JD
5012 emacs_event->modifiers |= parse_solitary_modifier
5013 (ns_command_modifier);
b7d1e144 5014
edfda783
AR
5015 /* if super (default), take input manager's word so things like
5016 dvorak / qwerty layout work */
5017 if (EQ (ns_command_modifier, Qsuper)
5018 && !fnKeysym
5019 && [[theEvent characters] length] != 0)
5020 {
df2142db 5021 /* XXX: the code we get will be unshifted, so if we have
edfda783
AR
5022 a shift modifier, must convert ourselves */
5023 if (!(flags & NSShiftKeyMask))
5024 code = [[theEvent characters] characterAtIndex: 0];
5025#if 0
5026 /* this is ugly and also requires linking w/Carbon framework
5027 (for LMGetKbdType) so for now leave this rare (?) case
5028 undealt with.. in future look into CGEvent methods */
5029 else
5030 {
5031 long smv = GetScriptManagerVariable (smKeyScript);
5032 Handle uchrHandle = GetResource
5033 ('uchr', GetScriptVariable (smv, smScriptKeys));
5034 UInt32 dummy = 0;
5035 UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5036 [[theEvent characters] characterAtIndex: 0],
5037 kUCKeyActionDisplay,
5038 (flags & ~NSCommandKeyMask) >> 8,
5039 LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5040 &dummy, 1, &dummy, &code);
5041 code &= 0xFF;
5042 }
5043#endif
5044 }
5045 }
5046
5d127af9
JD
5047 is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5048 is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5049 || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5050
5051 if (is_right_key)
50795d1f
JD
5052 emacs_event->modifiers |= parse_solitary_modifier
5053 (EQ (ns_right_control_modifier, Qleft)
5054 ? ns_control_modifier
5055 : ns_right_control_modifier);
5056
5d127af9 5057 if (is_left_key)
50795d1f
JD
5058 emacs_event->modifiers |= parse_solitary_modifier
5059 (ns_control_modifier);
edfda783
AR
5060
5061 if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
a9b4df69
AR
5062 emacs_event->modifiers |=
5063 parse_solitary_modifier (ns_function_modifier);
edfda783 5064
449ab399
JD
5065 left_is_none = NILP (ns_alternate_modifier)
5066 || EQ (ns_alternate_modifier, Qnone);
5067
5d127af9
JD
5068 is_right_key = (flags & NSRightAlternateKeyMask)
5069 == NSRightAlternateKeyMask;
5070 is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5071 || (! is_right_key
5072 && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5073
5074 if (is_right_key)
50795d1f
JD
5075 {
5076 if ((NILP (ns_right_alternate_modifier)
449ab399
JD
5077 || EQ (ns_right_alternate_modifier, Qnone)
5078 || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
50795d1f
JD
5079 && !fnKeysym)
5080 { /* accept pre-interp alt comb */
5081 if ([[theEvent characters] length] > 0)
5082 code = [[theEvent characters] characterAtIndex: 0];
5083 /*HACK: clear lone shift modifier to stop next if from firing */
5084 if (emacs_event->modifiers == shift_modifier)
5085 emacs_event->modifiers = 0;
5086 }
5087 else
5088 emacs_event->modifiers |= parse_solitary_modifier
5089 (EQ (ns_right_alternate_modifier, Qleft)
5090 ? ns_alternate_modifier
5091 : ns_right_alternate_modifier);
5092 }
5093
5d127af9 5094 if (is_left_key) /* default = meta */
edfda783 5095 {
449ab399 5096 if (left_is_none && !fnKeysym)
edfda783
AR
5097 { /* accept pre-interp alt comb */
5098 if ([[theEvent characters] length] > 0)
5099 code = [[theEvent characters] characterAtIndex: 0];
5100 /*HACK: clear lone shift modifier to stop next if from firing */
5101 if (emacs_event->modifiers == shift_modifier)
5102 emacs_event->modifiers = 0;
5103 }
5104 else
a9b4df69
AR
5105 emacs_event->modifiers |=
5106 parse_solitary_modifier (ns_alternate_modifier);
edfda783
AR
5107 }
5108
a9b4df69
AR
5109 if (NS_KEYLOG)
5110 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5111 code, fnKeysym, flags, emacs_event->modifiers);
edfda783
AR
5112
5113 /* if it was a function key or had modifiers, pass it directly to emacs */
5114 if (fnKeysym || (emacs_event->modifiers
bdaa0745 5115 && (emacs_event->modifiers != shift_modifier)
edfda783
AR
5116 && [[theEvent charactersIgnoringModifiers] length] > 0))
5117/*[[theEvent characters] length] */
5118 {
5119 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5120 if (code < 0x20)
5121 code |= (1<<28)|(3<<16);
5122 else if (code == 0x7f)
5123 code |= (1<<28)|(3<<16);
5124 else if (!fnKeysym)
5125 emacs_event->kind = code > 0xFF
5126 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5127
5128 emacs_event->code = code;
5129 EV_TRAILER (theEvent);
eac4d08f 5130 processingCompose = NO;
edfda783
AR
5131 return;
5132 }
5133 }
5134
1ef7689b 5135
4393663b 5136#if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
edfda783
AR
5137 /* if we get here we should send the key for input manager processing */
5138 if (firstTime && [[NSInputManager currentInputManager]
5139 wantsToDelayTextChangeNotifications] == NO)
5140 fprintf (stderr,
5141 "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
5142 firstTime = NO;
4393663b 5143#endif
edfda783 5144 if (NS_KEYLOG && !processingCompose)
a9b4df69 5145 fprintf (stderr, "keyDown: Begin compose sequence.\n");
edfda783
AR
5146
5147 processingCompose = YES;
5148 [nsEvArray addObject: theEvent];
5149 [self interpretKeyEvents: nsEvArray];
5150 [nsEvArray removeObject: theEvent];
5151}
5152
5153
a9b4df69
AR
5154#ifdef NS_IMPL_COCOA
5155/* Needed to pick up Ctrl-tab and possibly other events that OS X has
5156 decided not to send key-down for.
5157 See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5dd9a6f7 5158 This only applies on Tiger and earlier.
a9b4df69
AR
5159 If it matches one of these, send it on to keyDown. */
5160-(void)keyUp: (NSEvent *)theEvent
5161{
5162 int flags = [theEvent modifierFlags];
5163 int code = [theEvent keyCode];
5dd9a6f7
AR
5164 if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5165 code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
a9b4df69
AR
5166 {
5167 if (NS_KEYLOG)
5168 fprintf (stderr, "keyUp: passed test");
5169 ns_fake_keydown = YES;
5170 [self keyDown: theEvent];
5171 }
5172}
5173#endif
5174
5175
edfda783
AR
5176/* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5177
5178
8612b71a
AR
5179/* <NSTextInput>: called when done composing;
5180 NOTE: also called when we delete over working text, followed immed.
5181 by doCommandBySelector: deleteBackward: */
edfda783
AR
5182- (void)insertText: (id)aString
5183{
5184 int code;
5185 int len = [(NSString *)aString length];
5186 int i;
5187
a9b4df69
AR
5188 if (NS_KEYLOG)
5189 NSLog (@"insertText '%@'\tlen = %d", aString, len);
edfda783
AR
5190 processingCompose = NO;
5191
5192 if (!emacs_event)
5193 return;
5194
5195 /* first, clear any working text */
5196 if (workingText != nil)
5197 [self deleteWorkingText];
5198
5199 /* now insert the string as keystrokes */
5200 for (i =0; i<len; i++)
5201 {
5202 code = [aString characterAtIndex: i];
df2142db 5203 /* TODO: still need this? */
edfda783
AR
5204 if (code == 0x2DC)
5205 code = '~'; /* 0x7E */
4ce7a138
JD
5206 if (code != 32) /* Space */
5207 emacs_event->modifiers = 0;
facfbbbd
SM
5208 emacs_event->kind
5209 = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
edfda783
AR
5210 emacs_event->code = code;
5211 EV_TRAILER ((id)nil);
5212 }
5213}
5214
5215
5216/* <NSTextInput>: inserts display of composing characters */
5217- (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5218{
5219 NSString *str = [aString respondsToSelector: @selector (string)] ?
5220 [aString string] : aString;
5221 if (NS_KEYLOG)
5222 NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
5223 selRange.length, selRange.location);
5224
5225 if (workingText != nil)
5226 [self deleteWorkingText];
5227 if ([str length] == 0)
5228 return;
5229
5230 if (!emacs_event)
5231 return;
5232
5233 processingCompose = YES;
5234 workingText = [str copy];
5235 ns_working_text = build_string ([workingText UTF8String]);
5236
8612b71a
AR
5237 emacs_event->kind = NS_TEXT_EVENT;
5238 emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5239 EV_TRAILER ((id)nil);
edfda783
AR
5240}
5241
5242
5243/* delete display of composing characters [not in <NSTextInput>] */
5244- (void)deleteWorkingText
5245{
5246 if (workingText == nil)
5247 return;
5248 if (NS_KEYLOG)
8612b71a 5249 NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
edfda783
AR
5250 [workingText release];
5251 workingText = nil;
5252 processingCompose = NO;
5253
5254 if (!emacs_event)
5255 return;
5256
8612b71a
AR
5257 emacs_event->kind = NS_TEXT_EVENT;
5258 emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5259 EV_TRAILER ((id)nil);
5260}
edfda783
AR
5261
5262
5263- (BOOL)hasMarkedText
5264{
5265 return workingText != nil;
5266}
5267
8612b71a 5268
edfda783
AR
5269- (NSRange)markedRange
5270{
5271 NSRange rng = workingText != nil
5272 ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
a9b4df69
AR
5273 if (NS_KEYLOG)
5274 NSLog (@"markedRange request");
edfda783
AR
5275 return rng;
5276}
5277
8612b71a 5278
edfda783
AR
5279- (void)unmarkText
5280{
a9b4df69
AR
5281 if (NS_KEYLOG)
5282 NSLog (@"unmark (accept) text");
edfda783
AR
5283 [self deleteWorkingText];
5284 processingCompose = NO;
5285}
5286
8612b71a 5287
edfda783
AR
5288/* used to position char selection windows, etc. */
5289- (NSRect)firstRectForCharacterRange: (NSRange)theRange
5290{
5291 NSRect rect;
5292 NSPoint pt;
5293 struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
a9b4df69
AR
5294 if (NS_KEYLOG)
5295 NSLog (@"firstRectForCharRange request");
edfda783
AR
5296
5297 rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5298 rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5299 pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5300 pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5301 +FRAME_LINE_HEIGHT (emacsframe));
5302
5303 pt = [self convertPoint: pt toView: nil];
5304 pt = [[self window] convertBaseToScreen: pt];
5305 rect.origin = pt;
5306 return rect;
5307}
5308
8612b71a 5309
4b17afa7 5310- (NSInteger)conversationIdentifier
edfda783 5311{
4b17afa7 5312 return (NSInteger)self;
edfda783
AR
5313}
5314
edfda783
AR
5315
5316- (void)doCommandBySelector: (SEL)aSelector
5317{
a9b4df69
AR
5318 if (NS_KEYLOG)
5319 NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
edfda783 5320
eac4d08f 5321 processingCompose = NO;
edfda783
AR
5322 if (aSelector == @selector (deleteBackward:))
5323 {
5324 /* happens when user backspaces over an ongoing composition:
5325 throw a 'delete' into the event queue */
5326 if (!emacs_event)
5327 return;
5328 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5329 emacs_event->code = 0xFF08;
5330 EV_TRAILER ((id)nil);
5331 }
5332}
5333
5334- (NSArray *)validAttributesForMarkedText
5335{
5336 static NSArray *arr = nil;
5337 if (arr == nil) arr = [NSArray new];
5338 /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5339 return arr;
5340}
5341
5342- (NSRange)selectedRange
5343{
a9b4df69
AR
5344 if (NS_KEYLOG)
5345 NSLog (@"selectedRange request");
edfda783
AR
5346 return NSMakeRange (NSNotFound, 0);
5347}
5348
e7b90afd 5349- (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
edfda783 5350{
a9b4df69
AR
5351 if (NS_KEYLOG)
5352 NSLog (@"characterIndexForPoint request");
edfda783
AR
5353 return 0;
5354}
5355
5356- (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5357{
5358 static NSAttributedString *str = nil;
5359 if (str == nil) str = [NSAttributedString new];
a9b4df69
AR
5360 if (NS_KEYLOG)
5361 NSLog (@"attributedSubstringFromRange request");
edfda783
AR
5362 return str;
5363}
5364
5365/* End <NSTextInput> impl. */
5366/*****************************************************************************/
5367
5368
5369/* This is what happens when the user presses a mouse button. */
5370- (void)mouseDown: (NSEvent *)theEvent
5371{
5372 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
edfda783
AR
5373
5374 NSTRACE (mouseDown);
5375
5376 [self deleteWorkingText];
5377
5378 if (!emacs_event)
5379 return;
5380
5381 last_mouse_frame = emacsframe;
5382 /* appears to be needed to prevent spurious movement events generated on
5383 button clicks */
5384 last_mouse_frame->mouse_moved = 0;
5385
5386 if ([theEvent type] == NSScrollWheel)
5387 {
5388 float delta = [theEvent deltaY];
5389 /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5390 if (delta == 0)
5391 return;
5392 emacs_event->kind = WHEEL_EVENT;
5393 emacs_event->code = 0;
5394 emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5395 ((delta > 0) ? up_modifier : down_modifier);
5396 }
5397 else
5398 {
5399 emacs_event->kind = MOUSE_CLICK_EVENT;
5400 emacs_event->code = EV_BUTTON (theEvent);
5401 emacs_event->modifiers = EV_MODIFIERS (theEvent)
5402 | EV_UDMODIFIERS (theEvent);
5403 }
5404 XSETINT (emacs_event->x, lrint (p.x));
5405 XSETINT (emacs_event->y, lrint (p.y));
5406 EV_TRAILER (theEvent);
5407}
5408
5409
19454c0a 5410- (void)rightMouseDown: (NSEvent *)theEvent
edfda783 5411{
19454c0a 5412 NSTRACE (rightMouseDown);
edfda783
AR
5413 [self mouseDown: theEvent];
5414}
5415
5416
19454c0a 5417- (void)otherMouseDown: (NSEvent *)theEvent
edfda783 5418{
19454c0a
AR
5419 NSTRACE (otherMouseDown);
5420 [self mouseDown: theEvent];
5421}
5422
5423
5424- (void)mouseUp: (NSEvent *)theEvent
5425{
5426 NSTRACE (mouseUp);
edfda783
AR
5427 [self mouseDown: theEvent];
5428}
5429
5430
5431- (void)rightMouseUp: (NSEvent *)theEvent
5432{
5433 NSTRACE (rightMouseUp);
5434 [self mouseDown: theEvent];
5435}
5436
5437
19454c0a
AR
5438- (void)otherMouseUp: (NSEvent *)theEvent
5439{
5440 NSTRACE (otherMouseUp);
5441 [self mouseDown: theEvent];
5442}
5443
5444
edfda783
AR
5445- (void) scrollWheel: (NSEvent *)theEvent
5446{
5447 NSTRACE (scrollWheel);
5448 [self mouseDown: theEvent];
5449}
5450
5451
5452/* Tell emacs the mouse has moved. */
5453- (void)mouseMoved: (NSEvent *)e
5454{
bbf534ce 5455 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
edfda783
AR
5456 Lisp_Object frame;
5457
c8c057de 5458// NSTRACE (mouseMoved);
edfda783
AR
5459
5460 last_mouse_movement_time = EV_TIMESTAMP (e);
facfbbbd
SM
5461 last_mouse_motion_position
5462 = [self convertPoint: [e locationInWindow] fromView: nil];
edfda783
AR
5463
5464 /* update any mouse face */
bbf534ce 5465 if (hlinfo->mouse_face_hidden)
edfda783 5466 {
bbf534ce
EZ
5467 hlinfo->mouse_face_hidden = 0;
5468 clear_mouse_face (hlinfo);
edfda783
AR
5469 }
5470
5471 /* tooltip handling */
5472 previous_help_echo_string = help_echo_string;
5473 help_echo_string = Qnil;
5474
5475 if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
5476 last_mouse_motion_position.y))
5477 help_echo_string = previous_help_echo_string;
5478
5479 XSETFRAME (frame, emacsframe);
5480 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5481 {
5482 /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5483 (note_mouse_highlight), which is called through the
5484 note_mouse_movement () call above */
5485 gen_help_event (help_echo_string, frame, help_echo_window,
5486 help_echo_object, help_echo_pos);
5487 }
5488 else
5489 {
5490 help_echo_string = Qnil;
5491 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5492 }
5493
5494 if (emacsframe->mouse_moved && send_appdefined)
5495 ns_send_appdefined (-1);
5496}
5497
5498
5499- (void)mouseDragged: (NSEvent *)e
5500{
5501 NSTRACE (mouseDragged);
5502 [self mouseMoved: e];
5503}
5504
5505
5506- (void)rightMouseDragged: (NSEvent *)e
5507{
5508 NSTRACE (rightMouseDragged);
5509 [self mouseMoved: e];
5510}
5511
5512
19454c0a
AR
5513- (void)otherMouseDragged: (NSEvent *)e
5514{
5515 NSTRACE (otherMouseDragged);
5516 [self mouseMoved: e];
5517}
5518
5519
edfda783
AR
5520- (BOOL)windowShouldClose: (id)sender
5521{
5522 NSEvent *e =[[self window] currentEvent];
5523
5524 NSTRACE (windowShouldClose);
5525 windowClosing = YES;
edfda783
AR
5526 if (!emacs_event)
5527 return NO;
5528 emacs_event->kind = DELETE_WINDOW_EVENT;
5529 emacs_event->modifiers = 0;
5530 emacs_event->code = 0;
5531 EV_TRAILER (e);
5532 /* Don't close this window, let this be done from lisp code. */
5533 return NO;
5534}
5535
c4c9756b 5536- (void) updateFrameSize: (BOOL) delay;
aa7d57c5
JD
5537{
5538 NSWindow *window = [self window];
5539 NSRect wr = [window frame];
aa7d57c5 5540 int extra = 0;
6871e574
JD
5541 int gsextra = 0;
5542#ifdef NS_IMPL_GNUSTEP
5543 gsextra = 3;
aa7d57c5
JD
5544#endif
5545
5546 int oldc = cols, oldr = rows;
5547 int oldw = FRAME_PIXEL_WIDTH (emacsframe),
5548 oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5549 int neww, newh;
5550
6871e574 5551 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, wr.size.width + gsextra);
aa7d57c5
JD
5552
5553 if (cols < MINWIDTH)
5554 cols = MINWIDTH;
5555
6871e574
JD
5556 if (! [self isFullscreen])
5557 {
5558 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5559 + FRAME_TOOLBAR_HEIGHT (emacsframe) - gsextra;
5560 }
5561
5562 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, wr.size.height - extra);
aa7d57c5
JD
5563
5564 if (rows < MINHEIGHT)
5565 rows = MINHEIGHT;
5566
5567 neww = (int)wr.size.width - emacsframe->border_width;
6871e574 5568 newh = (int)wr.size.height - extra;
aa7d57c5
JD
5569
5570 if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5571 {
960ce480 5572 struct frame *f = emacsframe;
0b3b1d23 5573 NSView *view = FRAME_NS_VIEW (emacsframe);
960ce480
JD
5574 NSWindow *win = [view window];
5575 NSSize sz = [win resizeIncrements];
5576
aa7d57c5
JD
5577 FRAME_PIXEL_WIDTH (emacsframe) = neww;
5578 FRAME_PIXEL_HEIGHT (emacsframe) = newh;
c4c9756b 5579 change_frame_size (emacsframe, rows, cols, 0, delay, 0);
aa7d57c5
JD
5580 SET_FRAME_GARBAGED (emacsframe);
5581 cancel_mouse_face (emacsframe);
960ce480
JD
5582
5583 // Did resize increments change because of a font change?
5584 if (sz.width != FRAME_COLUMN_WIDTH (emacsframe) ||
5585 sz.height != FRAME_LINE_HEIGHT (emacsframe))
5586 {
5587 sz.width = FRAME_COLUMN_WIDTH (emacsframe);
5588 sz.height = FRAME_LINE_HEIGHT (emacsframe);
5589 [win setResizeIncrements: sz];
5590 }
5591
0b3b1d23 5592 [view setFrame: NSMakeRect (0, 0, neww, newh)];
dd946752 5593 [self windowDidMove:nil]; // Update top/left.
aa7d57c5
JD
5594 }
5595}
edfda783
AR
5596
5597- (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5598/* normalize frame to gridded text size */
5599{
6871e574
JD
5600 int extra = 0;
5601 int gsextra = 0;
5602#ifdef NS_IMPL_GNUSTEP
5603 gsextra = 3;
5604#endif
5605
edfda783
AR
5606 NSTRACE (windowWillResize);
5607/*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5608
dd946752
JD
5609 if (fs_state == FULLSCREEN_MAXIMIZED
5610 && (maximized_width != (int)frameSize.width
5611 || maximized_height != (int)frameSize.height))
5612 [self setFSValue: FULLSCREEN_NONE];
5613 else if (fs_state == FULLSCREEN_WIDTH
5614 && maximized_width != (int)frameSize.width)
5615 [self setFSValue: FULLSCREEN_NONE];
5616 else if (fs_state == FULLSCREEN_HEIGHT
5617 && maximized_height != (int)frameSize.height)
5618 [self setFSValue: FULLSCREEN_NONE];
5619 if (fs_state == FULLSCREEN_NONE)
5620 maximized_width = maximized_height = -1;
5621
edfda783 5622 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
6871e574 5623 frameSize.width + gsextra);
edfda783
AR
5624 if (cols < MINWIDTH)
5625 cols = MINWIDTH;
edfda783 5626
6871e574
JD
5627 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
5628 frameSize.height - extra);
edfda783
AR
5629 if (rows < MINHEIGHT)
5630 rows = MINHEIGHT;
edfda783
AR
5631#ifdef NS_IMPL_COCOA
5632 {
5633 /* this sets window title to have size in it; the wm does this under GS */
5634 NSRect r = [[self window] frame];
5635 if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5636 {
5637 if (old_title != 0)
5638 {
5639 xfree (old_title);
5640 old_title = 0;
5641 }
5642 }
5643 else
5644 {
5645 char *size_title;
5646 NSWindow *window = [self window];
5647 if (old_title == 0)
5648 {
5649 const char *t = [[[self window] title] UTF8String];
5650 char *pos = strstr (t, " — ");
5651 if (pos)
5652 *pos = '\0';
38182d90 5653 old_title = xstrdup (t);
edfda783
AR
5654 }
5655 size_title = xmalloc (strlen (old_title) + 40);
a66ff6d8 5656 esprintf (size_title, "%s — (%d x %d)", old_title, cols, rows);
edfda783
AR
5657 [window setTitle: [NSString stringWithUTF8String: size_title]];
5658 [window display];
5659 xfree (size_title);
5660 }
5661 }
5662#endif /* NS_IMPL_COCOA */
5663/*fprintf (stderr," ...size became %.0f x %.0f (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5664
5665 return frameSize;
5666}
5667
5668
5669- (void)windowDidResize: (NSNotification *)notification
5670{
6871e574
JD
5671 if (! [self fsIsNative])
5672 {
5673 NSWindow *theWindow = [notification object];
5674 /* We can get notification on the non-FS window when in
5675 fullscreen mode. */
5676 if ([self window] != theWindow) return;
5677 }
04fafa46 5678
0dc8cf50 5679#ifdef NS_IMPL_GNUSTEP
edfda783
AR
5680 NSWindow *theWindow = [notification object];
5681
04fafa46 5682 /* In GNUstep, at least currently, it's possible to get a didResize
edfda783
AR
5683 without getting a willResize.. therefore we need to act as if we got
5684 the willResize now */
5685 NSSize sz = [theWindow frame].size;
5686 sz = [self windowWillResize: theWindow toSize: sz];
5687#endif /* NS_IMPL_GNUSTEP */
5688
5689 NSTRACE (windowDidResize);
5690/*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5691
5692#ifdef NS_IMPL_COCOA
5693 if (old_title != 0)
5694 {
5695 xfree (old_title);
5696 old_title = 0;
5697 }
5698#endif /* NS_IMPL_COCOA */
5699
5700 if (cols > 0 && rows > 0)
9ceebf39 5701 {
3bc0a2f7 5702 [self updateFrameSize: YES];
9ceebf39 5703 }
edfda783
AR
5704
5705 ns_send_appdefined (-1);
edfda783
AR
5706}
5707
5708
5709- (void)windowDidBecomeKey: (NSNotification *)notification
c8c057de 5710/* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
edfda783 5711{
edfda783 5712 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
9e50ff0c 5713 struct frame *old_focus = dpyinfo->x_focus_frame;
edfda783
AR
5714
5715 NSTRACE (windowDidBecomeKey);
5716
5717 if (emacsframe != old_focus)
9e50ff0c 5718 dpyinfo->x_focus_frame = emacsframe;
81cfe31c 5719
edfda783
AR
5720 ns_frame_rehighlight (emacsframe);
5721
5722 if (emacs_event)
5723 {
5724 emacs_event->kind = FOCUS_IN_EVENT;
5725 EV_TRAILER ((id)nil);
5726 }
5727}
5728
5729
5730- (void)windowDidResignKey: (NSNotification *)notification
c8c057de 5731/* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
edfda783
AR
5732{
5733 struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5734 NSTRACE (windowDidResignKey);
5735
9e50ff0c
DN
5736 if (dpyinfo->x_focus_frame == emacsframe)
5737 dpyinfo->x_focus_frame = 0;
edfda783 5738
c8c057de
AR
5739 ns_frame_rehighlight (emacsframe);
5740
5741 /* FIXME: for some reason needed on second and subsequent clicks away
5742 from sole-frame Emacs to get hollow box to show */
5743 if (!windowClosing && [[self window] isVisible] == YES)
59bc82c0
SZ
5744 {
5745 x_update_cursor (emacsframe, 1);
5746 x_set_frame_alpha (emacsframe);
5747 }
edfda783
AR
5748
5749 if (emacs_event)
5750 {
5751 [self deleteWorkingText];
5752 emacs_event->kind = FOCUS_IN_EVENT;
5753 EV_TRAILER ((id)nil);
5754 }
5755}
5756
5757
5758- (void)windowWillMiniaturize: sender
5759{
5760 NSTRACE (windowWillMiniaturize);
5761}
5762
5763
5764- (BOOL)isFlipped
5765{
5766 return YES;
5767}
5768
5769
5770- (BOOL)isOpaque
5771{
5772 return NO;
5773}
5774
5775
5776- initFrameFromEmacs: (struct frame *)f
5777{
5778 NSRect r, wr;
5779 Lisp_Object tem;
5780 NSWindow *win;
5781 NSButton *toggleButton;
edfda783
AR
5782 NSSize sz;
5783 NSColor *col;
5784 NSString *name;
5785
5786 NSTRACE (initFrameFromEmacs);
5787
5788 windowClosing = NO;
5789 processingCompose = NO;
5790 scrollbarsNeedingUpdate = 0;
dd946752
JD
5791 fs_state = FULLSCREEN_NONE;
5792 fs_before_fs = next_maximized = -1;
6871e574
JD
5793#ifdef HAVE_NATIVE_FS
5794 fs_is_native = ns_use_native_fullscreen;
5795#else
5796 fs_is_native = NO;
5797#endif
dd946752
JD
5798 maximized_width = maximized_height = -1;
5799 nonfs_window = nil;
edfda783
AR
5800
5801/*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5802
e2f79c8d 5803 ns_userRect = NSMakeRect (0, 0, 0, 0);
edfda783
AR
5804 r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5805 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5806 [self initWithFrame: r];
6aba198c 5807 [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
edfda783
AR
5808
5809 FRAME_NS_VIEW (f) = self;
5810 emacsframe = f;
5811 old_title = 0;
5812
5813 win = [[EmacsWindow alloc]
5814 initWithContentRect: r
5815 styleMask: (NSResizableWindowMask |
a258d627
JD
5816#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5817 NSTitledWindowMask |
5818#endif
edfda783
AR
5819 NSMiniaturizableWindowMask |
5820 NSClosableWindowMask)
5821 backing: NSBackingStoreBuffered
5822 defer: YES];
5823
6871e574 5824#ifdef HAVE_NATIVE_FS
dd946752
JD
5825 [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
5826#endif
5827
edfda783 5828 wr = [win frame];
dd946752 5829 bwidth = f->border_width = wr.size.width - r.size.width;
04fafa46 5830 tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
edfda783
AR
5831
5832 [win setAcceptsMouseMovedEvents: YES];
5833 [win setDelegate: self];
5834 [win useOptimizedDrawing: YES];
5835
5836 sz.width = FRAME_COLUMN_WIDTH (f);
5837 sz.height = FRAME_LINE_HEIGHT (f);
5838 [win setResizeIncrements: sz];
5839
5840 [[win contentView] addSubview: self];
5841
5842 if (ns_drag_types)
5843 [self registerForDraggedTypes: ns_drag_types];
5844
e69b0960 5845 tem = f->name;
edfda783 5846 name = [NSString stringWithUTF8String:
0dc8cf50 5847 NILP (tem) ? "Emacs" : SSDATA (tem)];
edfda783
AR
5848 [win setTitle: name];
5849
5850 /* toolbar support */
5851 toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5852 [NSString stringWithFormat: @"Emacs Frame %d",
5853 ns_window_num]];
5854 [win setToolbar: toolbar];
5855 [toolbar setVisible: NO];
5856#ifdef NS_IMPL_COCOA
5857 toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5858 [toggleButton setTarget: self];
5859 [toggleButton setAction: @selector (toggleToolbar: )];
5860#endif
581a8100 5861 FRAME_TOOLBAR_HEIGHT (f) = 0;
edfda783 5862
e69b0960 5863 tem = f->icon_name;
edfda783
AR
5864 if (!NILP (tem))
5865 [win setMiniwindowTitle:
0dc8cf50 5866 [NSString stringWithUTF8String: SSDATA (tem)]];
edfda783
AR
5867
5868 {
5869 NSScreen *screen = [win screen];
5870
5871 if (screen != 0)
5872 [win setFrameTopLeftPoint: NSMakePoint
5873 (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5874 IN_BOUND (-SCREENMAX,
5875 [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5876 }
5877
5878 [win makeFirstResponder: self];
5879
5880 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5881 (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5882 [win setBackgroundColor: col];
5883 if ([col alphaComponent] != 1.0)
5884 [win setOpaque: NO];
5885
5886 [self allocateGState];
5887
699c10bd 5888 [NSApp registerServicesMenuSendTypes: ns_send_types
3fe4b549 5889 returnTypes: nil];
699c10bd 5890
edfda783
AR
5891 ns_window_num++;
5892 return self;
5893}
5894
5895
5896- (void)windowDidMove: sender
5897{
5898 NSWindow *win = [self window];
5899 NSRect r = [win frame];
e2f79c8d
JD
5900 NSArray *screens = [NSScreen screens];
5901 NSScreen *screen = [screens objectAtIndex: 0];
edfda783
AR
5902
5903 NSTRACE (windowDidMove);
5904
5905 if (!emacsframe->output_data.ns)
5906 return;
5907 if (screen != nil)
5908 {
6516d10a
AR
5909 emacsframe->left_pos = r.origin.x;
5910 emacsframe->top_pos =
5911 [screen frame].size.height - (r.origin.y + r.size.height);
edfda783
AR
5912 }
5913}
5914
6516d10a
AR
5915
5916/* Called AFTER method below, but before our windowWillResize call there leads
5917 to windowDidResize -> x_set_window_size. Update emacs' notion of frame
5918 location so set_window_size moves the frame. */
edfda783
AR
5919- (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5920{
e2f79c8d 5921 emacsframe->output_data.ns->zooming = 1;
edfda783
AR
5922 return YES;
5923}
edfda783 5924
4ddf94bd
AR
5925
5926/* Override to do something slightly nonstandard, but nice. First click on
5927 zoom button will zoom vertically. Second will zoom completely. Third
5928 returns to original. */
edfda783 5929- (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
4ddf94bd
AR
5930 defaultFrame:(NSRect)defaultFrame
5931{
5932 NSRect result = [sender frame];
6516d10a 5933
4ddf94bd
AR
5934 NSTRACE (windowWillUseStandardFrame);
5935
dd946752
JD
5936 if (fs_before_fs != -1) /* Entering fullscreen */
5937 {
5938 result = defaultFrame;
5939 }
5940 else if (next_maximized == FULLSCREEN_HEIGHT
5941 || (next_maximized == -1
5942 && abs (defaultFrame.size.height - result.size.height)
5943 > FRAME_LINE_HEIGHT (emacsframe)))
6516d10a
AR
5944 {
5945 /* first click */
5946 ns_userRect = result;
dd946752
JD
5947 maximized_height = result.size.height = defaultFrame.size.height;
5948 maximized_width = -1;
6516d10a 5949 result.origin.y = defaultFrame.origin.y;
dd946752
JD
5950 [self setFSValue: FULLSCREEN_HEIGHT];
5951 }
5952 else if (next_maximized == FULLSCREEN_WIDTH)
5953 {
5954 ns_userRect = result;
5955 maximized_width = result.size.width = defaultFrame.size.width;
5956 maximized_height = -1;
5957 result.origin.x = defaultFrame.origin.x;
5958 [self setFSValue: FULLSCREEN_WIDTH];
5959 }
5960 else if (next_maximized == FULLSCREEN_MAXIMIZED
5961 || (next_maximized == -1
5962 && abs (defaultFrame.size.width - result.size.width)
5963 > FRAME_COLUMN_WIDTH (emacsframe)))
5964 {
5965 result = defaultFrame; /* second click */
5966 maximized_width = result.size.width;
5967 maximized_height = result.size.height;
5968 [self setFSValue: FULLSCREEN_MAXIMIZED];
6516d10a
AR
5969 }
5970 else
5971 {
dd946752
JD
5972 /* restore */
5973 result = ns_userRect.size.height ? ns_userRect : result;
5974 ns_userRect = NSMakeRect (0, 0, 0, 0);
5975 [self setFSValue: FULLSCREEN_NONE];
5976 maximized_width = maximized_width = -1;
6516d10a 5977 }
4ddf94bd 5978
dd946752 5979 if (fs_before_fs == -1) next_maximized = -1;
4ddf94bd
AR
5980 [self windowWillResize: sender toSize: result.size];
5981 return result;
5982}
edfda783
AR
5983
5984
5985- (void)windowDidDeminiaturize: sender
5986{
5987 NSTRACE (windowDidDeminiaturize);
5988 if (!emacsframe->output_data.ns)
5989 return;
edfa7fa0
DA
5990
5991 SET_FRAME_ICONIFIED (emacsframe, 0);
5992 SET_FRAME_VISIBLE (emacsframe, 1);
edfda783
AR
5993 windows_or_buffers_changed++;
5994
5995 if (emacs_event)
5996 {
edfa7fa0 5997 emacs_event->kind = DEICONIFY_EVENT;
edfda783
AR
5998 EV_TRAILER ((id)nil);
5999 }
6000}
6001
6002
6003- (void)windowDidExpose: sender
6004{
6005 NSTRACE (windowDidExpose);
6006 if (!emacsframe->output_data.ns)
6007 return;
edfa7fa0
DA
6008
6009 SET_FRAME_VISIBLE (emacsframe, 1);
edfda783
AR
6010 SET_FRAME_GARBAGED (emacsframe);
6011
6012 if (send_appdefined)
6013 ns_send_appdefined (-1);
6014}
6015
6016
6017- (void)windowDidMiniaturize: sender
6018{
6019 NSTRACE (windowDidMiniaturize);
6020 if (!emacsframe->output_data.ns)
6021 return;
6022
edfa7fa0
DA
6023 SET_FRAME_ICONIFIED (emacsframe, 1);
6024 SET_FRAME_VISIBLE (emacsframe, 0);
edfda783
AR
6025
6026 if (emacs_event)
6027 {
6028 emacs_event->kind = ICONIFY_EVENT;
6029 EV_TRAILER ((id)nil);
6030 }
6031}
6032
6871e574
JD
6033#ifdef HAVE_NATIVE_FS
6034- (NSApplicationPresentationOptions)window:(NSWindow *)window
6035 willUseFullScreenPresentationOptions:
6036 (NSApplicationPresentationOptions)proposedOptions
6037{
6038 return proposedOptions|NSApplicationPresentationAutoHideToolbar;
6039}
6040#endif
6041
dd946752
JD
6042- (void)windowWillEnterFullScreen:(NSNotification *)notification
6043{
6044 fs_before_fs = fs_state;
6045}
6046
6047- (void)windowDidEnterFullScreen:(NSNotification *)notification
6048{
6049 [self setFSValue: FULLSCREEN_BOTH];
6871e574 6050 if (! [self fsIsNative])
04fafa46 6051 {
6871e574
JD
6052 [self windowDidBecomeKey:notification];
6053 [nonfs_window orderOut:self];
04fafa46 6054 }
6871e574
JD
6055 else if (! FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6056 [toolbar setVisible:NO];
dd946752
JD
6057}
6058
6059- (void)windowWillExitFullScreen:(NSNotification *)notification
6060{
6061 if (next_maximized != -1)
6062 fs_before_fs = next_maximized;
6063}
6064
6065- (void)windowDidExitFullScreen:(NSNotification *)notification
6066{
6067 [self setFSValue: fs_before_fs];
6068 fs_before_fs = -1;
6871e574
JD
6069 [self updateCollectionBehaviour];
6070 if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6071 {
6072 [toolbar setVisible:YES];
6073 update_frame_tool_bar (emacsframe);
6074 [self updateFrameSize:YES];
6075 [[self window] display];
6076 }
6077 else
6078 [toolbar setVisible:NO];
6079
dd946752
JD
6080 if (next_maximized != -1)
6081 [[self window] performZoom:self];
6082}
6083
6871e574 6084- (BOOL)fsIsNative
dd946752 6085{
6871e574
JD
6086 return fs_is_native;
6087}
6088
6089- (BOOL)isFullscreen
6090{
6091 if (! fs_is_native) return nonfs_window != nil;
6092#ifdef HAVE_NATIVE_FS
6093 return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
dd946752 6094#else
6871e574
JD
6095 return NO;
6096#endif
6097}
6098
6099#ifdef HAVE_NATIVE_FS
6100- (void)updateCollectionBehaviour
6101{
6102 if (! [self isFullscreen])
6103 {
6104 NSWindow *win = [self window];
6105 NSWindowCollectionBehavior b = [win collectionBehavior];
6106 if (ns_use_native_fullscreen)
6107 b |= NSWindowCollectionBehaviorFullScreenPrimary;
6108 else
6109 b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
6110
6111 [win setCollectionBehavior: b];
6112 fs_is_native = ns_use_native_fullscreen;
6113 }
6114}
6115#endif
6116
6117- (void)toggleFullScreen: (id)sender
6118{
6119 NSWindow *w, *fw;
6120 BOOL onFirstScreen;
6121 struct frame *f;
dd946752 6122 NSSize sz;
6871e574
JD
6123 NSRect r, wr;
6124 NSColor *col;
6125
6126 if (fs_is_native)
6127 {
6128 [[self window] toggleFullScreen:sender];
6129 return;
6130 }
6131
6132 w = [self window];
6133 onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
6134 f = emacsframe;
6135 wr = [w frame];
6136 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6137 (FRAME_DEFAULT_FACE (f)),
6138 f);
dd946752
JD
6139
6140 sz.width = FRAME_COLUMN_WIDTH (f);
6141 sz.height = FRAME_LINE_HEIGHT (f);
6142
6143 if (fs_state != FULLSCREEN_BOTH)
6144 {
6145 /* Hide dock and menubar if we are on the primary screen. */
6146 if (onFirstScreen)
6147 {
6148#if defined (NS_IMPL_COCOA) && \
6149 MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6150 NSApplicationPresentationOptions options
6151 = NSApplicationPresentationAutoHideDock
6152 | NSApplicationPresentationAutoHideMenuBar;
6153
6154 [NSApp setPresentationOptions: options];
6155#else
6156 [NSMenu setMenuBarVisible:NO];
6157#endif
6158 }
6159
6160 fw = [[EmacsFSWindow alloc]
04fafa46 6161 initWithContentRect:[w contentRectForFrameRect:wr]
dd946752
JD
6162 styleMask:NSBorderlessWindowMask
6163 backing:NSBackingStoreBuffered
6164 defer:YES
6165 screen:[w screen]];
6166
6167 [fw setContentView:[w contentView]];
6168 [fw setTitle:[w title]];
dd946752 6169 [fw setDelegate:self];
dd946752
JD
6170 [fw setAcceptsMouseMovedEvents: YES];
6171 [fw useOptimizedDrawing: YES];
6172 [fw setResizeIncrements: sz];
6173 [fw setBackgroundColor: col];
6174 if ([col alphaComponent] != 1.0)
6175 [fw setOpaque: NO];
6176
6177 f->border_width = 0;
6178 FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
04fafa46
JD
6179 tobar_height = FRAME_TOOLBAR_HEIGHT (f);
6180 FRAME_TOOLBAR_HEIGHT (f) = 0;
dd946752
JD
6181
6182 nonfs_window = w;
04fafa46 6183
dd946752 6184 [self windowWillEnterFullScreen:nil];
04fafa46
JD
6185 [fw makeKeyAndOrderFront:NSApp];
6186 [fw makeFirstResponder:self];
dd946752
JD
6187 [w orderOut:self];
6188 r = [fw frameRectForContentRect:[[fw screen] frame]];
6189 [fw setFrame: r display:YES animate:YES];
6190 [self windowDidEnterFullScreen:nil];
04fafa46 6191 [fw display];
dd946752
JD
6192 }
6193 else
6194 {
6195 fw = w;
6196 w = nonfs_window;
04fafa46 6197 nonfs_window = nil;
dd946752
JD
6198
6199 if (onFirstScreen)
6200 {
6201#if defined (NS_IMPL_COCOA) && \
6202 MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6203 [NSApp setPresentationOptions: NSApplicationPresentationDefault];
6204#else
6205 [NSMenu setMenuBarVisible:YES];
6206#endif
6207 }
6208
6209 [w setContentView:[fw contentView]];
6210 [w setResizeIncrements: sz];
6211 [w setBackgroundColor: col];
6212 if ([col alphaComponent] != 1.0)
6213 [w setOpaque: NO];
5f3f57be 6214
dd946752 6215 f->border_width = bwidth;
04fafa46 6216 FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
6871e574
JD
6217 if (FRAME_EXTERNAL_TOOL_BAR (f))
6218 FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
dd946752
JD
6219
6220 [self windowWillExitFullScreen:nil];
6221 [fw setFrame: [w frame] display:YES animate:YES];
6222 [fw close];
6223 [w makeKeyAndOrderFront:NSApp];
6224 [self windowDidExitFullScreen:nil];
6871e574 6225 [self updateFrameSize:YES];
dd946752 6226 }
dd946752
JD
6227}
6228
6229- (void)handleFS
6230{
6231 if (fs_state != emacsframe->want_fullscreen)
6232 {
6233 if (fs_state == FULLSCREEN_BOTH)
6234 {
6235 [self toggleFullScreen:self];
6236 }
6237
6238 switch (emacsframe->want_fullscreen)
6239 {
6240 case FULLSCREEN_BOTH:
6241 [self toggleFullScreen:self];
6242 break;
6243 case FULLSCREEN_WIDTH:
6244 next_maximized = FULLSCREEN_WIDTH;
6245 if (fs_state != FULLSCREEN_BOTH)
6246 [[self window] performZoom:self];
6247 break;
6248 case FULLSCREEN_HEIGHT:
6249 next_maximized = FULLSCREEN_HEIGHT;
6250 if (fs_state != FULLSCREEN_BOTH)
6251 [[self window] performZoom:self];
6252 break;
6253 case FULLSCREEN_MAXIMIZED:
6254 next_maximized = FULLSCREEN_MAXIMIZED;
6255 if (fs_state != FULLSCREEN_BOTH)
6256 [[self window] performZoom:self];
6257 break;
6258 case FULLSCREEN_NONE:
6259 if (fs_state != FULLSCREEN_BOTH)
6260 {
6261 next_maximized = FULLSCREEN_NONE;
6262 [[self window] performZoom:self];
6263 }
6264 break;
6265 }
5f3f57be 6266
dd946752
JD
6267 emacsframe->want_fullscreen = FULLSCREEN_NONE;
6268 }
6269
6270}
6271
6272- (void) setFSValue: (int)value
6273{
6274 Lisp_Object lval = Qnil;
6275 switch (value)
6276 {
6277 case FULLSCREEN_BOTH:
6278 lval = Qfullboth;
6279 break;
6280 case FULLSCREEN_WIDTH:
6281 lval = Qfullwidth;
6282 break;
6283 case FULLSCREEN_HEIGHT:
6284 lval = Qfullheight;
6285 break;
6286 case FULLSCREEN_MAXIMIZED:
6287 lval = Qmaximized;
6288 break;
6289 }
6290 store_frame_param (emacsframe, Qfullscreen, lval);
6291 fs_state = value;
6292}
edfda783
AR
6293
6294- (void)mouseEntered: (NSEvent *)theEvent
6295{
edfda783 6296 NSTRACE (mouseEntered);
edfda783
AR
6297 last_mouse_movement_time = EV_TIMESTAMP (theEvent);
6298}
6299
6300
6301- (void)mouseExited: (NSEvent *)theEvent
6302{
bbf534ce 6303 Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
edfda783
AR
6304
6305 NSTRACE (mouseExited);
6306
c1fc2d3a 6307 if (!hlinfo)
edfda783
AR
6308 return;
6309
6310 last_mouse_movement_time = EV_TIMESTAMP (theEvent);
6311
bbf534ce 6312 if (emacsframe == hlinfo->mouse_face_mouse_frame)
edfda783 6313 {
bbf534ce
EZ
6314 clear_mouse_face (hlinfo);
6315 hlinfo->mouse_face_mouse_frame = 0;
edfda783
AR
6316 }
6317}
6318
6319
6320- menuDown: sender
6321{
6322 NSTRACE (menuDown);
6323 if (context_menu_value == -1)
6324 context_menu_value = [sender tag];
1088b922 6325 else
0dc8cf50
JD
6326 {
6327 NSInteger tag = [sender tag];
6328 find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
e69b0960 6329 emacsframe->menu_bar_vector,
0dc8cf50
JD
6330 (void *)tag);
6331 }
6332
edfda783
AR
6333 ns_send_appdefined (-1);
6334 return self;
6335}
6336
6337
6338- (EmacsToolbar *)toolbar
6339{
6340 return toolbar;
6341}
6342
6343
6344/* this gets called on toolbar button click */
6345- toolbarClicked: (id)item
6346{
6347 NSEvent *theEvent;
6348 int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6349
6350 NSTRACE (toolbarClicked);
6351
6352 if (!emacs_event)
6353 return self;
6354
6355 /* send first event (for some reason two needed) */
8612b71a 6356 theEvent = [[self window] currentEvent];
edfda783
AR
6357 emacs_event->kind = TOOL_BAR_EVENT;
6358 XSETFRAME (emacs_event->arg, emacsframe);
6359 EV_TRAILER (theEvent);
6360
6361 emacs_event->kind = TOOL_BAR_EVENT;
6362/* XSETINT (emacs_event->code, 0); */
e69b0960 6363 emacs_event->arg = AREF (emacsframe->tool_bar_items,
edd74c35 6364 idx + TOOL_BAR_ITEM_KEY);
edfda783
AR
6365 emacs_event->modifiers = EV_MODIFIERS (theEvent);
6366 EV_TRAILER (theEvent);
6367 return self;
6368}
6369
6370
6371- toggleToolbar: (id)sender
6372{
8612b71a
AR
6373 if (!emacs_event)
6374 return self;
6375
a9f58614 6376 emacs_event->kind = NS_NONKEY_EVENT;
8612b71a
AR
6377 emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6378 EV_TRAILER ((id)nil);
6379 return self;
edfda783
AR
6380}
6381
6382
6383- (void)drawRect: (NSRect)rect
6384{
6385 int x = NSMinX (rect), y = NSMinY (rect);
6386 int width = NSWidth (rect), height = NSHeight (rect);
6387
6388 NSTRACE (drawRect);
6389
3bc0a2f7 6390 if (!emacsframe || !emacsframe->output_data.ns)
edfda783
AR
6391 return;
6392
4ddf94bd 6393 ns_clear_frame_area (emacsframe, x, y, width, height);
edfda783 6394 expose_frame (emacsframe, x, y, width, height);
15891144
DR
6395
6396 /*
6397 drawRect: may be called (at least in OS X 10.5) for invisible
2c6584e8 6398 views as well for some reason. Thus, do not infer visibility
15891144
DR
6399 here.
6400
6401 emacsframe->async_visible = 1;
6402 emacsframe->async_iconified = 0;
6403 */
edfda783
AR
6404}
6405
6406
6407/* NSDraggingDestination protocol methods. Actually this is not really a
6408 protocol, but a category of Object. O well... */
6409
e7b90afd 6410-(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
edfda783
AR
6411{
6412 NSTRACE (draggingEntered);
6413 return NSDragOperationGeneric;
6414}
6415
6416
6417-(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6418{
6419 return YES;
6420}
6421
6422
6423-(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6424{
6425 id pb;
6426 int x, y;
6427 NSString *type;
6428 NSEvent *theEvent = [[self window] currentEvent];
6429 NSPoint position;
6430
6431 NSTRACE (performDragOperation);
6432
6433 if (!emacs_event)
3fdebbf9 6434 return NO;
edfda783
AR
6435
6436 position = [self convertPoint: [sender draggingLocation] fromView: nil];
6437 x = lrint (position.x); y = lrint (position.y);
6438
6439 pb = [sender draggingPasteboard];
6440 type = [pb availableTypeFromArray: ns_drag_types];
6441 if (type == 0)
6442 {
6443 return NO;
6444 }
6445 else if ([type isEqualToString: NSFilenamesPboardType])
6446 {
6447 NSArray *files;
6448 NSEnumerator *fenum;
6449 NSString *file;
6450
6451 if (!(files = [pb propertyListForType: type]))
6452 return NO;
6453
6454 fenum = [files objectEnumerator];
6455 while ( (file = [fenum nextObject]) )
6456 {
a9f58614 6457 emacs_event->kind = NS_NONKEY_EVENT;
edfda783
AR
6458 emacs_event->code = KEY_NS_DRAG_FILE;
6459 XSETINT (emacs_event->x, x);
6460 XSETINT (emacs_event->y, y);
6461 ns_input_file = append2 (ns_input_file,
6462 build_string ([file UTF8String]));
6463 emacs_event->modifiers = EV_MODIFIERS (theEvent);
6464 EV_TRAILER (theEvent);
6465 }
6466 return YES;
6467 }
6468 else if ([type isEqualToString: NSURLPboardType])
6469 {
6470 NSString *file;
6471 NSURL *fileURL;
6472
6473 if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
6474 [fileURL isFileURL] == NO)
6475 return NO;
6476
6477 file = [fileURL path];
a9f58614 6478 emacs_event->kind = NS_NONKEY_EVENT;
edfda783
AR
6479 emacs_event->code = KEY_NS_DRAG_FILE;
6480 XSETINT (emacs_event->x, x);
6481 XSETINT (emacs_event->y, y);
6482 ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
6483 emacs_event->modifiers = EV_MODIFIERS (theEvent);
6484 EV_TRAILER (theEvent);
6485 return YES;
6486 }
6487 else if ([type isEqualToString: NSStringPboardType]
6488 || [type isEqualToString: NSTabularTextPboardType])
6489 {
6490 NSString *data;
6491
6492 if (! (data = [pb stringForType: type]))
6493 return NO;
6494
a9f58614 6495 emacs_event->kind = NS_NONKEY_EVENT;
edfda783
AR
6496 emacs_event->code = KEY_NS_DRAG_TEXT;
6497 XSETINT (emacs_event->x, x);
6498 XSETINT (emacs_event->y, y);
6499 ns_input_text = build_string ([data UTF8String]);
6500 emacs_event->modifiers = EV_MODIFIERS (theEvent);
6501 EV_TRAILER (theEvent);
6502 return YES;
6503 }
6504 else if ([type isEqualToString: NSColorPboardType])
6505 {
6506 NSColor *c = [NSColor colorFromPasteboard: pb];
a9f58614 6507 emacs_event->kind = NS_NONKEY_EVENT;
edfda783
AR
6508 emacs_event->code = KEY_NS_DRAG_COLOR;
6509 XSETINT (emacs_event->x, x);
6510 XSETINT (emacs_event->y, y);
6511 ns_input_color = ns_color_to_lisp (c);
6512 emacs_event->modifiers = EV_MODIFIERS (theEvent);
6513 EV_TRAILER (theEvent);
6514 return YES;
6515 }
6516 else if ([type isEqualToString: NSFontPboardType])
6517 {
6518 /* impl based on GNUstep NSTextView.m */
6519 NSData *data = [pb dataForType: NSFontPboardType];
6520 NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
6521 NSFont *font = [dict objectForKey: NSFontAttributeName];
6522 char fontSize[10];
6523
6524 if (font == nil)
6525 return NO;
6526
a9f58614 6527 emacs_event->kind = NS_NONKEY_EVENT;
edfda783
AR
6528 emacs_event->code = KEY_NS_CHANGE_FONT;
6529 XSETINT (emacs_event->x, x);
6530 XSETINT (emacs_event->y, y);
6531 ns_input_font = build_string ([[font fontName] UTF8String]);
6532 snprintf (fontSize, 10, "%f", [font pointSize]);
6533 ns_input_fontsize = build_string (fontSize);
6534 emacs_event->modifiers = EV_MODIFIERS (theEvent);
6535 EV_TRAILER (theEvent);
6536 return YES;
6537 }
6538 else
6539 {
6540 error ("Invalid data type in dragging pasteboard.");
6541 return NO;
6542 }
6543}
6544
6545
699c10bd
JD
6546- (id) validRequestorForSendType: (NSString *)typeSent
6547 returnType: (NSString *)typeReturned
edfda783
AR
6548{
6549 NSTRACE (validRequestorForSendType);
699c10bd 6550 if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
3fe4b549 6551 && typeReturned == nil)
699c10bd
JD
6552 {
6553 if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6554 return self;
6555 }
edfda783
AR
6556
6557 return [super validRequestorForSendType: typeSent
6558 returnType: typeReturned];
6559}
6560
6561
d900b2af
AR
6562/* The next two methods are part of NSServicesRequests informal protocol,
6563 supposedly called when a services menu item is chosen from this app.
6564 But this should not happen because we override the services menu with our
6565 own entries which call ns-perform-service.
d6223c23 6566 Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
d900b2af
AR
6567 So let's at least stub them out until further investigation can be done. */
6568
6569- (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6570{
6571 /* we could call ns_string_from_pasteboard(pboard) here but then it should
6572 be written into the buffer in place of the existing selection..
6573 ordinary service calls go through functions defined in ns-win.el */
6574 return NO;
6575}
6576
6577- (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6578{
699c10bd
JD
6579 NSArray *typesDeclared;
6580 Lisp_Object val;
6581
6582 /* We only support NSStringPboardType */
6583 if ([types containsObject:NSStringPboardType] == NO) {
6584 return NO;
6585 }
6586
6587 val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6588 if (CONSP (val) && SYMBOLP (XCAR (val)))
6589 {
6590 val = XCDR (val);
6591 if (CONSP (val) && NILP (XCDR (val)))
6592 val = XCAR (val);
6593 }
6594 if (! STRINGP (val))
6595 return NO;
6596
6597 typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6598 [pb declareTypes:typesDeclared owner:nil];
6599 ns_string_to_pasteboard (pb, val);
6600 return YES;
d900b2af
AR
6601}
6602
6603
edfda783
AR
6604/* setMini =YES means set from internal (gives a finder icon), NO means set nil
6605 (gives a miniaturized version of the window); currently we use the latter for
6606 frames whose active buffer doesn't correspond to any file
6607 (e.g., '*scratch*') */
6608- setMiniwindowImage: (BOOL) setMini
6609{
6610 id image = [[self window] miniwindowImage];
6611 NSTRACE (setMiniwindowImage);
6612
6613 /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6614 about "AppleDockIconEnabled" notwithstanding, however the set message
6615 below has its effect nonetheless. */
6616 if (image != emacsframe->output_data.ns->miniimage)
6617 {
6618 if (image && [image isKindOfClass: [EmacsImage class]])
6619 [image release];
6620 [[self window] setMiniwindowImage:
6621 setMini ? emacsframe->output_data.ns->miniimage : nil];
6622 }
6623
6624 return self;
6625}
6626
6627
6628- (void) setRows: (int) r andColumns: (int) c
6629{
6630 rows = r;
6631 cols = c;
6632}
6633
6634@end /* EmacsView */
6635
6636
6637
6638/* ==========================================================================
6639
6640 EmacsWindow implementation
6641
6642 ========================================================================== */
6643
6644@implementation EmacsWindow
6645
784051c4 6646#ifdef NS_IMPL_COCOA
c4328746
JD
6647- (id)accessibilityAttributeValue:(NSString *)attribute
6648{
6649 Lisp_Object str = Qnil;
6650 struct frame *f = SELECTED_FRAME ();
e74aeda8 6651 struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
1088b922 6652
c4328746
JD
6653 if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6654 return NSAccessibilityTextFieldRole;
6655
6656 if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6657 && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6658 {
6659 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6660 }
6661 else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
6662 {
6663 if (! NILP (BVAR (curbuf, mark_active)))
6664 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
1088b922 6665
c4328746
JD
6666 if (NILP (str))
6667 {
6668 ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
6669 ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
6670 ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
1088b922 6671
c4328746
JD
6672 if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
6673 str = make_uninit_multibyte_string (range, byte_range);
6674 else
6675 str = make_uninit_string (range);
6676 /* To check: This returns emacs-utf-8, which is a superset of utf-8.
6677 Is this a problem? */
6678 memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
6679 }
6680 }
1088b922
PE
6681
6682
6683 if (! NILP (str))
c4328746
JD
6684 {
6685 if (CONSP (str) && SYMBOLP (XCAR (str)))
6686 {
6687 str = XCDR (str);
6688 if (CONSP (str) && NILP (XCDR (str)))
6689 str = XCAR (str);
6690 }
6691 if (STRINGP (str))
6692 {
6693 const char *utfStr = SSDATA (str);
6694 NSString *nsStr = [NSString stringWithUTF8String: utfStr];
6695 return nsStr;
6696 }
6697 }
1088b922 6698
c4328746
JD
6699 return [super accessibilityAttributeValue:attribute];
6700}
784051c4 6701#endif /* NS_IMPL_COCOA */
c4328746 6702
e2f79c8d
JD
6703/* If we have multiple monitors, one above the other, we don't want to
6704 restrict the height to just one monitor. So we override this. */
6705- (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6706{
aff67c82
JD
6707 /* When making the frame visible for the first time or if there is just
6708 one screen, we want to constrain. Other times not. */
6709 NSUInteger nr_screens = [[NSScreen screens] count];
e2f79c8d 6710 struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
f0a1382a
JD
6711 NSTRACE (constrainFrameRect);
6712
aff67c82 6713 if (nr_screens == 1)
9d7f1863
JD
6714 {
6715 NSRect r = [super constrainFrameRect:frameRect toScreen:screen];
9d7f1863
JD
6716 return r;
6717 }
0caaedb1 6718
f0a1382a
JD
6719 if (f->output_data.ns->dont_constrain
6720 || ns_menu_bar_should_be_hidden ())
e2f79c8d
JD
6721 return frameRect;
6722
3fb69558 6723 f->output_data.ns->dont_constrain = 1;
e2f79c8d
JD
6724 return [super constrainFrameRect:frameRect toScreen:screen];
6725}
6726
edfda783
AR
6727@end /* EmacsWindow */
6728
6729
dd946752
JD
6730@implementation EmacsFSWindow
6731
6732- (BOOL)canBecomeKeyWindow
6733{
6734 return YES;
6735}
6736
04fafa46
JD
6737- (BOOL)canBecomeMainWindow
6738{
6739 return YES;
6740}
6741
dd946752
JD
6742@end
6743
edfda783
AR
6744/* ==========================================================================
6745
6746 EmacsScroller implementation
6747
6748 ========================================================================== */
6749
6750
6751@implementation EmacsScroller
6752
6753/* for repeat button push */
6754#define SCROLL_BAR_FIRST_DELAY 0.5
6755#define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6756
e7b90afd 6757+ (CGFloat) scrollerWidth
edfda783 6758{
df2142db
AR
6759 /* TODO: if we want to allow variable widths, this is the place to do it,
6760 however neither GNUstep nor Cocoa support it very well */
edfda783
AR
6761 return [NSScroller scrollerWidth];
6762}
6763
6764
6765- initFrame: (NSRect )r window: (Lisp_Object)nwin
6766{
6767 NSTRACE (EmacsScroller_initFrame);
6768
6769 r.size.width = [EmacsScroller scrollerWidth];
6770 [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6771 [self setContinuous: YES];
6772 [self setEnabled: YES];
6773
6774 /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6aba198c
AR
6775 locked against the top and bottom edges, and right edge on OS X, where
6776 scrollers are on right. */
6777#ifdef NS_IMPL_GNUSTEP
6778 [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6779#else
edfda783 6780 [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6aba198c 6781#endif
edfda783
AR
6782
6783 win = nwin;
6784 condemned = NO;
6785 pixel_height = NSHeight (r);
9aabf64c 6786 if (pixel_height == 0) pixel_height = 1;
edfda783
AR
6787 min_portion = 20 / pixel_height;
6788
d3d50620 6789 frame = XFRAME (XWINDOW (win)->frame);
edfda783
AR
6790 if (FRAME_LIVE_P (frame))
6791 {
6792 int i;
6793 EmacsView *view = FRAME_NS_VIEW (frame);
6794 NSView *sview = [[view window] contentView];
6795 NSArray *subs = [sview subviews];
6796
6797 /* disable optimization stopping redraw of other scrollbars */
6798 view->scrollbarsNeedingUpdate = 0;
6799 for (i =[subs count]-1; i >= 0; i--)
6800 if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6801 view->scrollbarsNeedingUpdate++;
6802 [sview addSubview: self];
6803 }
6804
6805/* [self setFrame: r]; */
6806
6807 return self;
6808}
6809
6810
6811- (void)setFrame: (NSRect)newRect
6812{
6813 NSTRACE (EmacsScroller_setFrame);
4d7e6e51 6814/* block_input (); */
edfda783 6815 pixel_height = NSHeight (newRect);
9aabf64c 6816 if (pixel_height == 0) pixel_height = 1;
edfda783
AR
6817 min_portion = 20 / pixel_height;
6818 [super setFrame: newRect];
6819 [self display];
4d7e6e51 6820/* unblock_input (); */
edfda783
AR
6821}
6822
6823
6824- (void)dealloc
6825{
6826 NSTRACE (EmacsScroller_dealloc);
6827 if (!NILP (win))
e8c17b81 6828 wset_vertical_scroll_bar (XWINDOW (win), Qnil);
edfda783
AR
6829 [super dealloc];
6830}
6831
6832
6833- condemn
6834{
6835 NSTRACE (condemn);
6836 condemned =YES;
6837 return self;
6838}
6839
6840
6841- reprieve
6842{
6843 NSTRACE (reprieve);
6844 condemned =NO;
6845 return self;
6846}
6847
6848
6849- judge
6850{
6851 NSTRACE (judge);
6852 if (condemned)
6853 {
3d608a86 6854 EmacsView *view;
4d7e6e51 6855 block_input ();
edfda783 6856 /* ensure other scrollbar updates after deletion */
3d608a86 6857 view = (EmacsView *)FRAME_NS_VIEW (frame);
edfda783
AR
6858 if (view != nil)
6859 view->scrollbarsNeedingUpdate++;
6860 [self removeFromSuperview];
6861 [self release];
4d7e6e51 6862 unblock_input ();
edfda783
AR
6863 }
6864 return self;
6865}
6866
6867
6868- (void)resetCursorRects
6869{
6870 NSRect visible = [self visibleRect];
6871 NSTRACE (resetCursorRects);
6872
6873 if (!NSIsEmptyRect (visible))
6874 [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6875 [[NSCursor arrowCursor] setOnMouseEntered: YES];
6876}
6877
6878
6879- (int) checkSamePosition: (int) position portion: (int) portion
6880 whole: (int) whole
6881{
6882 return em_position ==position && em_portion ==portion && em_whole ==whole
6883 && portion != whole; /* needed for resize empty buf */
6884}
6885
6886
6887- setPosition: (int)position portion: (int)portion whole: (int)whole
6888{
6889 NSTRACE (setPosition);
6890
6891 em_position = position;
6892 em_portion = portion;
6893 em_whole = whole;
6894
6895 if (portion >= whole)
4393663b
JD
6896 {
6897#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6898 [self setKnobProportion: 1.0];
6899 [self setDoubleValue: 1.0];
6900#else
6901 [self setFloatValue: 0.0 knobProportion: 1.0];
6902#endif
6903 }
edfda783
AR
6904 else
6905 {
6906 float pos, por;
6907 portion = max ((float)whole*min_portion/pixel_height, portion);
6908 pos = (float)position / (whole - portion);
6909 por = (float)portion/whole;
4393663b
JD
6910#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6911 [self setKnobProportion: por];
6912 [self setDoubleValue: pos];
6913#else
edfda783 6914 [self setFloatValue: pos knobProportion: por];
4393663b 6915#endif
edfda783 6916 }
167e3640
JD
6917
6918 /* Events may come here even if the event loop is not running.
6919 If we don't enter the event loop, the scroll bar will not update.
6920 So send SIGIO to ourselves. */
a631d0e0 6921 if (apploopnr == 0) raise (SIGIO);
167e3640 6922
edfda783
AR
6923 return self;
6924}
6925
df2142db
AR
6926/* FIXME: unused at moment (see ns_mouse_position) at the moment because
6927 drag events will go directly to the EmacsScroller. Leaving in for now. */
edfda783
AR
6928-(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6929 x: (Lisp_Object *)x y: ( Lisp_Object *)y
6930{
6931 *part = last_hit_part;
6932 *window = win;
6933 XSETINT (*y, pixel_height);
6934 if ([self floatValue] > 0.999)
6935 XSETINT (*x, pixel_height);
6936 else
6937 XSETINT (*x, pixel_height * [self floatValue]);
6938}
6939
6940
6941/* set up emacs_event */
6942- (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6943{
6944 if (!emacs_event)
6945 return;
6946
6947 emacs_event->part = last_hit_part;
6948 emacs_event->code = 0;
6949 emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
6950 emacs_event->frame_or_window = win;
6951 emacs_event->timestamp = EV_TIMESTAMP (e);
6952 emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
6953 emacs_event->arg = Qnil;
6954 XSETINT (emacs_event->x, loc * pixel_height);
6955 XSETINT (emacs_event->y, pixel_height-20);
6956
ddee6515
JD
6957 if (q_event_ptr)
6958 {
6959 n_emacs_events_pending++;
6960 kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
6961 }
6962 else
167e3640 6963 hold_event (emacs_event);
edfda783
AR
6964 EVENT_INIT (*emacs_event);
6965 ns_send_appdefined (-1);
6966}
6967
6968
6969/* called manually thru timer to implement repeated button action w/hold-down */
6970- repeatScroll: (NSTimer *)scrollEntry
6971{
6972 NSEvent *e = [[self window] currentEvent];
6973 NSPoint p = [[self window] mouseLocationOutsideOfEventStream];
6974 BOOL inKnob = [self testPart: p] == NSScrollerKnob;
6975
6976 /* clear timer if need be */
6977 if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
6978 {
6979 [scroll_repeat_entry invalidate];
6980 [scroll_repeat_entry release];
6981 scroll_repeat_entry = nil;
6982
6983 if (inKnob)
6984 return self;
6985
facfbbbd
SM
6986 scroll_repeat_entry
6987 = [[NSTimer scheduledTimerWithTimeInterval:
6988 SCROLL_BAR_CONTINUOUS_DELAY
edfda783
AR
6989 target: self
6990 selector: @selector (repeatScroll:)
6991 userInfo: 0
6992 repeats: YES]
facfbbbd 6993 retain];
edfda783
AR
6994 }
6995
6996 [self sendScrollEventAtLoc: 0 fromEvent: e];
6997 return self;
6998}
6999
7000
7001/* Asynchronous mouse tracking for scroller. This allows us to dispatch
7002 mouseDragged events without going into a modal loop. */
7003- (void)mouseDown: (NSEvent *)e
7004{
7005 NSRect sr, kr;
7006 /* hitPart is only updated AFTER event is passed on */
7007 NSScrollerPart part = [self testPart: [e locationInWindow]];
7008 double inc = 0.0, loc, kloc, pos;
7009 int edge = 0;
7010
7011 NSTRACE (EmacsScroller_mouseDown);
7012
7013 switch (part)
7014 {
7015 case NSScrollerDecrementPage:
7016 last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
7017 case NSScrollerIncrementPage:
7018 last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
7019 case NSScrollerDecrementLine:
7020 last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
7021 case NSScrollerIncrementLine:
7022 last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
7023 case NSScrollerKnob:
7024 last_hit_part = scroll_bar_handle; break;
7025 case NSScrollerKnobSlot: /* GNUstep-only */
7026 last_hit_part = scroll_bar_move_ratio; break;
7027 default: /* NSScrollerNoPart? */
e7b90afd 7028 fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
bf856382 7029 (long) part);
edfda783
AR
7030 return;
7031 }
7032
7033 if (inc != 0.0)
7034 {
7035 pos = 0; /* ignored */
7036
7037 /* set a timer to repeat, as we can't let superclass do this modally */
facfbbbd 7038 scroll_repeat_entry
b3aac06a 7039 = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
facfbbbd
SM
7040 target: self
7041 selector: @selector (repeatScroll:)
7042 userInfo: 0
7043 repeats: YES]
7044 retain];
edfda783
AR
7045 }
7046 else
7047 {
7048 /* handle, or on GNUstep possibly slot */
7049 NSEvent *fake_event;
7050
7051 /* compute float loc in slot and mouse offset on knob */
7052 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7053 toView: nil];
7054 loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7055 if (loc <= 0.0)
7056 {
7057 loc = 0.0;
7058 edge = -1;
7059 }
7060 else if (loc >= NSHeight (sr))
7061 {
7062 loc = NSHeight (sr);
7063 edge = 1;
7064 }
7065
7066 if (edge)
7067 kloc = 0.5 * edge;
7068 else
7069 {
7070 kr = [self convertRect: [self rectForPart: NSScrollerKnob]
7071 toView: nil];
7072 kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
7073 }
7074 last_mouse_offset = kloc;
7075
7076 /* if knob, tell emacs a location offset by knob pos
7077 (to indicate top of handle) */
7078 if (part == NSScrollerKnob)
7079 pos = (loc - last_mouse_offset) / NSHeight (sr);
7080 else
7081 /* else this is a slot click on GNUstep: go straight there */
7082 pos = loc / NSHeight (sr);
7083
7084 /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
7085 fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
7086 location: [e locationInWindow]
7087 modifierFlags: [e modifierFlags]
7088 timestamp: [e timestamp]
7089 windowNumber: [e windowNumber]
7090 context: [e context]
7091 eventNumber: [e eventNumber]
7092 clickCount: [e clickCount]
7093 pressure: [e pressure]];
7094 [super mouseUp: fake_event];
7095 }
7096
7097 if (part != NSScrollerKnob)
7098 [self sendScrollEventAtLoc: pos fromEvent: e];
7099}
7100
7101
7102/* Called as we manually track scroller drags, rather than superclass. */
7103- (void)mouseDragged: (NSEvent *)e
7104{
7105 NSRect sr;
7106 double loc, pos;
7107 int edge = 0;
7108
7109 NSTRACE (EmacsScroller_mouseDragged);
7110
7111 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7112 toView: nil];
7113 loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7114
7115 if (loc <= 0.0)
7116 {
7117 loc = 0.0;
7118 edge = -1;
7119 }
7120 else if (loc >= NSHeight (sr) + last_mouse_offset)
7121 {
7122 loc = NSHeight (sr) + last_mouse_offset;
7123 edge = 1;
7124 }
7125
7126 pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
7127 [self sendScrollEventAtLoc: pos fromEvent: e];
7128}
7129
7130
7131- (void)mouseUp: (NSEvent *)e
7132{
7133 if (scroll_repeat_entry)
7134 {
7135 [scroll_repeat_entry invalidate];
7136 [scroll_repeat_entry release];
7137 scroll_repeat_entry = nil;
7138 }
7139 last_hit_part = 0;
7140}
7141
7142
7143/* treat scrollwheel events in the bar as though they were in the main window */
7144- (void) scrollWheel: (NSEvent *)theEvent
7145{
7146 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
7147 [view mouseDown: theEvent];
7148}
7149
7150@end /* EmacsScroller */
7151
7152
7153
edfda783
AR
7154
7155/* ==========================================================================
7156
7157 Font-related functions; these used to be in nsfaces.m
7158
7159 ========================================================================== */
7160
7161
7162Lisp_Object
7163x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
7164{
7165 struct font *font = XFONT_OBJECT (font_object);
7166
7167 if (fontset < 0)
7168 fontset = fontset_from_font (font_object);
7169 FRAME_FONTSET (f) = fontset;
7170
7171 if (FRAME_FONT (f) == font)
7172 /* This font is already set in frame F. There's nothing more to
7173 do. */
7174 return font_object;
7175
7176 FRAME_FONT (f) = font;
7177
7178 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
7179 FRAME_COLUMN_WIDTH (f) = font->average_width;
edfda783
AR
7180 FRAME_LINE_HEIGHT (f) = font->height;
7181
7182 compute_fringe_widths (f, 1);
7183
7184 /* Compute the scroll bar width in character columns. */
7185 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
7186 {
7187 int wid = FRAME_COLUMN_WIDTH (f);
7188 FRAME_CONFIG_SCROLL_BAR_COLS (f)
7189 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
7190 }
7191 else
7192 {
7193 int wid = FRAME_COLUMN_WIDTH (f);
7194 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
7195 }
7196
7197 /* Now make the frame display the given font. */
7198 if (FRAME_NS_WINDOW (f) != 0)
7199 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
7200
7201 return font_object;
7202}
7203
7204
edfda783 7205/* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
35ed44db
AR
7206/* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
7207 in 1.43. */
edfda783
AR
7208
7209const char *
7210ns_xlfd_to_fontname (const char *xlfd)
7211/* --------------------------------------------------------------------------
7212 Convert an X font name (XLFD) to an NS font name.
7213 Only family is used.
7214 The string returned is temporarily allocated.
7215 -------------------------------------------------------------------------- */
7216{
7217 char *name = xmalloc (180);
7218 int i, len;
7219 const char *ret;
e2749141 7220
edfda783
AR
7221 if (!strncmp (xlfd, "--", 2))
7222 sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7223 else
7224 sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7225
7226 /* stopgap for malformed XLFD input */
7227 if (strlen (name) == 0)
7228 strcpy (name, "Monaco");
7229
7230 /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7231 also uppercase after '-' or ' ' */
620f13b0 7232 name[0] = c_toupper (name[0]);
edfda783
AR
7233 for (len =strlen (name), i =0; i<len; i++)
7234 {
7235 if (name[i] == '$')
7236 {
7237 name[i] = '-';
7238 if (i+1<len)
620f13b0 7239 name[i+1] = c_toupper (name[i+1]);
edfda783
AR
7240 }
7241 else if (name[i] == '_')
7242 {
7243 name[i] = ' ';
7244 if (i+1<len)
620f13b0 7245 name[i+1] = c_toupper (name[i+1]);
edfda783
AR
7246 }
7247 }
7248/*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name); */
7249 ret = [[NSString stringWithUTF8String: name] UTF8String];
7250 xfree (name);
7251 return ret;
7252}
0ae1e5e5 7253
15034960 7254
1baa6236 7255void
3d608a86 7256syms_of_nsterm (void)
1baa6236
DN
7257{
7258 NSTRACE (syms_of_nsterm);
e5a29a10
CY
7259
7260 ns_antialias_threshold = 10.0;
7261
4d03ece0 7262 /* from 23+ we need to tell emacs what modifiers there are.. */
652fcc71
CY
7263 DEFSYM (Qmodifier_value, "modifier-value");
7264 DEFSYM (Qalt, "alt");
7265 DEFSYM (Qhyper, "hyper");
7266 DEFSYM (Qmeta, "meta");
7267 DEFSYM (Qsuper, "super");
7268 DEFSYM (Qcontrol, "control");
699c10bd
JD
7269 DEFSYM (QUTF8_STRING, "UTF8_STRING");
7270
4d03ece0 7271 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
4d03ece0 7272 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
4d03ece0 7273 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
4d03ece0 7274 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
4d03ece0
CY
7275 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7276
fb9d0f5a 7277 DEFVAR_LISP ("ns-input-file", ns_input_file,
1baa6236
DN
7278 "The file specified in the last NS event.");
7279 ns_input_file =Qnil;
7280
fb9d0f5a 7281 DEFVAR_LISP ("ns-input-text", ns_input_text,
1baa6236
DN
7282 "The data received in the last NS text drag event.");
7283 ns_input_text =Qnil;
7284
fb9d0f5a 7285 DEFVAR_LISP ("ns-working-text", ns_working_text,
1baa6236
DN
7286 "String for visualizing working composition sequence.");
7287 ns_working_text =Qnil;
7288
fb9d0f5a 7289 DEFVAR_LISP ("ns-input-font", ns_input_font,
1baa6236
DN
7290 "The font specified in the last NS event.");
7291 ns_input_font =Qnil;
7292
fb9d0f5a 7293 DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
1baa6236
DN
7294 "The fontsize specified in the last NS event.");
7295 ns_input_fontsize =Qnil;
7296
fb9d0f5a 7297 DEFVAR_LISP ("ns-input-line", ns_input_line,
1baa6236
DN
7298 "The line specified in the last NS event.");
7299 ns_input_line =Qnil;
7300
fb9d0f5a 7301 DEFVAR_LISP ("ns-input-color", ns_input_color,
1baa6236
DN
7302 "The color specified in the last NS event.");
7303 ns_input_color =Qnil;
7304
fb9d0f5a 7305 DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
1baa6236
DN
7306 "The service name specified in the last NS event.");
7307 ns_input_spi_name =Qnil;
7308
fb9d0f5a 7309 DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
1baa6236
DN
7310 "The service argument specified in the last NS event.");
7311 ns_input_spi_arg =Qnil;
7312
fb9d0f5a 7313 DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
1baa6236
DN
7314 "This variable describes the behavior of the alternate or option key.\n\
7315Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7316Set to none means that the alternate / option key is not interpreted by Emacs\n\
7317at all, allowing it to be used at a lower level for accented character entry.");
e5a29a10 7318 ns_alternate_modifier = Qmeta;
1baa6236 7319
fb9d0f5a 7320 DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
a2e35ef5
JD
7321 "This variable describes the behavior of the right alternate or option key.\n\
7322Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7323Set to left means be the same key as `ns-alternate-modifier'.\n\
7324Set to none means that the alternate / option key is not interpreted by Emacs\n\
7325at all, allowing it to be used at a lower level for accented character entry.");
7326 ns_right_alternate_modifier = Qleft;
7327
fb9d0f5a 7328 DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
1baa6236
DN
7329 "This variable describes the behavior of the command key.\n\
7330Set to control, meta, alt, super, or hyper means it is taken to be that key.");
e5a29a10 7331 ns_command_modifier = Qsuper;
1baa6236 7332
fb9d0f5a 7333 DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
b7d1e144
JD
7334 "This variable describes the behavior of the right command key.\n\
7335Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7336Set to left means be the same key as `ns-command-modifier'.\n\
7337Set to none means that the command / option key is not interpreted by Emacs\n\
7338at all, allowing it to be used at a lower level for accented character entry.");
7339 ns_right_command_modifier = Qleft;
7340
fb9d0f5a 7341 DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
1baa6236
DN
7342 "This variable describes the behavior of the control key.\n\
7343Set to control, meta, alt, super, or hyper means it is taken to be that key.");
e5a29a10 7344 ns_control_modifier = Qcontrol;
1baa6236 7345
fb9d0f5a 7346 DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
b7d1e144
JD
7347 "This variable describes the behavior of the right control key.\n\
7348Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7349Set to left means be the same key as `ns-control-modifier'.\n\
7350Set to none means that the control / option key is not interpreted by Emacs\n\
7351at all, allowing it to be used at a lower level for accented character entry.");
7352 ns_right_control_modifier = Qleft;
7353
fb9d0f5a 7354 DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
1baa6236
DN
7355 "This variable describes the behavior of the function key (on laptops).\n\
7356Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7357Set to none means that the function key is not interpreted by Emacs at all,\n\
7358allowing it to be used at a lower level for accented character entry.");
e5a29a10 7359 ns_function_modifier = Qnone;
1baa6236 7360
fb9d0f5a 7361 DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
335f5ae4 7362 "Non-nil (the default) means to render text antialiased.");
e5a29a10 7363 ns_antialias_text = Qt;
1baa6236 7364
fb9d0f5a 7365 DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
fc7a54a9 7366 "Whether to confirm application quit using dialog.");
e5a29a10 7367 ns_confirm_quit = Qnil;
fc7a54a9 7368
1baa6236
DN
7369 staticpro (&ns_display_name_list);
7370 ns_display_name_list = Qnil;
7371
7372 staticpro (&last_mouse_motion_frame);
7373 last_mouse_motion_frame = Qnil;
7374
f0a1382a 7375 DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
5ffb62aa
JD
7376 doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7377Only works on OSX 10.6 or later. */);
f0a1382a
JD
7378 ns_auto_hide_menu_bar = Qnil;
7379
6871e574
JD
7380 DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
7381 doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
7382Nil means use fullscreen the old (< 10.7) way. The old way works better with
7383multiple monitors, but lacks tool bar. This variable is ignored on OSX < 10.7.
7384Default is t for OSX >= 10.7, nil otherwise. */);
7385#ifdef HAVE_NATIVE_FS
7386 ns_use_native_fullscreen = YES;
7387#else
7388 ns_use_native_fullscreen = NO;
7389#endif
7390 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
7391
7ded3383 7392 /* TODO: move to common code */
fb9d0f5a 7393 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
97897668
GM
7394 doc: /* Which toolkit scroll bars Emacs uses, if any.
7395A value of nil means Emacs doesn't use toolkit scroll bars.
7396With the X Window system, the value is a symbol describing the
7397X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
44f92739 7398With MS Windows or Nextstep, the value is t. */);
1baa6236 7399 Vx_toolkit_scroll_bars = Qt;
1baa6236 7400
1baa6236 7401 DEFVAR_BOOL ("x-use-underline-position-properties",
fb9d0f5a 7402 x_use_underline_position_properties,
4843aac3 7403 doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
1baa6236
DN
7404A value of nil means ignore them. If you encounter fonts with bogus
7405UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
4843aac3 7406to 4.1, set this to nil. */);
1baa6236
DN
7407 x_use_underline_position_properties = 0;
7408
7409 DEFVAR_BOOL ("x-underline-at-descent-line",
fb9d0f5a 7410 x_underline_at_descent_line,
4843aac3 7411 doc: /* Non-nil means to draw the underline at the same place as the descent line.
1baa6236
DN
7412A value of nil means to draw the underline according to the value of the
7413variable `x-use-underline-position-properties', which is usually at the
7414baseline level. The default value is nil. */);
7415 x_underline_at_descent_line = 0;
7416
7417 /* Tell emacs about this window system. */
7c799cf5 7418 Fprovide (intern ("ns"), Qnil);
1baa6236 7419}