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