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