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