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