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