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