[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] Changes to src/nsterm.m
From: |
Adrian Robert |
Subject: |
[Emacs-diffs] Changes to src/nsterm.m |
Date: |
Tue, 15 Jul 2008 18:16:08 +0000 |
CVSROOT: /sources/emacs
Module name: emacs
Changes by: Adrian Robert <arobert> 08/07/15 18:15:19
Index: src/nsterm.m
===================================================================
RCS file: src/nsterm.m
diff -N src/nsterm.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/nsterm.m 15 Jul 2008 18:15:16 -0000 1.1
@@ -0,0 +1,6598 @@
+/* NeXT/Open/GNUstep / MacOSX communication module.
+ Copyright (C) 1989, 1993, 1994, 2005, 2006, 2008,
+ Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.
+
+Originally by Carl Edman
+Updated by Christian Limpach (address@hidden)
+OpenStep/Rhapsody port by Scott Bender (address@hidden)
+MacOSX/Aqua port by Christophe de Dinechin (address@hidden)
+GNUstep port and post-20 update by Adrian Robert (address@hidden)
+*/
+
+#include <math.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "lisp.h"
+#include "blockinput.h"
+#include "sysselect.h"
+#include "nsterm.h"
+#include "systime.h"
+#include "character.h"
+#include "fontset.h"
+#include "composite.h"
+#include "ccl.h"
+
+#include "termhooks.h"
+#include "termopts.h"
+#include "termchar.h"
+
+#include "window.h"
+#include "keyboard.h"
+
+#include "font.h"
+
+/* call tracing */
+#if 0
+int term_trace_num = 0;
+#define NSTRACE(x) fprintf (stderr, "%s:%d: [%d] " #x "\n", \
+ __FILE__, __LINE__, ++term_trace_num)
+#else
+#define NSTRACE(x)
+#endif
+
+
+/* ==========================================================================
+
+ Local declarations
+
+ ==========================================================================
*/
+
+/* Special keycodes that we pass down the event chain */
+#define KEY_NS_POWER_OFF ((1<<28)|(0<<16)|1)
+#define KEY_NS_OPEN_FILE ((1<<28)|(0<<16)|2)
+#define KEY_NS_OPEN_TEMP_FILE ((1<<28)|(0<<16)|3)
+#define KEY_NS_DRAG_FILE ((1<<28)|(0<<16)|4)
+#define KEY_NS_DRAG_COLOR ((1<<28)|(0<<16)|5)
+#define KEY_NS_DRAG_TEXT ((1<<28)|(0<<16)|6)
+#define KEY_NS_CHANGE_FONT ((1<<28)|(0<<16)|7)
+#define KEY_NS_OPEN_FILE_LINE ((1<<28)|(0<<16)|8)
+#define KEY_NS_INSERT_WORKING_TEXT ((1<<28)|(0<<16)|9)
+#define KEY_NS_DELETE_WORKING_TEXT ((1<<28)|(0<<16)|10)
+#define KEY_NS_SPI_SERVICE_CALL ((1<<28)|(0<<16)|11)
+
+/* Convert a symbol indexed with an NSxxx value to a value as defined
+ in keyboard.c (lispy_function_key). I hope this is a correct way
+ of doing things... */
+static unsigned convert_ns_to_X_keysym[] =
+{
+ NSHomeFunctionKey, 0x50,
+ NSLeftArrowFunctionKey, 0x51,
+ NSUpArrowFunctionKey, 0x52,
+ NSRightArrowFunctionKey, 0x53,
+ NSDownArrowFunctionKey, 0x54,
+ NSPageUpFunctionKey, 0x55,
+ NSPageDownFunctionKey, 0x56,
+ NSEndFunctionKey, 0x57,
+ NSBeginFunctionKey, 0x58,
+ NSSelectFunctionKey, 0x60,
+ NSPrintFunctionKey, 0x61,
+ NSExecuteFunctionKey, 0x62,
+ NSInsertFunctionKey, 0x63,
+ NSUndoFunctionKey, 0x65,
+ NSRedoFunctionKey, 0x66,
+ NSMenuFunctionKey, 0x67,
+ NSFindFunctionKey, 0x68,
+ NSHelpFunctionKey, 0x6A,
+ NSBreakFunctionKey, 0x6B,
+
+ NSF1FunctionKey, 0xBE,
+ NSF2FunctionKey, 0xBF,
+ NSF3FunctionKey, 0xC0,
+ NSF4FunctionKey, 0xC1,
+ NSF5FunctionKey, 0xC2,
+ NSF6FunctionKey, 0xC3,
+ NSF7FunctionKey, 0xC4,
+ NSF8FunctionKey, 0xC5,
+ NSF9FunctionKey, 0xC6,
+ NSF10FunctionKey, 0xC7,
+ NSF11FunctionKey, 0xC8,
+ NSF12FunctionKey, 0xC9,
+ NSF13FunctionKey, 0xCA,
+ NSF14FunctionKey, 0xCB,
+ NSF15FunctionKey, 0xCC,
+
+ NSBackspaceCharacter, 0x08, /* 8: Not on some KBs. */
+ NSDeleteCharacter, 0xFF, /* 127: Big 'delete' key upper right. */
+ NSDeleteFunctionKey, 0x9F, /* 63272: Del forw key off main array.
*/
+
+ NSTabCharacter, 0x09,
+ 0x19, 0x09, /* left tab->regular since pass
shift */
+ NSCarriageReturnCharacter, 0x0D,
+ NSNewlineCharacter, 0x0D,
+ NSEnterCharacter, 0x8D,
+
+ 0x1B, 0x1B /* escape */
+};
+
+
+/* Lisp communications */
+Lisp_Object ns_input_file, ns_input_font, ns_input_fontsize, ns_input_line;
+Lisp_Object ns_input_color, ns_input_text, ns_working_text;
+Lisp_Object ns_input_spi_name, ns_input_spi_arg;
+Lisp_Object Vx_toolkit_scroll_bars;
+static Lisp_Object Qmodifier_value;
+/*PENDING: unsure why these defined in term files, anyway we need in keymap.c
*/
+Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper;
+extern Lisp_Object Qcursor_color, Qcursor_type, Qns;
+extern int lisp_to_mod (Lisp_Object lmod);
+
+
+EmacsPrefsController *prefsController;
+
+/* Defaults managed through the OpenStep defaults system. These pertain to
+ the NS interface specifically. Although a customization group could be
+ created, it's more natural to manage them via defaults. */
+
+/* Specifies which emacs modifier should be generated when NS receives
+ the Alternate modifer. May be Qnone or any of the modifier lisp symbols. */
+Lisp_Object ns_alternate_modifier;
+
+/* Specifies which emacs modifier should be generated when NS receives
+ the Command modifer. May be any of the modifier lisp symbols. */
+Lisp_Object ns_command_modifier;
+
+/* Specifies which emacs modifier should be generated when NS receives
+ the Control modifer. May be any of the modifier lisp symbols. */
+Lisp_Object ns_control_modifier;
+
+/* Specifies which emacs modifier should be generated when NS receives
+ the Function modifer (laptops). May be any of the modifier lisp symbols. */
+Lisp_Object ns_function_modifier;
+
+/* A floating point value specifying the rate at which to blink the cursor.
+ YES indicates 0.5, NO indicates no blinking. */
+Lisp_Object ns_cursor_blink_rate;
+
+/* Used for liason with core emacs cursor-blink-mode. */
+Lisp_Object ns_cursor_blink_mode;
+
+/* A floating point value specifying vertical stretch (positive) or shrink
+ (negative) of text line spacing. Zero means default spacing.
+ YES indicates 0.5, NO indicates 0.0. */
+Lisp_Object ns_expand_space;
+
+/* Control via default 'GSFontAntiAlias' on OS X and GNUstep. */
+int ns_antialias_text;
+
+/* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
+ the maximum font size to NOT antialias. On GNUstep there is currently
+ no way to control this behavior. */
+float ns_antialias_threshold;
+
+/* Controls use of an undocumented CG function to do Quickdraw-style font
+ smoothing (less heavy) instead of regular Quartz smoothing. */
+int ns_use_qd_smoothing;
+
+/* Used to pick up AppleHighlightColor on OS X */
+int ns_use_system_highlight_color;
+NSString *ns_selection_color;
+
+
+NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
+
+/* Display variables */
+struct ns_display_info *ns_display_list; /* Chain of existing displays */
+Lisp_Object ns_display_name_list;
+long context_menu_value = 0;
+
+/* display update */
+NSPoint last_mouse_motion_position;
+static NSRect last_mouse_glyph;
+static unsigned long last_mouse_movement_time = 0;
+static Lisp_Object last_mouse_motion_frame;
+static EmacsScroller *last_mouse_scroll_bar = nil;
+static struct frame *ns_updating_frame;
+static NSView *focus_view = NULL;
+static int ns_window_num =0;
+static NSRect uRect;
+static BOOL gsaved = NO;
+BOOL ns_in_resize = NO;
+int ns_tmp_flags; /*PENDING */
+struct nsfont_info *ns_tmp_font; /*PENDING */
+/*static int debug_lock = 0; */
+
+#ifdef NS_IMPL_COCOA
+/* This undocumented Quartz function controls how fonts are anti-aliased.
+ (Found from code in Mac wxWindows impl, discovered by running `nm' on
+ the "QD" framework.)
+ Mode 0 is normal anti-aliasing, mode 1 is no anti-aliasing, and mode 2 is
+ 4-bit pixel-aligned anti-aliasing (the old QuickDraw standard). */
+extern void CGContextSetFontRenderingMode (CGContextRef cg, int v);
+#endif
+
+
+/* event loop */
+static BOOL send_appdefined = YES;
+static NSEvent *last_appdefined_event = 0;
+static NSTimer *timed_entry = 0;
+static NSTimer *fd_entry = nil;
+static NSTimer *cursor_blink_entry = nil;
+static NSTimer *scroll_repeat_entry = nil;
+static fd_set select_readfds, t_readfds;
+static struct timeval select_timeout;
+static int select_nfds;
+static NSAutoreleasePool *outerpool;
+static BOOL ns_shutdown_properly = NO;
+static struct input_event *emacs_event = NULL;
+static struct input_event *q_event_ptr = NULL;
+static int n_emacs_events_pending = 0;
+static NSMutableArray *ns_pending_files, *ns_pending_service_names,
+ *ns_pending_service_args;
+static BOOL inNsSelect = 0;
+
+/* Convert modifiers in a NeXTSTEP event to emacs style modifiers. */
+#define NS_FUNCTION_KEY_MASK 0x800000
+#define EV_MODIFIERS(e) \
+ ((([e modifierFlags] & NSHelpKeyMask) ? \
+ hyper_modifier : 0) \
+ | (([e modifierFlags] & NSAlternateKeyMask) ? \
+ lisp_to_mod (ns_alternate_modifier) : 0) \
+ | (([e modifierFlags] & NSShiftKeyMask) ? \
+ shift_modifier : 0) \
+ | (([e modifierFlags] & NSControlKeyMask) ? \
+ lisp_to_mod (ns_control_modifier) : 0) \
+ | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ? \
+ lisp_to_mod (ns_function_modifier) : 0) \
+ | (([e modifierFlags] & NSCommandKeyMask) ? \
+ lisp_to_mod (ns_command_modifier):0))
+
+#define EV_UDMODIFIERS(e) \
+ ((([e type] == NSLeftMouseDown) ? down_modifier : 0) \
+ | (([e type] == NSRightMouseDown) ? down_modifier : 0) \
+ | (([e type] == NSLeftMouseDragged) ? down_modifier : 0) \
+ | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
+ | (([e type] == NSLeftMouseUp) ? up_modifier : 0) \
+ | (([e type] == NSRightMouseUp) ? up_modifier : 0))
+
+#define EV_BUTTON(e) \
+ ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 : \
+ (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : 1)
+
+/* Convert the time field to a timestamp in milliseconds. */
+#ifdef NS_IMPL_GNUSTEP
+/* Apple says timestamp is in seconds, but GNUstep seems to be returning msec
*/
+#define EV_TIMESTAMP(e) ([e timestamp])
+#else
+#define EV_TIMESTAMP(e) ([e timestamp] * 1000)
+#endif /* not gnustep */
+
+/* This is a piece of code which is common to all the event handling
+ methods. Maybe it should even be a function. */
+#define EV_TRAILER(e) \
+ { \
+ XSETFRAME (emacs_event->frame_or_window, [NSApp isActive] ? \
+ emacsframe : SELECTED_FRAME ()); \
+ if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \
+ n_emacs_events_pending++; \
+ kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \
+ EVENT_INIT (*emacs_event); \
+ ns_send_appdefined (-1); \
+ }
+
+/*PENDING: get rid of need for these forward declarations */
+static void ns_condemn_scroll_bars (struct frame *f),
+ ns_judge_scroll_bars (struct frame *f);
+
+/* unused variables needed for compatibility reasons */
+int x_use_underline_position_properties, x_underline_at_descent_line;
+/* PENDING: figure out what to do with underline_minimum_offset. */
+
+
+/* ==========================================================================
+
+ Utilities
+
+ ==========================================================================
*/
+
+
+static Lisp_Object
+append2 (Lisp_Object list, Lisp_Object item)
+/* --------------------------------------------------------------------------
+ Utility to append to a list
+ --------------------------------------------------------------------------
*/
+{
+ Lisp_Object array[2];
+ array[0] = list;
+ array[1] = Fcons (item, Qnil);
+ return Fnconc (2, &array[0]);
+}
+
+
+void
+ns_init_paths ()
+/* --------------------------------------------------------------------------
+ Used to allow emacs to find its resources under Emacs.app
+ Called from emacs.c at startup.
+ --------------------------------------------------------------------------
*/
+{
+ NSBundle *bundle = [NSBundle mainBundle];
+ NSString *binDir = [bundle bundlePath], *resourceDir = [bundle resourcePath];
+ NSString *resourcePath, *resourcePaths;
+ NSRange range;
+ BOOL onWindows = NO; /* how do I determine this? */
+ NSString *pathSeparator = onWindows ? @";" : @":";
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ BOOL isDir;
+/*NSLog (@"ns_init_paths: '%@'address@hidden", [[NSBundle mainBundle]
bundlePath], [[NSBundle mainBundle] resourcePath]); */
+
+ /* get bindir from base */
+ range = [resourceDir rangeOfString: @"Contents"];
+ if (range.location != NSNotFound)
+ {
+ binDir = [binDir stringByAppendingPathComponent: @"Contents"];
+#ifdef NS_IMPL_COCOA
+ binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
+#endif
+ }
+
+ /* the following based on Andrew Choi's init_mac_osx_environment () */
+ if (!getenv ("EMACSLOADPATH"))
+ {
+ NSArray *paths = [resourceDir stringsByAppendingPaths:
+ [NSArray arrayWithObjects:
+ @"site-lisp", @"lisp", @"leim", nil]];
+ NSEnumerator *pathEnum = [paths objectEnumerator];
+ resourcePaths = @"";
+ while (resourcePath = [pathEnum nextObject])
+ {
+ if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
+ if (isDir)
+ {
+ if ([resourcePaths length] > 0)
+ resourcePaths =
+ [resourcePaths stringByAppendingString: pathSeparator];
+ resourcePaths =
+ [resourcePaths stringByAppendingString: resourcePath];
+ }
+ }
+ if ([resourcePaths length] > 0)
+ setenv ("EMACSLOADPATH", [resourcePaths UTF8String], 1);
+/*NSLog (@"loadPath: '%s'\n", resourcePaths); */
+ }
+
+ if (!getenv ("EMACSPATH"))
+ {
+ NSArray *paths = [binDir stringsByAppendingPaths:
+ [NSArray arrayWithObjects: @"bin",
+ @"lib-exec",
nil]];
+ NSEnumerator *pathEnum = [paths objectEnumerator];
+ resourcePaths = @"";
+ while (resourcePath = [pathEnum nextObject])
+ {
+ if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
+ if (isDir)
+ {
+ if ([resourcePaths length] > 0)
+ resourcePaths =
+ [resourcePaths stringByAppendingString: pathSeparator];
+ resourcePaths =
+ [resourcePaths stringByAppendingString: resourcePath];
+ }
+ }
+ if ([resourcePaths length] > 0)
+ setenv ("EMACSPATH", [resourcePaths UTF8String], 1);
+ }
+
+ resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
+ if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
+ {
+ if (isDir)
+ {
+ if (!getenv ("EMACSDATA"))
+ setenv ("EMACSDATA", [resourcePath UTF8String], 1);
+ if (!getenv ("EMACSDOC"))
+ setenv ("EMACSDOC", [resourcePath UTF8String], 1);
+ }
+ }
+
+ /*PENDING: append to INFOPATH... */
+ if (!getenv ("INFOPATH"))
+ {
+ resourcePath = [resourceDir stringByAppendingPathComponent: @"info"];
+ if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
+ if (isDir)
+ setenv ("INFOPATH", [resourcePath UTF8String], 1);
+ }
+}
+
+
+static int
+timeval_subtract (struct timeval *result, struct timeval x, struct timeval y)
+/* --------------------------------------------------------------------------
+ Subtract the `struct timeval' values X and Y, storing the result in RESULT.
+ Return 1 if the difference is negative, otherwise 0.
+ --------------------------------------------------------------------------
*/
+{
+ /* Perform the carry for the later subtraction by updating y.
+ This is safer because on some systems
+ the tv_sec member is unsigned. */
+ if (x.tv_usec < y.tv_usec)
+ {
+ int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
+ y.tv_usec -= 1000000 * nsec;
+ y.tv_sec += nsec;
+ }
+ if (x.tv_usec - y.tv_usec > 1000000)
+ {
+ int nsec = (y.tv_usec - x.tv_usec) / 1000000;
+ y.tv_usec += 1000000 * nsec;
+ y.tv_sec -= nsec;
+ }
+
+ /* Compute the time remaining to wait. tv_usec is certainly positive. */
+ result->tv_sec = x.tv_sec - y.tv_sec;
+ result->tv_usec = x.tv_usec - y.tv_usec;
+
+ /* Return indication of whether the result should be considered negative. */
+ return x.tv_sec < y.tv_sec;
+}
+
+static void
+ns_timeout (int usecs)
+/* --------------------------------------------------------------------------
+ Blocking timer utility used by ns_ring_bell
+ --------------------------------------------------------------------------
*/
+{
+ struct timeval wakeup;
+
+ EMACS_GET_TIME (wakeup);
+
+ /* Compute time to wait until, propagating carry from usecs. */
+ wakeup.tv_usec += usecs;
+ wakeup.tv_sec += (wakeup.tv_usec / 1000000);
+ wakeup.tv_usec %= 1000000;
+
+ /* Keep waiting until past the time wakeup. */
+ while (1)
+ {
+ struct timeval timeout;
+
+ EMACS_GET_TIME (timeout);
+
+ /* In effect, timeout = wakeup - timeout.
+ Break if result would be negative. */
+ if (timeval_subtract (&timeout, wakeup, timeout))
+ break;
+
+ /* Try to wait that long--but we might wake up sooner. */
+ select (0, NULL, NULL, NULL, &timeout);
+ }
+}
+
+
+void
+ns_release_object (void *obj)
+/* --------------------------------------------------------------------------
+ Release an object (callable from C)
+ --------------------------------------------------------------------------
*/
+{
+ [(id)obj release];
+}
+
+
+void
+ns_retain_object (void *obj)
+/* --------------------------------------------------------------------------
+ Retain an object (callable from C)
+ --------------------------------------------------------------------------
*/
+{
+ [(id)obj retain];
+}
+
+
+void *
+ns_alloc_autorelease_pool ()
+/* --------------------------------------------------------------------------
+ Allocate a pool for temporary objects (callable from C)
+ --------------------------------------------------------------------------
*/
+{
+ return [[NSAutoreleasePool alloc] init];
+}
+
+
+void
+ns_release_autorelease_pool (void *pool)
+/* --------------------------------------------------------------------------
+ Free a pool and temporary objects it refers to (callable from C)
+ --------------------------------------------------------------------------
*/
+{
+ ns_release_object (pool);
+}
+
+
+
+/* ==========================================================================
+
+ Focus (clipping) and screen update
+
+ ==========================================================================
*/
+
+static NSRect
+ns_resize_handle_rect (NSWindow *window)
+{
+ NSRect r = [window frame];
+ r.origin.x = r.size.width - RESIZE_HANDLE_SIZE;
+ r.origin.y = 0;
+ r.size.width = r.size.height = RESIZE_HANDLE_SIZE;
+ return r;
+}
+
+
+static void
+ns_update_begin (struct frame *f)
+/* --------------------------------------------------------------------------
+ Prepare for a grouped sequence of drawing calls
+ 23: external (RIF) call; now split w/ and called before update_window_begin
+ --------------------------------------------------------------------------
*/
+{
+ NSView *view = FRAME_NS_VIEW (f);
+ NSTRACE (ns_update_begin);
+/*fprintf (stderr, "\\%p\n", f); */
+
+ ns_updating_frame = f;
+ [view lockFocus];
+
+#ifdef NS_IMPL_GNUSTEP
+ uRect = NSMakeRect (0, 0, 0, 0);
+#endif
+}
+
+
+static void
+ns_update_window_begin (struct window *w)
+/* --------------------------------------------------------------------------
+ Prepare for a grouped sequence of drawing calls
+ 23: external (RIF) call; now split with and called after update_begin
+ --------------------------------------------------------------------------
*/
+{
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+ struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
+ NSTRACE (ns_update_window_begin);
+
+ updated_window = w;
+ set_output_cursor (&w->cursor);
+
+ BLOCK_INPUT;
+
+ if (f == dpyinfo->mouse_face_mouse_frame)
+ {
+ /* Don't do highlighting for mouse motion during the update. */
+ dpyinfo->mouse_face_defer = 1;
+
+ /* If the frame needs to be redrawn,
+ simply forget about any prior mouse highlighting. */
+ if (FRAME_GARBAGED_P (f))
+ dpyinfo->mouse_face_window = Qnil;
+
+ /* (further code for mouse faces ifdef'd out in other terms elided) */
+ }
+
+ UNBLOCK_INPUT;
+}
+
+
+static void
+ns_update_window_end (struct window *w, int cursor_on_p,
+ int mouse_face_overwritten_p)
+/* --------------------------------------------------------------------------
+ Finished a grouped sequence of drawing calls
+ 23: external (RIF) call; now split with and called before update_window_end
+ --------------------------------------------------------------------------
*/
+{
+ struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (XFRAME (w->frame));
+
+ /* note: this fn is nearly identical in all terms */
+ if (!w->pseudo_window_p)
+ {
+ BLOCK_INPUT;
+
+ if (cursor_on_p)
+ display_and_set_cursor (w, 1,
+ output_cursor.hpos, output_cursor.vpos,
+ output_cursor.x, output_cursor.y);
+
+ if (draw_window_fringes (w, 1))
+ x_draw_vertical_border (w);
+
+ UNBLOCK_INPUT;
+ }
+
+ /* If a row with mouse-face was overwritten, arrange for
+ frame_up_to_date to redisplay the mouse highlight. */
+ if (mouse_face_overwritten_p)
+ {
+ dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
+ dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
+ dpyinfo->mouse_face_window = Qnil;
+ }
+
+ updated_window = NULL;
+ NSTRACE (update_window_end);
+}
+
+
+static void
+ns_update_end (struct frame *f)
+/* --------------------------------------------------------------------------
+ Finished a grouped sequence of drawing calls
+ 23: external (RIF) call; now split with and called after update_window_end
+ --------------------------------------------------------------------------
*/
+{
+ NSView *view = FRAME_NS_VIEW (f);
+
+/* if (f == FRAME_NS_DISPLAY_INFO (f)->mouse_face_mouse_frame) */
+ FRAME_NS_DISPLAY_INFO (f)->mouse_face_defer = 0;
+
+ BLOCK_INPUT;
+
+#ifdef NS_IMPL_GNUSTEP
+ /* trigger flush only in the rectangle we tracked as being drawn */
+ [view unlockFocusNeedsFlush: NO];
+/*fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", uRect.origin.x,
uRect.origin.y, uRect.size.width, uRect.size.height); */
+ [view lockFocusInRect: uRect];
+#endif
+
+ [view unlockFocus];
+ [[view window] flushWindow];
+
+ UNBLOCK_INPUT;
+ ns_updating_frame = NULL;
+ NSTRACE (ns_update_end);
+}
+
+
+static void
+ns_flush (struct frame *f)
+/* --------------------------------------------------------------------------
+ 23: external (RIF) call
+ NS impl is no-op since currently we flush in ns_update_end and elsewhere
+ --------------------------------------------------------------------------
*/
+{
+ NSTRACE (ns_flush);
+}
+
+
+static void
+ns_focus (struct frame *f, NSRect *r, int n)
+/* --------------------------------------------------------------------------
+ Internal: Focus on given frame. During small local updates this is used to
+ draw, however during large updates, ns_update_begin and ns_update_end are
+ called to wrap the whole thing, in which case these calls are stubbed out.
+ Except, on GNUstep, we accumulate the rectangle being drawn into, because
+ the back end won't do this automatically, and will just end up flushing
+ the entire window.
+ --------------------------------------------------------------------------
*/
+{
+ NSTRACE (ns_focus);
+#ifdef NS_IMPL_GNUSTEP
+ NSRect u;
+ if (n == 2)
+ u = NSUnionRect (r[0], r[1]);
+ else if (r)
+ u = *r;
+#endif
+/* static int c =0;
+ fprintf (stderr, "focus: %d", c++);
+ if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x,
r->origin.y, r->size.width, r->size.height);
+ fprintf (stderr, "\n"); */
+
+ if (f != ns_updating_frame)
+ {
+ NSView *view = FRAME_NS_VIEW (f);
+ if (view != focus_view)
+ {
+ if (focus_view != NULL)
+ {
+ [focus_view unlockFocus];
+ [[focus_view window] flushWindow];
+/*debug_lock--; */
+ }
+
+ if (view)
+#ifdef NS_IMPL_GNUSTEP
+ r ? [view lockFocusInRect: u] : [view lockFocus];
+#else
+ [view lockFocus];
+#endif
+ focus_view = view;
+/*if (view) debug_lock++; */
+ }
+#ifdef NS_IMPL_GNUSTEP
+ else
+ {
+ /* more than one rect being drawn into */
+ if (view && r)
+ {
+ [view unlockFocus]; /* add prev rect to redraw list */
+ [view lockFocusInRect: u]; /* focus for draw in new rect */
+ }
+ }
+#endif
+ }
+#ifdef NS_IMPL_GNUSTEP
+ else
+ {
+ /* in batch mode, but in GNUstep must still track rectangles explicitly
*/
+ uRect = (r ? NSUnionRect (uRect, u) : [FRAME_NS_VIEW (f) visibleRect]);
+ }
+#endif
+
+ /*23: clipping */
+ if (r)
+ {
+ [[NSGraphicsContext currentContext] saveGraphicsState];
+ if (n == 2)
+ NSRectClipList (r, 2);
+ else
+ NSRectClip (*r);
+ gsaved = YES;
+ }
+}
+
+
+static void
+ns_unfocus (struct frame *f)
+/* --------------------------------------------------------------------------
+ Internal: Remove focus on given frame
+ --------------------------------------------------------------------------
*/
+{
+ NSTRACE (ns_unfocus);
+
+ if (gsaved)
+ {
+ [[NSGraphicsContext currentContext] restoreGraphicsState];
+ gsaved = NO;
+ }
+
+ if (f != ns_updating_frame)
+ {
+ if (focus_view != NULL)
+ {
+ [focus_view unlockFocus];
+ [[focus_view window] flushWindow];
+ focus_view = NULL;
+/*debug_lock--; */
+ }
+ }
+}
+
+
+static void
+ns_clip_to_row (struct window *w, struct glyph_row *row, int area, GC gc)
+/* --------------------------------------------------------------------------
+ 23: Internal (but parallels other terms): Focus drawing on given row
+ --------------------------------------------------------------------------
*/
+{
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+ NSRect clip_rect;
+ int window_x, window_y, window_width;
+
+ window_box (w, area, &window_x, &window_y, &window_width, 0);
+
+ clip_rect.origin.x = window_x - FRAME_INTERNAL_BORDER_WIDTH (f);
+ clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
+ clip_rect.origin.y = max (clip_rect.origin.y, window_y);
+ clip_rect.size.width = window_width + 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
+ clip_rect.size.height = row->visible_height;
+
+ /* allow a full-height row at the top when requested
+ (used to draw fringe all the way through internal border area) */
+ if (gc && clip_rect.origin.y < 5)
+ {
+ clip_rect.origin.y -= FRAME_INTERNAL_BORDER_WIDTH (f);
+ clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
+ }
+
+ /* likewise at bottom */
+ if (gc &&
+ FRAME_PIXEL_HEIGHT (f) - (clip_rect.origin.y + clip_rect.size.height) <
5)
+ clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
+
+ ns_focus (f, &clip_rect, 1);
+}
+
+
+static void
+ns_ring_bell ()
+/* --------------------------------------------------------------------------
+ "Beep" routine
+ --------------------------------------------------------------------------
*/
+{
+ NSTRACE (ns_ring_bell);
+ if (visible_bell)
+ {
+ NSAutoreleasePool *pool;
+ struct frame *frame = SELECTED_FRAME ();
+ NSView *view;
+
+ BLOCK_INPUT;
+ pool = [[NSAutoreleasePool alloc] init];
+
+ view = FRAME_NS_VIEW (frame);
+ if (view != nil)
+ {
+ NSRect r, surr;
+ NSPoint dim = NSMakePoint (128, 128);
+
+ r = [view bounds];
+ r.origin.x += (r.size.width - dim.x) / 2;
+ r.origin.y += (r.size.height - dim.y) / 2;
+ r.size.width = dim.x;
+ r.size.height = dim.y;
+ /* PENDING: cacheImageInRect under GNUSTEP does not account for
+ offset in x_set_window_size, so overestimate (4 fine on Cocoa) */
+ surr = NSInsetRect (r, -10, -10);
+ ns_focus (frame, &surr, 1);
+ [[view window] cacheImageInRect: surr];
+ [ns_lookup_indexed_color (NS_FACE_FOREGROUND
+ (FRAME_DEFAULT_FACE (frame)), frame)
set];
+ NSRectFill (r);
+ [[view window] flushWindow];
+ ns_timeout (150000);
+ [[view window] restoreCachedImage];
+ [[view window] flushWindow];
+ ns_unfocus (frame);
+ }
+ [pool release];
+ UNBLOCK_INPUT;
+ }
+ else
+ {
+ NSBeep ();
+ }
+}
+
+
+static void
+ns_reset_terminal_modes (struct terminal *terminal)
+/* Externally called as hook */
+{
+ NSTRACE (ns_reset_terminal_modes);
+}
+
+static void
+ns_set_terminal_modes (struct terminal *terminal)
+/* Externally called as hook */
+{
+ NSTRACE (ns_set_terminal_modes);
+}
+
+
+
+/* ==========================================================================
+
+ Frame / window manager related functions
+
+ ==========================================================================
*/
+
+
+static void
+ns_raise_frame (struct frame *f)
+/* --------------------------------------------------------------------------
+ Bring window to foreground and make it active
+ --------------------------------------------------------------------------
*/
+{
+ NSView *view = FRAME_NS_VIEW (f);
+ check_ns ();
+ BLOCK_INPUT;
+ [[view window] makeKeyAndOrderFront: NSApp];
+ UNBLOCK_INPUT;
+}
+
+
+static void
+ns_lower_frame (struct frame *f)
+/* --------------------------------------------------------------------------
+ Send window to back
+ --------------------------------------------------------------------------
*/
+{
+ NSView *view = FRAME_NS_VIEW (f);
+ check_ns ();
+ BLOCK_INPUT;
+ [[view window] orderBack: NSApp];
+ UNBLOCK_INPUT;
+}
+
+
+static void
+ns_frame_raise_lower (struct frame *f, int raise)
+/* --------------------------------------------------------------------------
+ External (hook)
+ --------------------------------------------------------------------------
*/
+{
+ NSTRACE (ns_frame_raise_lower);
+
+ if (raise)
+ ns_raise_frame (f);
+ else
+ ns_lower_frame (f);
+}
+
+
+static void
+ns_frame_rehighlight (struct frame *frame)
+/* --------------------------------------------------------------------------
+ External (hook): called on things like window switching within frame
+ --------------------------------------------------------------------------
*/
+{
+ struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
+ struct frame *old_highlight = dpyinfo->ns_highlight_frame;
+
+ NSTRACE (ns_frame_rehighlight);
+ if (dpyinfo->ns_focus_frame)
+ {
+ dpyinfo->ns_highlight_frame =
+ (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->ns_focus_frame))
+ ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->ns_focus_frame))
+ : dpyinfo->ns_focus_frame);
+ if (!FRAME_LIVE_P (dpyinfo->ns_highlight_frame))
+ {
+ FRAME_FOCUS_FRAME (dpyinfo->ns_focus_frame) = Qnil;
+ dpyinfo->ns_highlight_frame = dpyinfo->ns_focus_frame;
+ }
+ }
+ else
+ dpyinfo->ns_highlight_frame = 0;
+
+ if (dpyinfo->ns_highlight_frame &&
+ dpyinfo->ns_highlight_frame != old_highlight)
+ {
+ /* as of 20080602 the lower and raise are superfluous */
+ if (old_highlight)
+ {
+ /*ns_lower_frame (old_highlight); */
+ x_update_cursor (old_highlight, 1);
+ }
+ if (dpyinfo->ns_highlight_frame)
+ {
+ /*ns_raise_frame (dpyinfo->ns_highlight_frame); */
+ x_update_cursor (dpyinfo->ns_highlight_frame, 1);
+ }
+ }
+}
+
+
+void
+x_make_frame_visible (struct frame *f)
+/* --------------------------------------------------------------------------
+ External: Show the window (X11 semantics)
+ --------------------------------------------------------------------------
*/
+{
+ NSTRACE (x_make_frame_visible);
+ /* PENDING: at some points in past this was not needed, as the only place
that
+ called this (frame.c:Fraise_frame ()) also called raise_lower;
+ if this ends up the case again, comment this out again. */
+ if (!FRAME_VISIBLE_P (f))
+ ns_raise_frame (f);
+}
+
+
+void
+x_make_frame_invisible (struct frame *f)
+/* --------------------------------------------------------------------------
+ External: Hide the window (X11 semantics)
+ --------------------------------------------------------------------------
*/
+{
+ NSView * view = FRAME_NS_VIEW (f);
+ NSTRACE (x_make_frame_invisible);
+ check_ns ();
+ [[view window] orderOut: NSApp];
+}
+
+
+void
+x_iconify_frame (struct frame *f)
+/* --------------------------------------------------------------------------
+ External: Iconify window
+ --------------------------------------------------------------------------
*/
+{
+ NSView * view = FRAME_NS_VIEW (f);
+ struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
+ NSTRACE (x_iconify_frame);
+ check_ns ();
+
+ if (dpyinfo->ns_highlight_frame == f)
+ dpyinfo->ns_highlight_frame = 0;
+
+ if ([[view window] windowNumber] <= 0)
+ {
+ /* the window is still deferred. Make it very small, bring it
+ on screen and order it out. */
+ NSRect s = { { 100, 100}, {0, 0} };
+ NSRect t;
+ t = [[view window] frame];
+ [[view window] setFrame: s display: NO];
+ [[view window] orderBack: NSApp];
+ [[view window] orderOut: NSApp];
+ [[view window] setFrame: t display: NO];
+ }
+ [[view window] miniaturize: NSApp];
+}
+
+
+void
+x_destroy_window (struct frame *f)
+/* --------------------------------------------------------------------------
+ External: Delete the window
+ --------------------------------------------------------------------------
*/
+{
+ NSView *view = FRAME_NS_VIEW (f);
+ struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
+ NSTRACE (x_destroy_window);
+ check_ns ();
+
+ [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
+
+ BLOCK_INPUT;
+
+ free_frame_menubar (f);
+
+ if (FRAME_FACE_CACHE (f))
+ free_frame_faces (f);
+
+ if (f == dpyinfo->ns_focus_frame)
+ dpyinfo->ns_focus_frame = 0;
+ if (f == dpyinfo->ns_highlight_frame)
+ dpyinfo->ns_highlight_frame = 0;
+ if (f == dpyinfo->mouse_face_mouse_frame)
+ {
+ dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
+ dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
+ dpyinfo->mouse_face_window = Qnil;
+ dpyinfo->mouse_face_deferred_gc = 0;
+ dpyinfo->mouse_face_mouse_frame = 0;
+ }
+
+ xfree (f->output_data.ns);
+
+ [[view window] close];
+ [view release];
+
+ ns_window_num--;
+ UNBLOCK_INPUT;
+}
+
+
+void
+x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
+/* --------------------------------------------------------------------------
+ External: Position the window
+ --------------------------------------------------------------------------
*/
+{
+ NSScreen *screen;
+ NSView *view = FRAME_NS_VIEW (f);
+
+ NSTRACE (x_set_offset);
+
+ BLOCK_INPUT;
+
+ f->left_pos = xoff;
+ f->top_pos = yoff;
+#ifdef NS_IMPL_GNUSTEP
+ if (xoff < 100)
+ f->left_pos = 100; /* don't overlap menu */
+#endif
+ if (view != nil && (screen = [[view window] screen]))
+ [[view window] setFrameTopLeftPoint:
+ NSMakePoint (SCREENMAXBOUND (f->left_pos),
+ SCREENMAXBOUND ([screen frame].size.height
+ - NS_TOP_POS (f)))];
+ UNBLOCK_INPUT;
+}
+
+
+void
+x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
+/* --------------------------------------------------------------------------
+ Adjust window pixel size based on given character grid size
+ Impl is a bit more complex than other terms, need to do some
+ internal clipping and also pay attention to screen constraints.
+ --------------------------------------------------------------------------
*/
+{
+ EmacsView *view = FRAME_NS_VIEW (f);
+ EmacsToolbar *toolbar = [view toolbar];
+ NSWindow *window = [view window];
+ NSScreen *screen = [window screen];
+ NSRect wr = [window frame];
+ int tb = FRAME_EXTERNAL_TOOL_BAR (f);
+ int pixelwidth, pixelheight;
+ static int oldRows, oldCols, oldFontWidth, oldFontHeight;
+ static int oldTB;
+ static struct frame *oldF;
+
+ NSTRACE (x_set_window_size);
+
+ if (view == nil ||
+ (f == oldF
+ && rows == oldRows && cols == oldCols
+ && oldFontWidth == FRAME_COLUMN_WIDTH (f)
+ && oldFontHeight == FRAME_LINE_HEIGHT (f)
+ && oldTB == tb))
+ return;
+
+/*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols,
rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
+
+ BLOCK_INPUT;
+
+ check_frame_size (f, &rows, &cols);
+ oldF = f;
+ oldRows = rows;
+ oldCols = cols;
+ oldFontWidth = FRAME_COLUMN_WIDTH (f);
+ oldFontHeight = FRAME_LINE_HEIGHT (f);
+ oldTB = tb;
+
+ f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
+ compute_fringe_widths (f, 0);
+
+ pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
+ pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
+
+ /* If we have a change in toolbar display, calculate height */
+ if (tb)
+ /* PENDING: GNUstep has not yet implemented the first method below, added
+ in Panther, however the second is incorrect under Cocoa. */
+#ifdef NS_IMPL_GNUSTEP
+ FRAME_NS_TOOLBAR_HEIGHT (f) =
+ NSHeight ([NSWindow frameRectForContentRect: NSMakeRect (0, 0, 0, 0)
+ styleMask: [window styleMask]])
+ - FRAME_NS_TITLEBAR_HEIGHT (f);
+#else
+ FRAME_NS_TOOLBAR_HEIGHT (f) = 32;
+ /* actually get wrong result here if toolbar not yet displayed
+ NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
+ - FRAME_NS_TITLEBAR_HEIGHT (f); */
+#endif
+ else
+ FRAME_NS_TOOLBAR_HEIGHT (f) = 0;
+
+ wr.size.width = pixelwidth + f->border_width;
+ wr.size.height = pixelheight + FRAME_NS_TITLEBAR_HEIGHT (f)
+ + FRAME_NS_TOOLBAR_HEIGHT (f);
+
+ /* constrain to screen if we can */
+ if (screen)
+ {
+ NSSize sz = [screen visibleFrame].size;
+ NSSize ez = { wr.size.width - sz.width, wr.size.height - sz.height };
+ if (ez.width > 0)
+ {
+ int cr = ez.width / FRAME_COLUMN_WIDTH (f) + 1;
+ cols -= cr;
+ oldCols = cols;
+ wr.size.width -= cr * FRAME_COLUMN_WIDTH (f);
+ pixelwidth -= cr * FRAME_COLUMN_WIDTH (f);
+ }
+ if (ez.height > 0)
+ {
+ int rr = ez.height / FRAME_LINE_HEIGHT (f) + 1;
+ rows -= rr;
+ oldRows = rows;
+ wr.size.height -= rr * FRAME_LINE_HEIGHT (f);
+ pixelheight -= rr * FRAME_LINE_HEIGHT (f);
+ }
+ wr.origin.x = f->left_pos;
+ wr.origin.y = [screen frame].size.height - NS_TOP_POS (f)
+ - wr.size.height;
+ }
+
+ [view setRows: rows andColumns: cols];
+ [window setFrame: wr display: YES];
+
+/*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows,
pixelwidth, pixelheight); */
+
+ /* This is a trick to compensate for Emacs' managing the scrollbar area
+ as a fixed number of standard character columns. Instead of leaving
+ blank space for the extra, we chopped it off above. Now for
+ left-hand scrollbars, we shift all rendering to the left by the
+ difference between the real width and Emacs' imagined one. For
+ right-hand bars, don't worry about it since the extra is never used.
+ (Obviously doesn't work for vertically split windows tho..) */
+ NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
+ ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
+ - NS_SCROLL_BAR_WIDTH (f), 0)
+ : NSMakePoint (0, 0);
+ [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
+ [view setBoundsOrigin: origin];
+
+ change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
+ FRAME_PIXEL_WIDTH (f) = pixelwidth;
+ FRAME_PIXEL_HEIGHT (f) = pixelheight;
+/* SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
+
+ mark_window_cursors_off (XWINDOW (f->root_window));
+ cancel_mouse_face (f);
+
+ UNBLOCK_INPUT;
+}
+
+
+/* ==========================================================================
+
+ Color management
+
+ ==========================================================================
*/
+
+NSColor *
+ns_lookup_indexed_color (unsigned long idx, struct frame *f)
+{
+ struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
+ return color_table->colors[idx];
+}
+
+
+unsigned long
+ns_index_color (NSColor *color, struct frame *f)
+{
+ struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
+ int idx;
+ NSNumber *index;
+
+ if (!color_table->colors)
+ {
+ color_table->size = NS_COLOR_CAPACITY;
+ color_table->avail = 1; /* skip idx=0 as marker */
+ color_table->colors =
+ (NSColor **)xmalloc (color_table->size * sizeof (NSColor *));
+ color_table->empty_indices = [[NSMutableSet alloc] init];
+ }
+
+ /* do we already have this color ? */
+ {
+ int i;
+ for (i = 1; i < color_table->avail; i++)
+ {
+ if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
+ {
+ [color_table->colors[i] retain];
+ return i;
+ }
+ }
+ }
+
+ if ([color_table->empty_indices count] > 0)
+ {
+ index = [color_table->empty_indices anyObject];
+ [color_table->empty_indices removeObject: index];
+ idx = [index unsignedIntValue];
+ }
+ else
+ {
+ if (color_table->avail == color_table->size)
+ {
+ color_table->size += NS_COLOR_CAPACITY;
+ color_table->colors =
+ (NSColor **)xrealloc (color_table->colors,
+ color_table->size * sizeof (NSColor *));
+ }
+ idx = color_table->avail++;
+ index = [NSNumber numberWithUnsignedInt: idx];
+ }
+
+ color_table->colors[idx] = color;
+ [color retain];
+/*fprintf(stderr, "color_table: allocated %d\n",idx);*/
+ return idx;
+}
+
+
+void
+ns_free_indexed_color (unsigned long idx, struct frame *f)
+{
+ struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
+ NSColor *color;
+ if (!idx)
+ return;
+ color = color_table->colors[idx];
+ [color release];
+ color_table->colors[idx] = nil;
+ [color_table->empty_indices addObject: [NSNumber numberWithUnsignedInt:
idx]];
+/*fprintf(stderr, "color_table: FREED %d\n",idx);*/
+}
+
+
+static int
+ns_get_color (const char *name, NSColor **col)
+/* --------------------------------------------------------------------------
+ Parse a color name
+/* --------------------------------------------------------------------------
+/* On *Step, we recognize several color formats, in addition to a catalog
+ of colors found in the file Emacs.clr. Color formats include:
+ - #rrggbb or RGBrrggbb where rr, gg, bb specify red, green and blue in hex
+ - ARGBaarrggbb is similar, with aa being the alpha channel (FF = opaque)
+ - HSVhhssvv and AHSVaahhssvv are similar for hue, saturation, value
+ - CMYKccmmyykk is similar for cyan, magenta, yellow, black. */
+{
+ NSColor * new = nil;
+ const char *hex = NULL;
+ enum { rgb, argb, hsv, ahsv, cmyk, gray } color_space;
+ NSString *nsname = [NSString stringWithUTF8String: name];
+
+/*fprintf (stderr, "ns_get_color: '%s'\n", name); */
+ BLOCK_INPUT;
+
+ if ([nsname isEqualToString: @"ns_selection_color"])
+ {
+ nsname = ns_selection_color;
+ name = [ns_selection_color UTF8String];
+ }
+
+ if (name[0] == '0' || name[0] == '1' || name[0] == '.')
+ {
+ /* RGB decimal */
+ NSScanner *scanner = [NSScanner scannerWithString: nsname];
+ float r, g, b;
+ [scanner scanFloat: &r];
+ [scanner scanFloat: &g];
+ [scanner scanFloat: &b];
+ *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
+ UNBLOCK_INPUT;
+ return 0;
+ }
+
+ /* 23: PENDING: emacs seems to downcase everything before passing it here,
+ which we can work around, except for GRAY, since gray##, where ## is
+ decimal between 0 and 99, is also an X11 colorname. */
+ if (name[0] == '#') /* X11 format */
+ {
+ hex = name + 1;
+ color_space = rgb;
+ }
+ else if (!memcmp (name, "RGB", 3) || !memcmp (name, "rgb", 3))
+ {
+ hex = name + 3;
+ color_space = rgb;
+ }
+ else if (!memcmp (name, "ARGB", 4) || !memcmp (name, "argb", 4))
+ {
+ hex = name + 4;
+ color_space = argb;
+ }
+ else if (!memcmp (name, "HSV", 3) || !memcmp (name, "hsv", 3))
+ {
+ hex = name + 3;
+ color_space = hsv;
+ }
+ else if (!memcmp (name, "AHSV", 4) || !memcmp (name, "ahsv", 4))
+ {
+ hex = name + 4;
+ color_space = ahsv;
+ }
+ else if (!memcmp (name, "CMYK", 4) || !memcmp (name, "cmyk", 4))
+ {
+ hex = name + 4;
+ color_space = cmyk;
+ }
+ else if (!memcmp (name, "GRAY", 4) /*|| !memcmp (name, "gray", 4)*/)
+ {
+ hex = name + 4;
+ color_space = gray;
+ }
+
+ /* Direct colors (hex values) */
+ if (hex)
+ {
+ unsigned int color = 0;
+ if (sscanf (hex, "%x", &color))
+ {
+ float f1 = ((color >> 24) & 0xff) / 255.0;
+ float f2 = ((color >> 16) & 0xff) / 255.0;
+ float f3 = ((color >> 8) & 0xff) / 255.0;
+ float f4 = ((color ) & 0xff) / 255.0;
+
+ switch (color_space)
+ {
+ case rgb:
+ *col = [NSColor colorWithCalibratedRed: f2
+ green: f3
+ blue: f4
+ alpha: 1.0];
+ break;
+ case argb:
+ *col = [NSColor colorWithCalibratedRed: f2
+ green: f3
+ blue: f4
+ alpha: f1];
+ break;
+ case hsv:
+ *col = [NSColor colorWithCalibratedHue: f2
+ saturation: f3
+ brightness: f4
+ alpha: 1.0];
+ break;
+ case ahsv:
+ *col = [NSColor colorWithCalibratedHue: f2
+ saturation: f3
+ brightness: f4
+ alpha: f1];
+ break;
+ case gray:
+ *col = [NSColor colorWithCalibratedWhite: f3 alpha: f4];
+ break;
+ case cmyk:
+ *col = [NSColor colorWithDeviceCyan: f1
+ magenta: f2
+ yellow: f3
+ black: f4
+ alpha: 1.0];
+ break;
+ }
+ *col = [*col colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
+ UNBLOCK_INPUT;
+ return 0;
+ }
+ }
+
+ /* Otherwise, color is expected to be from a list */
+ {
+ NSEnumerator *lenum, *cenum;
+ NSString *name;
+ NSColorList *clist;
+#ifdef NS_IMPL_GNUSTEP
+ /* PENDING: who is wrong, the requestor or the implementation? */
+ if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
+ == NSOrderedSame)
+ nsname = @"highlightColor";
+#endif
+ if ([nsname compare: @"dark blue" options: NSCaseInsensitiveSearch]
+ == NSOrderedSame
+ || [nsname compare: @"darkblue" options: NSCaseInsensitiveSearch]
+ == NSOrderedSame)
+ nsname = @"navy blue";
+
+ lenum = [[NSColorList availableColorLists] objectEnumerator];
+ while ( (clist = [lenum nextObject]) && new == nil)
+ {
+ cenum = [[clist allKeys] objectEnumerator];
+ while ( (name = [cenum nextObject]) && new == nil )
+ {
+ if ([name compare: nsname
+ options: NSCaseInsensitiveSearch] == NSOrderedSame )
+ new = [clist colorWithKey: name];
+ }
+ }
+ }
+
+ if ( new )
+ *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
+/* else
+ NSLog (@"Failed to find color '%@'", nsname); */
+ UNBLOCK_INPUT;
+ return new ? 0 : 1;
+}
+
+
+static NSColor *
+ns_get_color_default (const char *name, NSColor *dflt)
+/* --------------------------------------------------------------------------
+ Parse a color or use a default value
+ --------------------------------------------------------------------------
*/
+{
+ NSColor * col;
+
+ if (ns_get_color (name, &col))
+ return dflt;
+ else
+ return col;
+}
+
+
+int
+ns_lisp_to_color (Lisp_Object color, NSColor **col)
+/* --------------------------------------------------------------------------
+ Convert a Lisp string object to a NS color
+ --------------------------------------------------------------------------
*/
+{
+ NSTRACE (ns_lisp_to_color);
+ if (XTYPE (color) == Lisp_String)
+ return ns_get_color (XSTRING (color)->data, col);
+ else if (XTYPE (color) == Lisp_Symbol)
+ return ns_get_color (XSTRING (XSYMBOL (color)->xname)->data, col);
+ return 1;
+}
+
+
+Lisp_Object
+ns_color_to_lisp (NSColor *col)
+/* --------------------------------------------------------------------------
+ Convert a color to a lisp string with the RGB equivalent
+ --------------------------------------------------------------------------
*/
+{
+ float red, green, blue, alpha, gray;
+ char buf[1024];
+ const char *str;
+ NSTRACE (ns_color_to_lisp);
+
+ BLOCK_INPUT;
+ if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
+
+ if ((str =[[col colorNameComponent] UTF8String]))
+ {
+ UNBLOCK_INPUT;
+ return build_string ((char *)str);
+ }
+
+ [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
+ getRed: &red green: &green blue: &blue alpha: &alpha];
+ if (red ==green && red ==blue)
+ {
+ [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
+ getWhite: &gray alpha: &alpha];
+ snprintf (buf, sizeof (buf), "GRAY%02.2lx%02.2lx",
+ lrint (gray * 0xff), lrint (alpha * 0xff));
+ UNBLOCK_INPUT;
+ return build_string (buf);
+ }
+
+ snprintf (buf, sizeof (buf), "ARGB%02.2lx%02.2lx%02.2lx%02.2lx",
+ lrint (alpha*0xff),
+ lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
+
+ UNBLOCK_INPUT;
+ return build_string (buf);
+}
+
+
+int
+ns_defined_color (struct frame *f, char *name, XColor *color_def, int alloc,
+ char makeIndex)
+/* --------------------------------------------------------------------------
+ 23: Return 1 if named color found, and set color_def rgb accordingly.
+ If makeIndex and alloc are nonzero put the color in the color_table,
+ and set color_def pixel to the resulting index.
+ If makeIndex is zero, set color_def pixel to ARGB.
+ Return 0 if not found
+ --------------------------------------------------------------------------
*/
+{
+ NSColor *temp;
+ float r, g, b, a;
+ int notFound = ns_get_color (name, &temp);
+
+ NSTRACE (ns_defined_color);
+
+ if (notFound)
+ return 0;
+
+ if (makeIndex && alloc)
+ color_def->pixel = ns_index_color(temp, f);//[temp retain];
+
+ [temp getRed: &r green: &g blue: &b alpha: &a];
+ color_def->red = r * 256;
+ color_def->green = g * 256;
+ color_def->blue = b * 256;
+
+ if (!makeIndex)
+ color_def->pixel =
+ ARGB_TO_ULONG((int)(a*256),
+ color_def->red, color_def->green, color_def->blue);
+
+ return 1;
+}
+
+
+unsigned long
+ns_get_rgb_color (struct frame *f, float r, float g, float b, float a)
+/* --------------------------------------------------------------------------
+ return an autoreleased RGB color
+ --------------------------------------------------------------------------
*/
+{
+/*static int c = 1; fprintf (stderr, "color request %d\n", c++); */
+ if (r < 0.0) r = 0.0;
+ else if (r > 1.0) r = 1.0;
+ if (g < 0.0) g = 0.0;
+ else if (g > 1.0) g = 1.0;
+ if (b < 0.0) b = 0.0;
+ else if (b > 1.0) b = 1.0;
+ if (a < 0.0) a = 0.0;
+ else if (a > 1.0) a = 1.0;
+ return (unsigned long) ns_index_color(
+ [NSColor colorWithCalibratedRed: r green: g blue: b alpha: a], f);
+}
+
+
+
+/* ==========================================================================
+
+ Mouse handling
+
+ ==========================================================================
*/
+
+
+void
+x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
+/* --------------------------------------------------------------------------
+ Programmatically reposition mouse pointer in pixel coordinates
+ --------------------------------------------------------------------------
*/
+{
+ NSTRACE (x_set_mouse_pixel_position);
+ ns_raise_frame (f);
+#if 0
+ /*PENDING: this does not work, and what about GNUstep? */
+#ifdef NS_IMPL_COCOA
+ [FRAME_NS_VIEW (f) lockFocus];
+ PSsetmouse ((float)pix_x, (float)pix_y);
+ [FRAME_NS_VIEW (f) unlockFocus];
+#endif
+#endif
+}
+
+
+void
+x_set_mouse_position (struct frame *f, int h, int v)
+/* --------------------------------------------------------------------------
+ Programmatically reposition mouse pointer in character coordinates
+ --------------------------------------------------------------------------
*/
+{
+ int pix_x, pix_y;
+
+ pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
+ pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
+
+ if (pix_x < 0) pix_x = 0;
+ if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
+
+ if (pix_y < 0) pix_y = 0;
+ if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
+
+ x_set_mouse_pixel_position (f, pix_x, pix_y);
+}
+
+
+static int
+note_mouse_movement (struct frame *frame, float x, float y)
+/* ------------------------------------------------------------------------
+ Called by EmacsView on mouseMovement events. Passes on
+ to emacs mainstream code if we moved off of a rect of interest
+ known as last_mouse_glyph.
+ ------------------------------------------------------------------------
*/
+{
+ NSTRACE (note_mouse_movement);
+
+ XSETFRAME (last_mouse_motion_frame, frame);
+
+ /* Note, this doesn't get called for enter/leave, since we don't have a
+ position. Those are taken care of in the corresponding NSView methods. */
+
+ /* has movement gone beyond last rect we were tracking? */
+ if (x < last_mouse_glyph.origin.x ||
+ x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
+ y < last_mouse_glyph.origin.y ||
+ y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
+ {
+ frame->mouse_moved = 1;
+ note_mouse_highlight (frame, x, y);
+ remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void
+ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
+ enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
+ unsigned long *time)
+/* --------------------------------------------------------------------------
+ External (hook): inform emacs about mouse position and hit parts.
+ If a scrollbar is being dragged, set bar_window, part, x, y, time.
+ x & y should be position in the scrollbar (the whole bar, not the handle)
+ and length of scrollbar respectively
+ --------------------------------------------------------------------------
*/
+{
+ id view;
+ NSPoint position;
+ int xchar, ychar;
+ Lisp_Object frame, tail;
+ struct frame *f;
+ struct ns_display_info *dpyinfo;
+
+ NSTRACE (ns_mouse_position);
+
+ if (*fp == NULL)
+ {
+ fprintf (stderr, "Warning: ns_mouse_position () called with null
*fp.\n");
+ return;
+ }
+
+ dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
+
+ BLOCK_INPUT;
+
+ if (last_mouse_scroll_bar != nil && insist == 0)
+ {
+ /* PENDING: we do not use this path at the moment because drag events
will
+ go directly to the EmacsScroller. Leaving code in for now. */
+ [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
+ x: x y: y];
+ if (time) *time = last_mouse_movement_time;
+ last_mouse_scroll_bar = nil;
+ }
+ else
+ {
+ /* Clear the mouse-moved flag for every frame on this display. */
+ FOR_EACH_FRAME (tail, frame)
+ if (FRAME_NS_P (XFRAME (frame))
+ && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
+ XFRAME (frame)->mouse_moved = 0;
+
+ last_mouse_scroll_bar = nil;
+ if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
+ f = last_mouse_frame;
+ else
+ f = dpyinfo->ns_focus_frame ? dpyinfo->ns_focus_frame
+ : SELECTED_FRAME ();
+
+ if (f && f->output_data.ns) /*PENDING: 2nd check no longer needed? */
+ {
+ view = FRAME_NS_VIEW (*fp);
+
+ position = [[view window] mouseLocationOutsideOfEventStream];
+ position = [view convertPoint: position fromView: nil];
+ remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
+/*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y);
*/
+
+ if (bar_window) *bar_window = Qnil;
+ if (part) *part = 0; /*scroll_bar_handle; */
+
+ if (x) XSETINT (*x, lrint (position.x));
+ if (y) XSETINT (*y, lrint (position.y));
+ if (time) *time = last_mouse_movement_time;
+ *fp = f;
+ }
+ }
+
+ UNBLOCK_INPUT;
+}
+
+
+static void
+ns_frame_up_to_date (struct frame *f)
+/* --------------------------------------------------------------------------
+ External (hook): Fix up mouse highlighting right after a full update.
+ Some highlighting was deferred if GC was happening during
+ note_mouse_highlight (), while other highlighting was deferred for update.
+ --------------------------------------------------------------------------
*/
+{
+ NSTRACE (ns_frame_up_to_date);
+
+ if (FRAME_NS_P (f))
+ {
+ struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
+ if ((dpyinfo->mouse_face_deferred_gc||f
==dpyinfo->mouse_face_mouse_frame)
+ /*&& dpyinfo->mouse_face_mouse_frame*/)
+ {
+ BLOCK_INPUT;
+ if (dpyinfo->mouse_face_mouse_frame)
+ note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
+ dpyinfo->mouse_face_mouse_x,
+ dpyinfo->mouse_face_mouse_y);
+ dpyinfo->mouse_face_deferred_gc = 0;
+ UNBLOCK_INPUT;
+ }
+ }
+}
+
+
+void
+ns_define_frame_cursor (struct frame *f, Cursor cursor)
+/* --------------------------------------------------------------------------
+ External (RIF): set frame mouse pointer type.
+ --------------------------------------------------------------------------
*/
+{
+ NSTRACE (ns_define_frame_cursor);
+ if (FRAME_POINTER_TYPE (f) != cursor)
+ {
+ EmacsView *view = FRAME_NS_VIEW (f);
+ FRAME_POINTER_TYPE (f) = cursor;
+ [[view window] invalidateCursorRectsForView: view];
+ }
+}
+
+
+
+/* ==========================================================================
+
+ Keyboard handling
+
+ ==========================================================================
*/
+
+
+static unsigned
+ns_convert_key (unsigned code)
+/* --------------------------------------------------------------------------
+ Internal call used by NSView-keyDown.
+ --------------------------------------------------------------------------
*/
+{
+ const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
+ / sizeof (convert_ns_to_X_keysym[0]));
+ unsigned keysym;
+ /* An array would be faster, but less easy to read. */
+ for (keysym = 0; keysym < last_keysym; keysym += 2)
+ if (code == convert_ns_to_X_keysym[keysym])
+ return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
+ return 0;
+/* if decide to use keyCode and Carbon table, use this line:
+ return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
+}
+
+
+char *
+x_get_keysym_name (int keysym)
+/* --------------------------------------------------------------------------
+ Called by keyboard.c. Not sure if the return val is important, except
+ that it be unique.
+ --------------------------------------------------------------------------
*/
+{
+ static char value[16];
+ NSTRACE (x_get_keysym_name);
+ sprintf (value, "%d", keysym);
+ return value;
+}
+
+
+
+/* ==========================================================================
+
+ Block drawing operations
+
+ ==========================================================================
*/
+
+
+static void
+ns_redraw_scroll_bars (struct frame *f)
+{
+ int i;
+ id view;
+ NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
+ NSTRACE (ns_judge_scroll_bars);
+ for (i =[subviews count]-1; i >= 0; i--)
+ {
+ view = [subviews objectAtIndex: i];
+ if (![view isKindOfClass: [EmacsScroller class]]) continue;
+ [view display];
+ }
+}
+
+
+void
+ns_clear_frame (struct frame *f)
+/* --------------------------------------------------------------------------
+ External (hook): Erase the entire frame
+ --------------------------------------------------------------------------
*/
+{
+ NSView *view = FRAME_NS_VIEW (f);
+ NSRect r;
+
+ NSTRACE (ns_clear_frame);
+ if (ns_in_resize)
+ return;
+
+ /* comes on initial frame because we have
+ after-make-frame-functions = select-frame */
+ if (!FRAME_DEFAULT_FACE (f))
+ return;
+
+ mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
+
+ output_cursor.hpos = output_cursor.vpos = 0;
+ output_cursor.x = -1;
+
+ r = [view bounds];
+
+ BLOCK_INPUT;
+ ns_focus (f, &r, 1);
+ [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f)
set];
+ NSRectFill (r);
+ ns_unfocus (f);
+
+#ifdef NS_IMPL_COCOA
+ [[view window] display]; /* redraw resize handle */
+#endif
+
+ /* as of 2006/11 or so this is now needed */
+ ns_redraw_scroll_bars (f);
+ UNBLOCK_INPUT;
+}
+
+
+void
+ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
+/* --------------------------------------------------------------------------
+ 23: External (RIF): Clear section of frame
+ --------------------------------------------------------------------------
*/
+{
+ NSRect r = NSMakeRect (x, y, width, height);
+ NSView *view = FRAME_NS_VIEW (f);
+ struct face *face = FRAME_DEFAULT_FACE (f);
+
+ if (!view || !face)
+ return;
+
+ r = NSIntersectionRect (r, [view frame]);
+ ns_focus (f, &r, 1);
+ [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
+
+#ifdef NS_IMPL_COCOA
+ {
+ /* clip out the resize handle */
+ NSWindow *window = [FRAME_NS_VIEW (f) window];
+ NSRect ir =
+ [view convertRect: ns_resize_handle_rect (window) fromView: nil];
+
+ ir = NSIntersectionRect (r, ir);
+ if (NSIsEmptyRect (ir))
+ {
+#endif
+
+ NSRectFill (r);
+
+#ifdef NS_IMPL_COCOA
+ }
+ else
+ {
+ NSRect r1 = r, r2 = r; /* upper and lower non-intersecting */
+ r1.size.height -= ir.size.height;
+ r2.origin.y += r1.size.height;
+ r2.size.width -= ir.size.width;
+ r2.size.height = ir.size.height;
+ NSRectFill (r1);
+ NSRectFill (r2);
+ }
+ }
+#endif
+
+ ns_unfocus (f);
+ return;
+}
+
+
+static void
+ns_scroll_run (struct window *w, struct run *run)
+/* --------------------------------------------------------------------------
+ 23: External (RIF): Insert or delete n lines at line vpos
+ --------------------------------------------------------------------------
*/
+{
+ struct frame *f = XFRAME (w->frame);
+ int x, y, width, height, from_y, to_y, bottom_y;
+
+ NSTRACE (ns_scroll_run);
+
+ /* begin copy from other terms */
+ /* Get frame-relative bounding box of the text display area of W,
+ without mode lines. Include in this box the left and right
+ fringe of W. */
+ window_box (w, -1, &x, &y, &width, &height);
+
+ from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
+ to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
+ bottom_y = y + height;
+
+ if (to_y < from_y)
+ {
+ /* Scrolling up. Make sure we don't copy part of the mode
+ line at the bottom. */
+ if (from_y + run->height > bottom_y)
+ height = bottom_y - from_y;
+ else
+ height = run->height;
+ }
+ else
+ {
+ /* Scolling down. Make sure we don't copy over the mode line.
+ at the bottom. */
+ if (to_y + run->height > bottom_y)
+ height = bottom_y - to_y;
+ else
+ height = run->height;
+ }
+ /* end copy from other terms */
+
+ if (height == 0)
+ return;
+
+ BLOCK_INPUT;
+
+ updated_window = w;
+ x_clear_cursor (w);
+
+ {
+ NSRect srcRect = NSMakeRect (x, from_y, width, height);
+ NSRect dstRect = NSMakeRect (x, to_y, width, height);
+ NSPoint dstOrigin = NSMakePoint (x, to_y);
+
+ ns_focus (f, &dstRect, 1);
+ NSCopyBits (0, srcRect , dstOrigin);
+ ns_unfocus (f);
+ }
+
+ UNBLOCK_INPUT;
+}
+
+
+static void
+ns_after_update_window_line (struct glyph_row *desired_row)
+/* --------------------------------------------------------------------------
+ 23: External (RIF): preparatory to fringe update after text was updated
+ --------------------------------------------------------------------------
*/
+{
+ struct window *w = updated_window;
+ struct frame *f;
+ int width, height;
+
+ NSTRACE (ns_after_update_window_line);
+
+ /* begin copy from other terms */
+ xassert (w);
+
+ if (!desired_row->mode_line_p && !w->pseudo_window_p)
+ desired_row->redraw_fringe_bitmaps_p = 1;
+
+ /* When a window has disappeared, make sure that no rest of
+ full-width rows stays visible in the internal border.
+ Under NS this is drawn inside the fringes. */
+ if (windows_or_buffers_changed
+ && (f = XFRAME (w->frame),
+ width = FRAME_INTERNAL_BORDER_WIDTH (f),
+ width != 0)
+ && (height = desired_row->visible_height,
+ height > 0))
+ {
+ int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
+
+ /* Internal border is drawn below the tool bar. */
+ if (WINDOWP (f->tool_bar_window)
+ && w == XWINDOW (f->tool_bar_window))
+ y -= width;
+ /* end copy from other terms */
+
+ BLOCK_INPUT;
+ if (!desired_row->full_width_p)
+ {
+ int x1 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
+ + WINDOW_LEFT_FRINGE_WIDTH (w);
+ int x2 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
+ + FRAME_PIXEL_WIDTH (f) - NS_SCROLL_BAR_WIDTH (f)
+ - WINDOW_RIGHT_FRINGE_WIDTH (w)
+ - FRAME_INTERNAL_BORDER_WIDTH (f);
+ ns_clear_frame_area (f, x1, y, width, height);
+ ns_clear_frame_area (f, x2, y, width, height);
+ }
+ UNBLOCK_INPUT;
+ }
+}
+
+
+static void
+ns_shift_glyphs_for_insert (struct frame *f,
+ int x, int y, int width, int height,
+ int shift_by)
+/* --------------------------------------------------------------------------
+ 23: External (RIF): copy an area horizontally, don't worry about clearing
src
+ --------------------------------------------------------------------------
*/
+{
+ NSRect srcRect = NSMakeRect (x, y, width, height);
+ NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
+ NSPoint dstOrigin = dstRect.origin;
+
+ NSTRACE (ns_shift_glyphs_for_insert);
+
+ ns_focus (f, &dstRect, 1);
+ NSCopyBits (0, srcRect, dstOrigin);
+ ns_unfocus (f);
+}
+
+
+
+/* ==========================================================================
+
+ Character encoding and metrics
+
+ ==========================================================================
*/
+
+
+static inline void
+ns_compute_glyph_string_overhangs (struct glyph_string *s)
+/* --------------------------------------------------------------------------
+ 23: External (RIF); compute left/right overhang of whole string and set in
s
+ --------------------------------------------------------------------------
*/
+{
+ struct face *face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
+ struct font *font = s->font; /*face->font; */
+
+ if (s->char2b)
+ {
+ struct font_metrics metrics;
+ unsigned int codes[2];
+ codes[0] = *(s->char2b);
+ codes[1] = *(s->char2b + s->nchars - 1);
+
+ font->driver->text_extents (font, codes, 2, &metrics);
+ s->left_overhang = -metrics.lbearing;
+ s->right_overhang =
+ metrics.rbearing > metrics.width ? metrics.rbearing - metrics.width :
0;
+ }
+ else
+ {
+ s->left_overhang = 0;
+ s->right_overhang = ((struct nsfont_info *)font)->ital ?
+ FONT_HEIGHT (font) * 0.2 : 0;
+ }
+}
+
+
+
+/* ==========================================================================
+
+ Fringe and cursor drawing
+
+ ==========================================================================
*/
+
+
+extern int max_used_fringe_bitmap;
+static void
+ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
+ struct draw_fringe_bitmap_params *p)
+/* --------------------------------------------------------------------------
+ 23: External (RIF); fringe-related
+ --------------------------------------------------------------------------
*/
+{
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+ struct face *face = p->face;
+ int rowY;
+ static EmacsImage **bimgs = NULL;
+ static int nBimgs = 0;
+ /* NS-specific: move internal border inside fringe */
+ int x = p->bx < 0 ? p->x : p->bx;
+ int wd = p->bx < 0 ? p->wd : p->nx;
+ BOOL fringeOnVeryLeft =
+ x - WINDOW_LEFT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w)
+ - FRAME_INTERNAL_BORDER_WIDTH (f) < 10;
+ BOOL fringeOnVeryRight =
+ FRAME_PIXEL_WIDTH (f) - x - wd - FRAME_INTERNAL_BORDER_WIDTH (f)
+ - WINDOW_RIGHT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w) < 10;
+ int xAdjust = FRAME_INTERNAL_BORDER_WIDTH (f) *
+ (fringeOnVeryLeft ? -1 : (fringeOnVeryRight ? 1 : 0));
+
+ /* grow bimgs if needed */
+ if (nBimgs < max_used_fringe_bitmap)
+ {
+ EmacsImage **newBimgs =
+ xmalloc (max_used_fringe_bitmap * sizeof (EmacsImage *));
+ bzero (newBimgs, max_used_fringe_bitmap * sizeof (EmacsImage *));
+
+ if (nBimgs)
+ {
+ bcopy (bimgs, newBimgs, nBimgs * sizeof (EmacsImage *));
+ xfree (bimgs);
+ }
+
+ bimgs = newBimgs;
+ nBimgs = max_used_fringe_bitmap;
+ }
+
+ /* Must clip because of partially visible lines. */
+ rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
+ if (p->y < rowY)
+ {
+ /* Adjust position of "bottom aligned" bitmap on partially
+ visible last row. */
+ int oldY = row->y;
+ int oldVH = row->visible_height;
+ row->visible_height = p->h;
+ row->y -= rowY - p->y;
+ ns_clip_to_row (w, row, -1, NULL);
+ row->y = oldY;
+ row->visible_height = oldVH;
+ }
+ else
+ ns_clip_to_row (w, row, -1, YES);
+
+ if (p->bx >= 0 && !p->overlay_p)
+ {
+ int yAdjust = rowY - FRAME_INTERNAL_BORDER_WIDTH (f) < 5 ?
+ -FRAME_INTERNAL_BORDER_WIDTH (f) : 0;
+ int yIncr = FRAME_PIXEL_HEIGHT (f) - (p->by+yAdjust + p->ny) < 5 ?
+ FRAME_INTERNAL_BORDER_WIDTH (f) : 0;
+ if (yAdjust)
+ yIncr += FRAME_INTERNAL_BORDER_WIDTH (f);
+ NSRect r = NSMakeRect (p->bx+xAdjust, p->by+yAdjust, p->nx, p->ny+yIncr);
+ NSRectClip (r);
+ [ns_lookup_indexed_color(face->background, f) set];
+ NSRectFill (r);
+ }
+
+ if (p->which)
+ {
+ NSRect r = NSMakeRect (p->x+xAdjust, p->y, p->wd, p->h);
+ NSPoint pt = r.origin;
+ EmacsImage *img = bimgs[p->which - 1];
+
+ if (!img)
+ {
+ unsigned short *bits = p->bits + p->dh;
+ int len = 8 * p->h/8;
+ int i;
+ unsigned char *cbits = xmalloc (len);
+
+ for (i =0; i<len; i++)
+ cbits[i] = ~(bits[i] & 0xff);
+ img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
+ flip: NO];
+ bimgs[p->which - 1] = img;
+ xfree (cbits);
+ }
+
+ NSRectClip (r);
+ /* Since we composite the bitmap instead of just blitting it, we need
+ to erase the whole background. */
+ [ns_lookup_indexed_color(face->background, f) set];
+ NSRectFill (r);
+ pt.y += p->h;
+ [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
+ [img compositeToPoint: pt operation: NSCompositeSourceOver];
+ }
+ ns_unfocus (f);
+}
+
+
+void
+ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
+ int x, int y, int cursor_type, int cursor_width,
+ int on_p, int active_p)
+/* --------------------------------------------------------------------------
+ External call (RIF): draw cursor
+ --------------------------------------------------------------------------
*/
+{
+ NSRect r, s;
+ int fx, fy, h;
+ struct frame *f = WINDOW_XFRAME (w);
+ struct glyph *phys_cursor_glyph;
+ int overspill;
+ unsigned char drawGlyph = 0, cursorType, oldCursorType;
+
+ NSTRACE (dumpcursor);
+
+ if (!on_p)
+ return;
+
+ w->phys_cursor_type = cursor_type;
+ w->phys_cursor_on_p = 1;
+
+ if (cursor_type == NO_CURSOR)
+ {
+ w->phys_cursor_width = 0;
+ return;
+ }
+
+ if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
+ {
+ if (glyph_row->exact_window_width_line_p
+ && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
+ {
+ glyph_row->cursor_in_fringe_p = 1;
+ draw_fringe_bitmap (w, glyph_row, 0);
+ }
+ return;
+ }
+
+ get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
+
+ r.origin.x = fx, r.origin.y = fy;
+ r.size.height = h;
+ r.size.width = w->phys_cursor_width;
+
+ /* PENDING: if we overwrite the internal border area, it does not get erased;
+ fix by truncating cursor, but better would be to erase properly */
+ overspill = r.origin.x + r.size.width -
+ WINDOW_TEXT_TO_FRAME_PIXEL_X (w, WINDOW_BOX_RIGHT_EDGE_X (w)
+ - WINDOW_TOTAL_FRINGE_WIDTH (w) - FRAME_INTERNAL_BORDER_WIDTH (f));
+ if (overspill > 0)
+ r.size.width -= overspill;
+
+ /* PENDING: 23: use emacs stored f->cursor_type instead of ns-specific */
+ oldCursorType = FRAME_CURSOR (f);
+ cursorType = FRAME_CURSOR (f) = FRAME_NEW_CURSOR (f);
+ f->output_data.ns->current_cursor_color =
+ f->output_data.ns->desired_cursor_color;
+
+ /* PENDING: only needed in rare cases with last-resort font in HELLO..
+ should we do this more efficiently? */
+ ns_clip_to_row (w, glyph_row, -1, NULL);
+/* ns_focus (f, &r, 1); */
+
+ if (FRAME_LAST_INACTIVE (f))
+ {
+ /* previously hollow box; clear entire area */
+ [FRAME_BACKGROUND_COLOR (f) set];
+ NSRectFill (r);
+ drawGlyph = 1;
+ FRAME_LAST_INACTIVE (f) = NO;
+ }
+
+ /* prepare to draw */
+ if (cursorType == no_highlight || cursor_type == NO_CURSOR)
+ {
+ /* clearing for blink: erase the cursor itself */
+ [FRAME_BACKGROUND_COLOR (f) set];
+ cursorType = oldCursorType; /* just clear what we had before */
+ }
+ else
+ [FRAME_CURSOR_COLOR (f) set];
+
+ if (!active_p)
+ {
+ /* inactive window: ignore what we just set and use a hollow box */
+ cursorType = hollow_box;
+ [FRAME_CURSOR_COLOR (f) set];
+ }
+
+ switch (cursorType)
+ {
+ case no_highlight:
+ break;
+ case filled_box:
+ NSRectFill (r);
+ drawGlyph = 1;
+ break;
+ case hollow_box:
+ NSRectFill (r);
+ [FRAME_BACKGROUND_COLOR (f) set];
+ NSRectFill (NSInsetRect (r, 1, 1));
+ [FRAME_CURSOR_COLOR (f) set];
+ drawGlyph = 1;
+ break;
+ case underscore:
+ s = r;
+ s.origin.y += lrint (0.75 * s.size.height);
+ s.size.height = lrint (s.size.height * 0.25);
+ NSRectFill (s);
+ break;
+ case bar:
+ s = r;
+ s.size.width = 1;
+ NSRectFill (s);
+ break;
+ }
+ ns_unfocus (f);
+
+ /* if needed, draw the character under the cursor */
+ if (drawGlyph)
+ draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
+}
+
+
+static void
+ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
+/* --------------------------------------------------------------------------
+ External (RIF): Draw a vertical line.
+ --------------------------------------------------------------------------
*/
+{
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+ struct face *face;
+ NSRect r = NSMakeRect (x, y0, 2, y1-y0);
+
+ face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
+ if (face)
+ [ns_lookup_indexed_color(face->foreground, f) set];
+
+ ns_focus (f, &r, 1);
+ NSDrawGroove (r, r);
+ ns_unfocus (f);
+}
+
+
+void
+show_hourglass (struct atimer *timer)
+{
+ if (hourglass_shown_p)
+ return;
+
+ BLOCK_INPUT;
+
+ /*PENDING: add NSProgressIndicator to selected frame (see macfns.c) */
+
+ hourglass_shown_p = 1;
+ UNBLOCK_INPUT;
+}
+
+
+void
+hide_hourglass ()
+{
+ if (!hourglass_shown_p)
+ return;
+
+ /*PENDING: remove NSProgressIndicator from all frames */
+
+ hourglass_shown_p = 0;
+ UNBLOCK_INPUT;
+}
+
+
+
+/* ==========================================================================
+
+ Glyph drawing operations
+
+ ==========================================================================
*/
+
+
+static inline NSRect
+/* --------------------------------------------------------------------------
+ Under NS we draw internal borders inside fringes, and want full-width
+ rendering to go all the way to edge. This function makes that correction.
+ --------------------------------------------------------------------------
*/
+ns_fix_rect_ibw (NSRect r, int fibw, int frame_pixel_width)
+{
+ if (r.origin.y <= fibw+1)
+ {
+ r.size.height += r.origin.y;
+ r.origin.y = 0;
+ }
+ if (r.origin.x <= fibw+1)
+ {
+ r.size.width += r.origin.x;
+ r.origin.x = 0;
+ }
+ if (frame_pixel_width - (r.origin.x+r.size.width) <= fibw+1)
+ r.size.width += fibw;
+
+ return r;
+}
+
+
+static int
+ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
+/* --------------------------------------------------------------------------
+ Wrapper utility to account for internal border width on full-width lines,
+ and allow top full-width rows to hit the frame top. nr should be pointer
+ to two successive NSRects. Number of rects actually used is returned.
+ --------------------------------------------------------------------------
*/
+{
+ int n = get_glyph_string_clip_rects (s, nr, 2);
+ if (s->row->full_width_p)
+ {
+ *nr = ns_fix_rect_ibw (*nr, FRAME_INTERNAL_BORDER_WIDTH (s->f),
+ FRAME_PIXEL_WIDTH (s->f));
+ if (n == 2)
+ *nr = ns_fix_rect_ibw (*(nr+1), FRAME_INTERNAL_BORDER_WIDTH (s->f),
+ FRAME_PIXEL_WIDTH (s->f));
+ }
+ return n;
+}
+
+
+static void
+ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char
right_p)
+/* --------------------------------------------------------------------------
+ Draw an unfilled rect inside r, optionally leaving left and/or right open.
+ Note we can't just use an NSDrawRect command, because of the possibility
+ of some sides not being drawn, and because the rect will be filled.
+ --------------------------------------------------------------------------
*/
+{
+ NSRect s = r;
+ [col set];
+
+ /* top, bottom */
+ s.size.height = thickness;
+ NSRectFill (s);
+ s.origin.y += r.size.height - thickness;
+ NSRectFill (s);
+
+ s.size.height = r.size.height;
+ s.origin.y = r.origin.y;
+
+ /* left, right (optional) */
+ s.size.width = thickness;
+ if (left_p)
+ NSRectFill (s);
+ if (right_p)
+ {
+ s.origin.x += r.size.width - thickness;
+ NSRectFill (s);
+ }
+}
+
+
+static void
+ns_draw_relief (NSRect r, int thickness, char raised_p,
+ char top_p, char bottom_p, char left_p, char right_p,
+ struct glyph_string *s)
+/* --------------------------------------------------------------------------
+ Draw a relief rect inside r, optionally leaving some sides open.
+ Note we can't just use an NSDrawBezel command, because of the possibility
+ of some sides not being drawn, and because the rect will be filled.
+ --------------------------------------------------------------------------
*/
+{
+ static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
+ NSColor *newBaseCol = nil;
+ NSRect sr = r;
+
+ NSTRACE (ns_draw_relief);
+
+ /* set up colors */
+
+ if (s->face->use_box_color_for_shadows_p)
+ {
+ newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
+ }
+/* else if (s->first_glyph->type == IMAGE_GLYPH
+ && s->img->pixmap
+ && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
+ {
+ newBaseCol = IMAGE_BACKGROUND (s->img, s->f, 0);
+ } */
+ else
+ {
+ newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
+ }
+
+ if (newBaseCol == nil)
+ newBaseCol = [NSColor grayColor];
+
+ if (newBaseCol != baseCol) /* PENDING: better check */
+ {
+ [baseCol release];
+ baseCol = [newBaseCol retain];
+ [lightCol release];
+ lightCol = [[baseCol highlightWithLevel: 0.2] retain];
+ [darkCol release];
+ darkCol = [[baseCol shadowWithLevel: 0.3] retain];
+ }
+
+ [(raised_p ? lightCol : darkCol) set];
+
+ /* TODO: mitering. Using NSBezierPath doesn't work because of color switch.
*/
+
+ /* top */
+ sr.size.height = thickness;
+ if (top_p) NSRectFill (sr);
+
+ /* left */
+ sr.size.height = r.size.height;
+ sr.size.width = thickness;
+ if (left_p) NSRectFill (sr);
+
+ [(raised_p ? darkCol : lightCol) set];
+
+ /* bottom */
+ sr.size.width = r.size.width;
+ sr.size.height = thickness;
+ sr.origin.y += r.size.height - thickness;
+ if (bottom_p) NSRectFill (sr);
+
+ /* right */
+ sr.size.height = r.size.height;
+ sr.origin.y = r.origin.y;
+ sr.size.width = thickness;
+ sr.origin.x += r.size.width - thickness;
+ if (right_p) NSRectFill (sr);
+}
+
+
+static void
+ns_dumpglyphs_box_or_relief (struct glyph_string *s)
+/* --------------------------------------------------------------------------
+ Function modeled after x_draw_glyph_string_box ().
+ Sets up parameters for drawing.
+ --------------------------------------------------------------------------
*/
+{
+ int right_x, last_x;
+ char left_p, right_p;
+ struct glyph *last_glyph;
+ NSRect r;
+ int thickness;
+ struct face *face;
+
+ if (s->hl == DRAW_MOUSE_FACE)
+ {
+ face = FACE_FROM_ID
+ (s->f, FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
+ if (!face)
+ face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
+ }
+ else
+ face = s->face;
+
+ thickness = face->box_line_width;
+
+ NSTRACE (ns_dumpglyphs_box_or_relief);
+
+ last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
+ ? WINDOW_RIGHT_EDGE_X (s->w)
+ : window_box_right (s->w, s->area));
+ last_glyph = (s->cmp || s->img
+ ? s->first_glyph : s->first_glyph + s->nchars-1);
+
+ right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
+ ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
+
+ left_p = (s->first_glyph->left_box_line_p
+ || (s->hl == DRAW_MOUSE_FACE
+ && (s->prev == NULL || s->prev->hl != s->hl)));
+ right_p = (last_glyph->right_box_line_p
+ || (s->hl == DRAW_MOUSE_FACE
+ && (s->next == NULL || s->next->hl != s->hl)));
+
+ r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
+
+ /* expand full-width row over internal borders */
+ if (s->row->full_width_p)
+ r = ns_fix_rect_ibw (r, FRAME_INTERNAL_BORDER_WIDTH (s->f),
+ FRAME_PIXEL_WIDTH (s->f));
+
+ if (s->face->box == FACE_SIMPLE_BOX)
+ {
+ xassert (s->face->box_color != nil);
+ ns_draw_box (r, abs (thickness),
+ ns_lookup_indexed_color (face->box_color, s->f),
+ left_p, right_p);
+ }
+ else
+ {
+ ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
+ 1, 1, left_p, right_p, s);
+ }
+}
+
+
+static void
+ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
+/* --------------------------------------------------------------------------
+ Modeled after x_draw_glyph_string_background, which draws BG in
+ certain cases. Others are left to the text rendering routine.
+ --------------------------------------------------------------------------
*/
+{
+ NSTRACE (ns_maybe_dumpglyphs_background);
+
+ if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
+ {
+ int box_line_width = max (s->face->box_line_width, 0);
+ if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
+ || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
+ {
+ struct face *face;
+ if (s->hl == DRAW_MOUSE_FACE)
+ {
+ face = FACE_FROM_ID
+ (s->f, FRAME_NS_DISPLAY_INFO (s->f)->mouse_face_face_id);
+ if (!face)
+ face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
+ }
+ else
+ face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
+ if (!face->stipple)
+ [(NS_FACE_BACKGROUND (face) != nil
+ ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
+ : FRAME_BACKGROUND_COLOR (s->f)) set];
+ else
+ {
+ struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
+ [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
+ }
+
+ if (s->hl != DRAW_CURSOR)
+ {
+ NSRect r = NSMakeRect (s->x, s->y + box_line_width,
+ s->background_width,
+ s->height-2*box_line_width);
+
+ /* expand full-width row over internal borders */
+ if (s->row->full_width_p)
+ {
+ int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
+ if (r.origin.y <= fibw+1 + box_line_width)
+ {
+ r.size.height += r.origin.y;
+ r.origin.y = 0;
+ }
+ if (r.origin.x <= fibw+1)
+ {
+ r.size.width += 2*r.origin.x;
+ r.origin.x = 0;
+ }
+ if (FRAME_PIXEL_WIDTH (s->f) - (r.origin.x + r.size.width)
+ <= fibw+1)
+ r.size.width += fibw;
+ }
+
+ NSRectFill (r);
+ }
+
+ s->background_filled_p = 1;
+ }
+ }
+}
+
+
+static void
+ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
+/* --------------------------------------------------------------------------
+ Renders an image and associated borders.
+ --------------------------------------------------------------------------
*/
+{
+ EmacsImage *img = s->img->pixmap;
+ int box_line_vwidth = max (s->face->box_line_width, 0);
+ int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
+ int bg_x, bg_y, bg_height;
+ int th;
+ char raised_p;
+ NSRect br;
+
+ NSTRACE (ns_dumpglyphs_image);
+
+ if (s->face->box != FACE_NO_BOX
+ && s->first_glyph->left_box_line_p && s->slice.x == 0)
+ x += abs (s->face->box_line_width);
+
+ bg_x = x;
+ bg_y = s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
+ bg_height = s->height;
+ /* other terms have this, but was causing problems w/tabbar mode */
+ /* - 2 * box_line_vwidth; */
+
+ if (s->slice.x == 0) x += s->img->hmargin;
+ if (s->slice.y == 0) y += s->img->vmargin;
+
+ /* Draw BG: if we need larger area than image itself cleared, do that,
+ otherwise, since we composite the image under NS (instead of mucking
+ with its background color), we must clear just the image area. */
+ [ns_lookup_indexed_color (NS_FACE_BACKGROUND
+ (FACE_FROM_ID (s->f, s->first_glyph->face_id)), s->f) set];
+
+ if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
+ || s->img->mask || s->img->pixmap == 0 || s->width !=
s->background_width)
+ {
+ br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
+ s->background_filled_p = 1;
+ }
+ else
+ {
+ br = NSMakeRect (x, y, s->slice.width, s->slice.height);
+ }
+
+ /* expand full-width row over internal borders */
+ if (s->row->full_width_p)
+ {
+ int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
+ if (br.origin.y <= fibw+1 + box_line_vwidth)
+ {
+ br.size.height += br.origin.y;
+ br.origin.y = 0;
+ }
+ if (br.origin.x <= fibw+1 + box_line_vwidth)
+ {
+ br.size.width += br.origin.x;
+ br.origin.x = 0;
+ }
+ if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) <= fibw+1)
+ br.size.width += fibw;
+ }
+
+ NSRectFill (br);
+
+ /* Draw the image.. do we need to draw placeholder if img ==nil? */
+ if (img != nil)
+ [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
+ operation: NSCompositeSourceOver];
+
+ /* Draw relief, if requested */
+ if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
+ {
+ if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
+ {
+ th = tool_bar_button_relief >= 0 ?
+ tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
+ raised_p = (s->hl == DRAW_IMAGE_RAISED);
+ }
+ else
+ {
+ th = abs (s->img->relief);
+ raised_p = (s->img->relief > 0);
+ }
+
+ r.origin.x = x - th;
+ r.origin.y = y - th;
+ r.size.width = s->slice.width + 2*th-1;
+ r.size.height = s->slice.height + 2*th-1;
+ ns_draw_relief (r, th, raised_p,
+ s->slice.y == 0,
+ s->slice.y + s->slice.height == s->img->height,
+ s->slice.x == 0,
+ s->slice.x + s->slice.width == s->img->width, s);
+ }
+}
+
+
+static void
+ns_draw_glyph_string (struct glyph_string *s)
+/* --------------------------------------------------------------------------
+ External (RIF): Main draw-text call.
+ --------------------------------------------------------------------------
*/
+{
+ /*PENDING (optimize): focus for box and contents draw */
+ NSRect r[2];
+ int n;
+ char box_drawn_p = 0;
+
+ NSTRACE (ns_draw_glyph_string);
+
+ if (s->next && s->right_overhang && !s->for_overlaps && s->hl != DRAW_CURSOR)
+ {
+ xassert (s->next->img == NULL);
+ n = ns_get_glyph_string_clip_rect (s->next, r);
+ ns_focus (s->f, r, n);
+ ns_maybe_dumpglyphs_background (s->next, 1);
+ ns_unfocus (s->f);
+ }
+
+ if (!s->for_overlaps && s->face->box != FACE_NO_BOX
+ && (s->first_glyph->type == CHAR_GLYPH
+ || s->first_glyph->type == COMPOSITE_GLYPH))
+ {
+ n = ns_get_glyph_string_clip_rect (s, r);
+ ns_focus (s->f, r, n);
+ ns_maybe_dumpglyphs_background (s, 1);
+ ns_dumpglyphs_box_or_relief (s);
+ ns_unfocus (s->f);
+ box_drawn_p = 1;
+ }
+
+ switch (s->first_glyph->type)
+ {
+
+ case IMAGE_GLYPH:
+ n = ns_get_glyph_string_clip_rect (s, r);
+ ns_focus (s->f, r, n);
+ ns_dumpglyphs_image (s, r[0]);
+ ns_unfocus (s->f);
+ break;
+
+ case STRETCH_GLYPH:
+ if (!s->background_filled_p)
+ {
+ *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
+
+ if (!s->row->full_width_p)
+ {
+ /* truncate to avoid overwriting fringe and/or scrollbar */
+ int overrun = max (0, (s->x + s->background_width)
+ - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
+ - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
+ r[0].size.width -= overrun;
+
+ /* PENDING: Try to work between problem where a stretch glyph on
+ a partially-visible bottom row will clear part of the
+ modeline, and another where list-buffers headers and similar
+ rows erroneously have visible_height set to 0. Not sure
+ where this is coming from as other terms seem not to show. */
+ r[0].size.height = min (s->height, s->row->visible_height);
+ }
+
+ /* expand full-width rows over internal borders */
+ else
+ {
+ r[0] = ns_fix_rect_ibw (r[0], FRAME_INTERNAL_BORDER_WIDTH (s->f),
+ FRAME_PIXEL_WIDTH (s->f));
+ }
+
+ /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
+ overwriting cursor (usually when cursor on a tab) */
+ if (s->hl == DRAW_CURSOR)
+ {
+ r[0].origin.x += s->width;
+ r[0].size.width -= s->width;
+ }
+
+ ns_focus (s->f, r, 1);
+ [ns_lookup_indexed_color (NS_FACE_BACKGROUND
+ (FACE_FROM_ID (s->f, s->first_glyph->face_id)), s->f) set];
+ NSRectFill (r[0]);
+ ns_unfocus (s->f);
+ s->background_filled_p = 1;
+ }
+ break;
+
+ case CHAR_GLYPH:
+ case COMPOSITE_GLYPH:
+ n = ns_get_glyph_string_clip_rect (s, r);
+ ns_focus (s->f, r, n);
+
+ if (s->for_overlaps || s->gidx > 0)
+ s->background_filled_p = 1;
+ else /* 1 */
+ ns_maybe_dumpglyphs_background
+ (s, s->first_glyph->type == COMPOSITE_GLYPH);
+
+ ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
+ (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
+ (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
+ NS_DUMPGLYPH_NORMAL));
+ ns_tmp_font = (struct nsfont_info *)s->face->font;
+ if (ns_tmp_font == ~0 || ns_tmp_font == NULL)
+ ns_tmp_font = FRAME_FONT (s->f);
+
+ ns_tmp_font->font.driver->draw
+ (s, 0, s->nchars, s->x, s->y,
+ (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
+ || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
+
+ ns_unfocus (s->f);
+ break;
+
+ default:
+ abort ();
+ }
+
+ /* Draw box if not done already. */
+ if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
+ {
+ n = ns_get_glyph_string_clip_rect (s, r);
+ ns_focus (s->f, r, n);
+ ns_dumpglyphs_box_or_relief (s);
+ ns_unfocus (s->f);
+ }
+
+}
+
+
+
+/* ==========================================================================
+
+ Event loop
+
+ ==========================================================================
*/
+
+
+static void
+ns_send_appdefined (int value)
+/* --------------------------------------------------------------------------
+ Internal: post an appdefined event which EmacsApp-sendEvent will
+ recognize and take as a command to halt the event loop.
+ --------------------------------------------------------------------------
*/
+{
+ /*NSTRACE (ns_send_appdefined); */
+
+ /* Only post this event if we haven't already posted one. This will end
+ the [NXApp run] main loop after having processed all events queued at
+ this moment. */
+ if (send_appdefined)
+ {
+ NSEvent *nxev;
+
+ /* We only need one NX_APPDEFINED event to stop NXApp from running. */
+ send_appdefined = NO;
+
+ /* Don't need wakeup timer any more */
+ if (timed_entry)
+ {
+ [timed_entry invalidate];
+ [timed_entry release];
+ timed_entry = nil;
+ }
+
+ /* Ditto for file descriptor poller */
+ if (fd_entry)
+ {
+ [fd_entry invalidate];
+ [fd_entry release];
+ fd_entry = nil;
+ }
+
+ nxev = [NSEvent otherEventWithType: NSApplicationDefined
+ location: NSMakePoint (0, 0)
+ modifierFlags: 0
+ timestamp: 0
+ windowNumber: [[NSApp mainWindow] windowNumber]
+ context: [NSApp context]
+ subtype: 0
+ data1: value
+ data2: 0];
+
+ /* Post an application defined event on the event queue. When this is
+ received the [NXApp run] will return, thus having processed all
+ events which are currently queued. */
+ [NSApp postEvent: nxev atStart: NO];
+ }
+}
+
+
+static int
+ns_read_socket (struct terminal *terminal, int expected,
+ struct input_event *hold_quit)
+/* --------------------------------------------------------------------------
+ External (hook): Post an event to ourself and keep reading events until
+ we read it back again. In effect process all events which were waiting.
+ 23: Now we have to manage the event buffer ourselves.
+ --------------------------------------------------------------------------
*/
+{
+ struct input_event ev;
+ int nevents;
+ static NSDate *lastCheck = nil;
+/* NSTRACE (ns_read_socket); */
+
+ if (interrupt_input_blocked)
+ {
+ interrupt_input_pending = 1;
+ return -1;
+ }
+
+ interrupt_input_pending = 0;
+ BLOCK_INPUT;
+
+#ifdef COCOA_EXPERIMENTAL_CTRL_G
+ /* causes Feval to abort; unclear on why this isn't in calling code */
+ ++handling_signal;
+#endif
+
+ n_emacs_events_pending = 0;
+ EVENT_INIT (ev);
+ emacs_event = &ev;
+ q_event_ptr = hold_quit;
+
+ /* we manage autorelease pools by allocate/reallocate each time around
+ the loop; strict nesting is occasionally violated but seems not to
+ matter.. earlier methods using full nesting caused major memory leaks */
+ [outerpool release];
+ outerpool = [[NSAutoreleasePool alloc] init];
+
+ /* If have pending open-file requests, attend to the next one of those. */
+ if (ns_pending_files && [ns_pending_files count] != 0
+ && [NSApp openFile: [ns_pending_files objectAtIndex: 0]])
+ {
+ [ns_pending_files removeObjectAtIndex: 0];
+ }
+ /* Deal with pending service requests. */
+ else if (ns_pending_service_names && [ns_pending_service_names count] != 0
+ && [NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
+ withArg: [ns_pending_service_args objectAtIndex: 0]])
+ {
+ [ns_pending_service_names removeObjectAtIndex: 0];
+ [ns_pending_service_args removeObjectAtIndex: 0];
+ }
+ else
+ {
+ /* Run and wait for events. We must always send one NX_APPDEFINED event
+ to ourself, otherwise [NXApp run] will never exit. */
+ send_appdefined = YES;
+
+ /*PENDING: from termhooks.h: */
+ /* XXX Please note that a non-zero value of EXPECTED only means that
+ there is available input on at least one of the currently opened
+ terminal devices -- but not necessarily on this device.
+ Therefore, in most cases EXPECTED should be simply ignored. */
+ /* However, if in ns_select, this is called from gobble_input, which
+ appears to set it correctly for our purposes, and always assuming
+ !expected causes 100% CPU usage. */
+ if (!inNsSelect || !expected)
+ {
+ /* Post an application defined event on the event queue. When this
is
+ received the [NXApp run] will return, thus having processed all
+ events which are currently queued, if any. */
+ ns_send_appdefined (-1);
+ }
+
+ [NSApp run];
+ }
+
+ nevents = n_emacs_events_pending;
+ n_emacs_events_pending = 0;
+ emacs_event = q_event_ptr = NULL;
+
+#ifdef COCOA_EXPERIMENTAL_CTRL_G
+ --handling_signal;
+#endif
+ UNBLOCK_INPUT;
+ return nevents;
+}
+
+
+int
+ns_select (int nfds, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, struct timeval *timeout)
+/* --------------------------------------------------------------------------
+ Replacement for select, checking for events
+ --------------------------------------------------------------------------
*/
+{
+ int result;
+ double time;
+ NSEvent *ev;
+/* NSTRACE (ns_select); */
+
+ if (NSApp == nil /* || ([NSApp isActive] == NO &&
+ [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil
+ inMode:NSDefaultRunLoopMode dequeue:NO] == nil) */)
+ return select (nfds, readfds, writefds, exceptfds, timeout);
+
+ /* Save file descriptor set, which gets overwritten in calls to select ()
+ Note, this is called from process.c, and only readfds is ever set */
+ if (readfds)
+ {
+ memcpy (&select_readfds, readfds, sizeof (fd_set));
+ select_nfds = nfds;
+ }
+ else
+ select_nfds = 0;
+
+ /* Try an initial select for pending data on input files */
+ select_timeout.tv_sec = select_timeout.tv_usec = 0;
+ result = select (nfds, readfds, writefds, exceptfds, &select_timeout);
+ if (result)
+ return result;
+
+ /* if (!timeout || timed_entry || fd_entry)
+ fprintf (stderr, "assertion failed: timeout null or
timed_entry/fd_entry non-null in ns_select\n"); */
+
+ /* set a timeout and run the main AppKit event loop while continuing
+ to monitor the files */
+ time = ((double) timeout->tv_sec) + ((double) timeout->tv_usec)/1000000.0;
+ timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
+ target: NSApp
+ selector: @selector (timeout_handler:)
+ userInfo: 0
+ repeats: YES] /* for safe removal */
+ retain];
+
+ /* set a periodic task to try the select () again */
+ fd_entry = [[NSTimer scheduledTimerWithTimeInterval: 0.1
+ target: NSApp
+ selector: @selector (fd_handler:)
+ userInfo: 0
+ repeats: YES]
+ retain];
+
+ if (!NILP (ns_cursor_blink_mode) && !cursor_blink_entry)
+ {
+ if (!NUMBERP (ns_cursor_blink_rate))
+ ns_cursor_blink_rate = make_float (0.5);
+ cursor_blink_entry = [[NSTimer
+ scheduledTimerWithTimeInterval: XFLOATINT (ns_cursor_blink_rate)
+ target: NSApp
+ selector: @selector (cursor_blink_handler:)
+ userInfo: 0
+ repeats: YES]
+ retain];
+ }
+ else if (NILP (ns_cursor_blink_mode) && cursor_blink_entry)
+ {
+ if (NUMBERP (ns_cursor_blink_rate))
+ ns_cursor_blink_rate = Qnil;
+ struct ns_display_info *dpyinfo = ns_display_list; /* HACK */
+ [cursor_blink_entry invalidate];
+ [cursor_blink_entry release];
+ cursor_blink_entry = 0;
+ if (dpyinfo->ns_highlight_frame)
+ {
+ Lisp_Object tem =
+ get_frame_param (dpyinfo->ns_highlight_frame, Qcursor_type);
+ dpyinfo->ns_highlight_frame->output_data.ns->desired_cursor =
+ ns_lisp_to_cursor_type (tem);
+ }
+ }
+
+ /* Let Application dispatch events until it receives an event of the type
+ NX_APPDEFINED, which should only be sent by timeout_handler. */
+ inNsSelect = 1;
+ gobble_input (timeout ? 1 : 0);
+ ev = last_appdefined_event;
+ inNsSelect = 0;
+
+ if (ev)
+ {
+ int t;
+ if ([ev type] != NSApplicationDefined)
+ abort ();
+
+ t = [ev data1];
+ last_appdefined_event = 0;
+
+ if (t == -2)
+ {
+ /* The NX_APPDEFINED event we received was a timeout. */
+ return 0;
+ }
+ else if (t == -1)
+ {
+ /* The NX_APPDEFINED event we received was the result of
+ at least one real input event arriving. */
+ errno = EINTR;
+ return -1;
+ }
+ else
+ {
+ /* Received back from select () in fd_handler; copy the results */
+ if (readfds)
+ memcpy (readfds, &select_readfds, sizeof (fd_set));
+ return t;
+ }
+ }
+ /* never reached, shut compiler up */
+ return 0;
+}
+
+
+
+/* ==========================================================================
+
+ Scrollbar handling
+
+ ==========================================================================
*/
+
+
+static void
+ns_set_vertical_scroll_bar (struct window *window,
+ int portion, int whole, int position)
+/* --------------------------------------------------------------------------
+ External (hook): Update or add scrollbar
+ --------------------------------------------------------------------------
*/
+{
+ Lisp_Object win;
+ NSRect r, v;
+ struct frame *f = XFRAME (WINDOW_FRAME (window));
+ EmacsView *view = FRAME_NS_VIEW (f);
+ int window_y, window_height;
+ BOOL barOnVeryLeft, barOnVeryRight;
+ int top, left, height, width, sb_width, sb_left;
+ EmacsScroller *bar;
+static int count = 0;
+
+ /* optimization; display engine sends WAY too many of these.. */
+ if (!NILP (window->vertical_scroll_bar))
+ {
+ bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
+ if ([bar checkSamePosition: position portion: portion whole: whole])
+ {
+ if (view->scrollbarsNeedingUpdate == 0)
+ {
+ if (!windows_or_buffers_changed)
+ return;
+ }
+ else
+ view->scrollbarsNeedingUpdate--;
+ }
+ }
+
+ NSTRACE (ns_set_vertical_scroll_bar);
+
+ /* Get dimensions. */
+ window_box (window, -1, 0, &window_y, 0, &window_height);
+ top = window_y;
+ height = window_height;
+ width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
+ left = WINDOW_SCROLL_BAR_AREA_X (window);
+
+ if (top < 5) /* top scrollbar adjustment */
+ {
+ top -= FRAME_INTERNAL_BORDER_WIDTH (f);
+ height += FRAME_INTERNAL_BORDER_WIDTH (f);
+ }
+
+ /* allow for displaying a skinnier scrollbar than char area allotted */
+ sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
+ WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
+
+ barOnVeryLeft = left < 5;
+ barOnVeryRight = FRAME_PIXEL_WIDTH (f) - left - width < 5;
+ sb_left = left + FRAME_INTERNAL_BORDER_WIDTH (f)
+ * (barOnVeryLeft ? -1 : (barOnVeryRight ? 1 : 0));
+
+ r = NSMakeRect (sb_left, top, sb_width, height);
+ /* the parent view is flipped, so we need to flip y value */
+ v = [view frame];
+ r.origin.y = (v.size.height - r.size.height - r.origin.y);
+
+ XSETWINDOW (win, window);
+ BLOCK_INPUT;
+
+ /* we want at least 5 lines to display a scrollbar */
+ if (WINDOW_TOTAL_LINES (window) < 5)
+ {
+ if (!NILP (window->vertical_scroll_bar))
+ {
+ bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
+ [bar removeFromSuperview];
+ window->vertical_scroll_bar = Qnil;
+ }
+ ns_clear_frame_area (f, sb_left, top, width, height);
+ UNBLOCK_INPUT;
+ return;
+ }
+
+ if (NILP (window->vertical_scroll_bar))
+ {
+ ns_clear_frame_area (f, sb_left, top, width, height);
+ bar = [[EmacsScroller alloc] initFrame: r window: win];
+ window->vertical_scroll_bar = make_save_value (bar, 0);
+ }
+ else
+ {
+ NSRect oldRect;
+ bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
+ oldRect = [bar frame];
+ r.size.width = oldRect.size.width;
+ if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
+ {
+ if (oldRect.origin.x != r.origin.x)
+ ns_clear_frame_area (f, sb_left, top, width, height);
+ [bar setFrame: r];
+ }
+ }
+
+ [bar setPosition: position portion: portion whole: whole];
+ UNBLOCK_INPUT;
+}
+
+
+static void
+ns_condemn_scroll_bars (struct frame *f)
+/* --------------------------------------------------------------------------
+ External (hook): arrange for all frame's scrollbars to be removed
+ at next call to judge_scroll_bars, except for those redeemed.
+ --------------------------------------------------------------------------
*/
+{
+ int i;
+ id view;
+ NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
+
+ NSTRACE (ns_condemn_scroll_bars);
+
+ for (i =[subviews count]-1; i >= 0; i--)
+ {
+ view = [subviews objectAtIndex: i];
+ if ([view isKindOfClass: [EmacsScroller class]])
+ [view condemn];
+ }
+}
+
+
+static void
+ns_redeem_scroll_bar (struct window *window)
+/* --------------------------------------------------------------------------
+ External (hook): arrange to spare this window's scrollbar
+ at next call to judge_scroll_bars.
+ --------------------------------------------------------------------------
*/
+{
+ id bar;
+ NSTRACE (ns_redeem_scroll_bar);
+ if (!NILP (window->vertical_scroll_bar))
+ {
+ bar =XNS_SCROLL_BAR (window->vertical_scroll_bar);
+ [bar reprieve];
+ }
+}
+
+
+static void
+ns_judge_scroll_bars (struct frame *f)
+/* --------------------------------------------------------------------------
+ External (hook): destroy all scrollbars on frame that weren't
+ redeemed after call to condemn_scroll_bars.
+ --------------------------------------------------------------------------
*/
+{
+ int i;
+ id view;
+ NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
+ NSTRACE (ns_judge_scroll_bars);
+ for (i =[subviews count]-1; i >= 0; i--)
+ {
+ view = [subviews objectAtIndex: i];
+ if (![view isKindOfClass: [EmacsScroller class]]) continue;
+ [view judge];
+ }
+}
+
+
+
+/* ==========================================================================
+
+ Miscellaneous, mainly stubbed-out functions added in 23
+
+ ==========================================================================
*/
+
+
+void
+x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
+{
+}
+
+
+
+/* ==========================================================================
+
+ Initialization
+
+ ==========================================================================
*/
+
+static Lisp_Object ns_string_to_lispmod (char *s)
+/* --------------------------------------------------------------------------
+ Convert modifier name to lisp symbol
+ --------------------------------------------------------------------------
*/
+{
+ if (!strncmp (SDATA (SYMBOL_NAME (Qmeta)), s, 10))
+ return Qmeta;
+ else if (!strncmp (SDATA (SYMBOL_NAME (Qsuper)), s, 10))
+ return Qsuper;
+ else if (!strncmp (SDATA (SYMBOL_NAME (Qcontrol)), s, 10))
+ return Qcontrol;
+ else if (!strncmp (SDATA (SYMBOL_NAME (Qalt)), s, 10))
+ return Qalt;
+ else if (!strncmp (SDATA (SYMBOL_NAME (Qhyper)), s, 10))
+ return Qhyper;
+ else if (!strncmp (SDATA (SYMBOL_NAME (Qnone)), s, 10))
+ return Qnone;
+ else
+ return Qnil;
+}
+
+
+static Lisp_Object ns_mod_to_lisp (int m)
+/* --------------------------------------------------------------------------
+ Convert modifier code (see lisp.h) to lisp symbol
+ --------------------------------------------------------------------------
*/
+{
+ if (m == CHAR_META)
+ return Qmeta;
+ else if (m == CHAR_SUPER)
+ return Qsuper;
+ else if (m == CHAR_CTL)
+ return Qcontrol;
+ else if (m == CHAR_ALT)
+ return Qalt;
+ else if (m == CHAR_HYPER)
+ return Qhyper;
+ else /* if (m == 0) */
+ return Qnone;
+}
+
+
+static void
+ns_set_default_prefs ()
+/* --------------------------------------------------------------------------
+ Initialize preference variables to defaults
+ --------------------------------------------------------------------------
*/
+{
+ ns_alternate_modifier = Qmeta;
+ ns_command_modifier = Qsuper;
+ ns_control_modifier = Qcontrol;
+ ns_function_modifier = Qnone;
+ ns_cursor_blink_rate = Qnil;
+ ns_cursor_blink_mode = Qnil;
+ ns_expand_space = make_float (0.0);
+ ns_antialias_text = YES;
+ ns_antialias_threshold = 10.0;
+ ns_use_qd_smoothing = NO;
+ ns_use_system_highlight_color = YES;
+}
+
+
+static void
+ns_default (const char *parameter, Lisp_Object *result,
+ Lisp_Object yesval, Lisp_Object noval,
+ BOOL is_float, BOOL is_modstring)
+/* --------------------------------------------------------------------------
+ Check a parameter value in user's preferences
+ --------------------------------------------------------------------------
*/
+{
+ const char *value;
+
+ if ( (value =[[[NSUserDefaults standardUserDefaults]
+ stringForKey: [NSString stringWithUTF8String: parameter]]
+ UTF8String]) )
+ {
+ double f;
+ char *pos;
+ if (strcasecmp (value, "YES") == 0)
+ *result = yesval;
+ else if (strcasecmp (value, "NO") == 0)
+ *result = noval;
+ else if (is_float && (f = strtod (value, &pos), pos != value))
+ *result = make_float (f);
+ else if (is_modstring && value)
+ *result = ns_string_to_lispmod (value);
+ else fprintf (stderr,
+ "Bad value for default \"%s\": \"%s\"\n", parameter, value);
+ }
+}
+
+
+void
+ns_initialize_display_info (struct ns_display_info *dpyinfo)
+/* --------------------------------------------------------------------------
+ Initialize global info and storage for display.
+ --------------------------------------------------------------------------
*/
+{
+ NSScreen *screen = [NSScreen mainScreen];
+ NSWindowDepth depth = [screen depth];
+
+ dpyinfo->width = [screen frame].size.width;
+ dpyinfo->height = [screen frame].size.height;
+ dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected
*/
+ dpyinfo->resy = 72.27;
+ dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
+ NSColorSpaceFromDepth
(depth)]
+ && ![NSCalibratedWhiteColorSpace isEqualToString:
+ NSColorSpaceFromDepth
(depth)];
+ dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
+ dpyinfo->image_cache = make_image_cache ();
+ dpyinfo->color_table =
+ (struct ns_color_table *)xmalloc (sizeof (struct ns_color_table));
+ dpyinfo->color_table->colors = NULL;
+ dpyinfo->root_window = 42; /* a placeholder.. */
+
+ dpyinfo->mouse_face_mouse_frame = NULL;
+ dpyinfo->mouse_face_deferred_gc = 0;
+ dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
+ dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
+ dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
+ dpyinfo->mouse_face_window = dpyinfo->mouse_face_overlay = Qnil;
+ dpyinfo->mouse_face_hidden = 0;
+
+ dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
+ dpyinfo->mouse_face_defer = 0;
+
+ dpyinfo->ns_highlight_frame = dpyinfo->ns_focus_frame = NULL;
+
+ dpyinfo->n_fonts = 0;
+ dpyinfo->smallest_font_height = 1;
+ dpyinfo->smallest_char_width = 1;
+}
+
+
+/* 23: Needed as new part of display engine; this and next define public
+ functions in this file (well, many of them, anyway). */
+/* x_... are generic versions in xdisp.c that we, and other terms, get away
+ with using despite presence in the "system dependent" redisplay
+ interface. In addition, many of the ns_ methods have code that is
+ shared with all terms, indicating need for further refactoring. */
+extern frame_parm_handler ns_frame_parm_handlers[];
+static struct redisplay_interface ns_redisplay_interface =
+{
+ ns_frame_parm_handlers,
+ x_produce_glyphs, /*generic OK */
+ x_write_glyphs, /*generic OK */
+ x_insert_glyphs, /*generic OK */
+ x_clear_end_of_line, /*generic OK */
+ ns_scroll_run, /*23 */
+ ns_after_update_window_line, /*23: added */
+ ns_update_window_begin, /*23: split from update_begin */
+ ns_update_window_end, /*23: split from update_end */
+ x_cursor_to, /*generic OK */
+ ns_flush,
+ 0, /* flush_display_optional */
+ x_clear_window_mouse_face, /*generic OK */
+ x_get_glyph_overhangs, /*23: generic OK */
+ x_fix_overlapping_area, /*generic OK */
+ ns_draw_fringe_bitmap, /*23 */
+ 0, /* define_fringe_bitmap */ /*PENDING: simplify ns_draw_fringe_bitmap? */
+ 0, /* destroy_fringe_bitmap */
+ ns_compute_glyph_string_overhangs, /*23 */
+ ns_draw_glyph_string, /*23: interface to nsfont.m */
+ ns_define_frame_cursor, /*23 */
+ ns_clear_frame_area, /*23 */
+ ns_draw_window_cursor, /*23: revamped ns_dumpcursor */
+ ns_draw_vertical_window_border,
+ ns_shift_glyphs_for_insert
+};
+
+
+static void
+ns_delete_display (struct ns_display_info *dpyinfo)
+{
+ /*PENDING... */
+}
+
+
+/* This function is called when the last frame on a display is deleted. */
+static void
+ns_delete_terminal (struct terminal *terminal)
+{
+ struct ns_display_info *dpyinfo = terminal->display_info.ns;
+ int i;
+
+ /* Protect against recursive calls. Fdelete_frame in
+ delete_terminal calls us back when it deletes our last frame. */
+ if (!terminal->name)
+ return;
+
+ BLOCK_INPUT;
+
+ x_destroy_all_bitmaps (dpyinfo);
+ ns_delete_display (dpyinfo);
+ UNBLOCK_INPUT;
+}
+
+
+static struct terminal *
+ns_create_terminal (struct ns_display_info *dpyinfo)
+/* --------------------------------------------------------------------------
+ Set up use of NS before we make the first connection.
+ --------------------------------------------------------------------------
*/
+{
+ struct terminal *terminal;
+
+ NSTRACE (ns_create_terminal);
+
+ terminal = create_terminal ();
+
+ terminal->type = output_ns;
+ terminal->display_info.ns = dpyinfo;
+ dpyinfo->terminal = terminal;
+
+ terminal->rif = &ns_redisplay_interface;
+
+ terminal->clear_frame_hook = ns_clear_frame;
+ terminal->ins_del_lines_hook = 0; /* 23: vestigial? */
+ terminal->delete_glyphs_hook = 0; /* 23: vestigial? */
+ terminal->ring_bell_hook = ns_ring_bell;
+ terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
+ terminal->set_terminal_modes_hook = ns_set_terminal_modes;
+ terminal->update_begin_hook = ns_update_begin;
+ terminal->update_end_hook = ns_update_end;
+ terminal->set_terminal_window_hook = NULL; /* 23: vestigial? */
+ terminal->read_socket_hook = ns_read_socket;
+ terminal->frame_up_to_date_hook = ns_frame_up_to_date;
+ terminal->mouse_position_hook = ns_mouse_position;
+ terminal->frame_rehighlight_hook = ns_frame_rehighlight;
+ terminal->frame_raise_lower_hook = ns_frame_raise_lower;
+
+ terminal->fullscreen_hook = 0; /*XTfullscreen_hook;//23.50 */
+
+ terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
+ terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
+ terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
+ terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
+
+ terminal->delete_frame_hook = x_destroy_window;
+ terminal->delete_terminal_hook = ns_delete_terminal;
+
+ terminal->scroll_region_ok = 1;
+ terminal->char_ins_del_ok = 1;
+ terminal->line_ins_del_ok = 1;
+ terminal->fast_clear_end_of_line = 1;
+ terminal->memory_below_frame = 0;
+
+ return terminal;
+}
+
+
+void
+ns_initialize ()
+/* --------------------------------------------------------------------------
+ Mainly vestigial under NS now that ns_create_terminal () does most things.
+ --------------------------------------------------------------------------
*/
+{
+ baud_rate = 38400;
+ Fset_input_interrupt_mode (Qt);
+}
+
+
+struct ns_display_info *
+ns_term_init (Lisp_Object display_name)
+/* --------------------------------------------------------------------------
+ Start the Application and get things rolling.
+ --------------------------------------------------------------------------
*/
+{
+ extern Lisp_Object Fset_input_mode (Lisp_Object, Lisp_Object,
+ Lisp_Object, Lisp_Object);
+ struct terminal *terminal;
+ struct ns_display_info *dpyinfo;
+ static int ns_initialized = 0;
+ Lisp_Object tmp;
+
+ NSTRACE (ns_term_init);
+
+ /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
+ /*GSDebugAllocationActive (YES); */
+ BLOCK_INPUT;
+handling_signal = 0;
+
+ if (!ns_initialized)
+ {
+ ns_initialize ();
+ ns_initialized = 1;
+ }
+
+ ns_pending_files = [[NSMutableArray alloc] init];
+ ns_pending_service_names = [[NSMutableArray alloc] init];
+ ns_pending_service_args = [[NSMutableArray alloc] init];
+
+ /* Start app and create the main menu, window, view.
+ Needs to be here because ns_initialize_display_info () uses AppKit
classes.
+ The view will then ask the NSApp to stop and return to Emacs. */
+ [EmacsApp sharedApplication];
+ if (NSApp == nil)
+ return NULL;
+ [NSApp setDelegate: NSApp];
+
+ /* debugging: log all notifications */
+ /* [[NSNotificationCenter defaultCenter] addObserver: NSApp
+ selector: @selector (logNotification:)
+ name: nil object: nil]; */
+
+ dpyinfo = (struct ns_display_info *)xmalloc (sizeof (struct
ns_display_info));
+ bzero (dpyinfo, sizeof (struct ns_display_info));
+
+ ns_initialize_display_info (dpyinfo);
+ terminal = ns_create_terminal (dpyinfo);
+
+ terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
+ init_kboard (terminal->kboard);
+ terminal->kboard->Vwindow_system = Qns;
+ terminal->kboard->next_kboard = all_kboards;
+ all_kboards = terminal->kboard;
+ /* Don't let the initial kboard remain current longer than necessary.
+ That would cause problems if a file loaded on startup tries to
+ prompt in the mini-buffer. */
+ if (current_kboard == initial_kboard)
+ current_kboard = terminal->kboard;
+ terminal->kboard->reference_count++;
+
+ dpyinfo->next = ns_display_list;
+ ns_display_list = dpyinfo;
+
+ /* Put it on ns_display_name_list */
+ ns_display_name_list = Fcons (Fcons (display_name, Qnil),
+ ns_display_name_list);
+/* ns_display_name_list = Fcons (Fcons (display_name,
+ Fcons (Qnil, dpyinfo->xrdb)),
+ ns_display_name_list); */
+ dpyinfo->name_list_element = XCAR (ns_display_name_list);
+
+ /* Set the name of the terminal. */
+ terminal->name = (char *) xmalloc (SBYTES (display_name) + 1);
+ strncpy (terminal->name, SDATA (display_name), SBYTES (display_name));
+ terminal->name[SBYTES (display_name)] = 0;
+
+ UNBLOCK_INPUT;
+
+ /* Read various user defaults. */
+ ns_set_default_prefs ();
+ ns_default ("AlternateModifier", &ns_alternate_modifier,
+ Qnil, Qnil, NO, YES);
+ if (NILP (ns_alternate_modifier))
+ ns_alternate_modifier = Qmeta;
+ ns_default ("CommandModifier", &ns_command_modifier,
+ Qnil, Qnil, NO, YES);
+ if (NILP (ns_command_modifier))
+ ns_command_modifier = Qsuper;
+ ns_default ("ControlModifier", &ns_control_modifier,
+ Qnil, Qnil, NO, YES);
+ if (NILP (ns_control_modifier))
+ ns_control_modifier = Qcontrol;
+ ns_default ("FunctionModifier", &ns_function_modifier,
+ Qnil, Qnil, NO, YES);
+ if (NILP (ns_function_modifier))
+ ns_function_modifier = Qnone;
+ ns_default ("CursorBlinkRate", &ns_cursor_blink_rate,
+ make_float (0.5), Qnil, YES, NO);
+ if (NUMBERP (ns_cursor_blink_rate))
+ ns_cursor_blink_mode = Qt;
+ ns_default ("ExpandSpace", &ns_expand_space,
+ make_float (0.5), make_float (0.0), YES, NO);
+ ns_default ("GSFontAntiAlias", &ns_antialias_text,
+ YES, NO, NO, NO);
+ tmp = Qnil;
+ ns_default ("AppleAntiAliasingThreshold", &tmp,
+ make_float (10.0), make_float (6.0), YES, NO);
+ ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
+ ns_default ("UseQuickdrawSmoothing", &ns_use_qd_smoothing,
+ YES, NO, NO, NO);
+ ns_default ("UseSystemHighlightColor", &ns_use_system_highlight_color,
+ YES, NO, NO, NO);
+ if (ns_use_system_highlight_color == YES)
+ {
+ ns_selection_color = [[NSUserDefaults standardUserDefaults]
+ stringForKey: @"AppleHighlightColor"];
+ if (ns_selection_color == nil)
+ ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
+ }
+ else
+ ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
+
+ {
+ id cl;
+ Lisp_Object tem, tem1;
+ extern Lisp_Object Vsource_directory;
+
+ cl = [NSColorList colorListNamed: @"Emacs"];
+
+ if ( cl == nil )
+ {
+ /* first try data_dir, then invocation-dir
+ and finally source-directory/etc */
+ tem1 = tem =
+ Fexpand_file_name (build_string ("Emacs.clr"), Vdata_directory);
+ if (NILP (Ffile_exists_p (tem)))
+ {
+ tem = Fexpand_file_name (build_string ("Emacs.clr"),
+ Vinvocation_directory);
+ if (NILP (Ffile_exists_p (tem)))
+ {
+ Lisp_Object newdir =
+ Fexpand_file_name (build_string ("etc/"),
+ Vsource_directory);
+ tem = Fexpand_file_name (build_string ("Emacs.clr"),
+ newdir);
+ }
+ }
+
+ cl = [[NSColorList alloc]
+ initWithName: @"Emacs"
+ fromFile: [NSString stringWithCString: XSTRING
(tem)->data]];
+ if (cl ==nil)
+ fatal ("Could not find %s.\n", XSTRING (tem1)->data);
+ [cl writeToFile: nil];
+ }
+ }
+
+ {
+ char c[128];
+#ifdef NS_IMPL_GNUSTEP
+ strncpy (c, gnustep_base_version, sizeof (c));
+#else
+ /*PSnextrelease (128, c); */
+ snprintf (c, sizeof (c), "%g", NSAppKitVersionNumber);
+#endif
+ Vwindow_system_version = build_string (c);
+ }
+
+ delete_keyboard_wait_descriptor (0);
+
+/* Set up OS X app menu */
+#ifdef NS_IMPL_COCOA
+ {
+ NSMenu *appMenu;
+ id<NSMenuItem> item;
+ /* set up the application menu */
+ svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
+ [svcsMenu setAutoenablesItems: NO];
+ appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
+ [appMenu setAutoenablesItems: NO];
+ mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
+
+ [appMenu insertItemWithTitle: @"About Emacs"
+ action: @selector (orderFrontStandardAboutPanel:)
+ keyEquivalent: @""
+ atIndex: 0];
+ [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
+ [appMenu insertItemWithTitle: @"Preferences..."
+ action: @selector (showPreferencesWindow:)
+ keyEquivalent: @","
+ atIndex: 2];
+ [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
+ item = [appMenu insertItemWithTitle: @"Services"
+ action: @selector (menuDown:)
+ keyEquivalent: @""
+ atIndex: 4];
+ [appMenu setSubmenu: svcsMenu forItem: item];
+/* [svcsMenu setSupercell: item]; */
+ [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
+ [appMenu insertItemWithTitle: @"Hide Emacs"
+ action: @selector (hide:)
+ keyEquivalent: @"h"
+ atIndex: 6];
+ item = [appMenu insertItemWithTitle: @"Hide Others"
+ action: @selector (hideOtherApplications:)
+ keyEquivalent: @"h"
+ atIndex: 7];
+ [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
+ [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
+ [appMenu insertItemWithTitle: @"Quit Emacs"
+ action: @selector (terminate:)
+ keyEquivalent: @"q"
+ atIndex: 9];
+
+ item = [mainMenu insertItemWithTitle: @"Emacs"
+ action: @selector (menuDown:)
+ keyEquivalent: @""
+ atIndex: 0];
+ [mainMenu setSubmenu: appMenu forItem: item];
+
+ [NSApp setMainMenu: mainMenu];
+ [NSApp setAppleMenu: appMenu];
+ [NSApp setServicesMenu: svcsMenu];
+ /* Needed at least on Cocoa, to get dock menu to show windows */
+ [NSApp setWindowsMenu: [[NSMenu alloc] init]];
+ }
+#endif /* MAC OS X menu setup */
+
+ [NSApp run];
+
+ return dpyinfo;
+}
+
+
+extern Lisp_Object Vauto_save_list_file_name;
+void
+ns_term_shutdown (int sig)
+{
+ /* code not reached in emacs.c after this is called by shut_down_emacs: */
+ if (STRINGP (Vauto_save_list_file_name))
+ unlink (XSTRING (Vauto_save_list_file_name)->data);
+
+ ns_shutdown_properly = YES;
+ [NSApp terminate: NSApp];
+}
+
+
+void
+syms_of_nsterm ()
+{
+ NSTRACE (syms_of_nsterm);
+ DEFVAR_LISP ("ns-input-file", &ns_input_file,
+ "The file specified in the last NS event.");
+ ns_input_file =Qnil;
+
+ DEFVAR_LISP ("ns-input-text", &ns_input_text,
+ "The data received in the last NS text drag event.");
+ ns_input_text =Qnil;
+
+ DEFVAR_LISP ("ns-working-text", &ns_working_text,
+ "String for visualizing working composition sequence.");
+ ns_working_text =Qnil;
+
+ DEFVAR_LISP ("ns-input-font", &ns_input_font,
+ "The font specified in the last NS event.");
+ ns_input_font =Qnil;
+
+ DEFVAR_LISP ("ns-input-fontsize", &ns_input_fontsize,
+ "The fontsize specified in the last NS event.");
+ ns_input_fontsize =Qnil;
+
+ DEFVAR_LISP ("ns-input-line", &ns_input_line,
+ "The line specified in the last NS event.");
+ ns_input_line =Qnil;
+
+ DEFVAR_LISP ("ns-input-color", &ns_input_color,
+ "The color specified in the last NS event.");
+ ns_input_color =Qnil;
+
+ DEFVAR_LISP ("ns-input-spi-name", &ns_input_spi_name,
+ "The service name specified in the last NS event.");
+ ns_input_spi_name =Qnil;
+
+ DEFVAR_LISP ("ns-input-spi-arg", &ns_input_spi_arg,
+ "The service argument specified in the last NS event.");
+ ns_input_spi_arg =Qnil;
+
+ DEFVAR_LISP ("ns-alternate-modifier", &ns_alternate_modifier,
+ "This variable describes the behavior of the alternate or
option key.\n\
+Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
+Set to none means that the alternate / option key is not interpreted by
Emacs\n\
+at all, allowing it to be used at a lower level for accented character
entry.");
+
+ DEFVAR_LISP ("ns-command-modifier", &ns_command_modifier,
+ "This variable describes the behavior of the command key.\n\
+Set to control, meta, alt, super, or hyper means it is taken to be that key.");
+
+ DEFVAR_LISP ("ns-control-modifier", &ns_control_modifier,
+ "This variable describes the behavior of the control key.\n\
+Set to control, meta, alt, super, or hyper means it is taken to be that key.");
+
+ DEFVAR_LISP ("ns-function-modifier", &ns_function_modifier,
+ "This variable describes the behavior of the function key (on
laptops).\n\
+Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
+Set to none means that the function key is not interpreted by Emacs at all,\n\
+allowing it to be used at a lower level for accented character entry.");
+
+ DEFVAR_LISP ("ns-cursor-blink-rate", &ns_cursor_blink_rate,
+ "Rate at which the Emacs cursor blinks (in seconds).\n\
+Set to nil to disable blinking.");
+
+ DEFVAR_LISP ("ns-cursor-blink-mode", &ns_cursor_blink_mode,
+ "Internal variable -- use M-x blink-cursor-mode or
preferences\n\
+panel to control this setting.");
+
+ DEFVAR_LISP ("ns-expand-space", &ns_expand_space,
+ "Amount by which spacing between lines is expanded (positive)\n\
+or shrunk (negative). Zero (the default) means standard line height.\n\
+(This variable should only be read, never set.)");
+
+ DEFVAR_BOOL ("ns-antialias-text", &ns_antialias_text,
+ "Non-nil (the default) means to render text antialiased. Only
has an effect on OS X Panther and above.");
+
+ DEFVAR_BOOL ("ns-use-qd-smoothing", &ns_use_qd_smoothing,
+ "Whether to render text using QuickDraw (less heavy)
antialiasing. Only has an effect on OS X Panther and above. Default is nil
(use Quartz smoothing).");
+
+ DEFVAR_BOOL ("ns-use-system-highlight-color",
+ &ns_use_system_highlight_color,
+ "Whether to use the system default (on OS X only) for the
highlight color. Nil means to use standard emacs (prior to version 21)
'grey'.");
+
+ staticpro (&ns_display_name_list);
+ ns_display_name_list = Qnil;
+
+ staticpro (&last_mouse_motion_frame);
+ last_mouse_motion_frame = Qnil;
+
+/*23: now apparently we need to tell emacs what modifiers there are.. */
+ Qmodifier_value = intern ("modifier-value");
+ Qalt = intern ("alt");
+ Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
+ Qhyper = intern ("hyper");
+ Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
+ Qmeta = intern ("meta");
+ Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
+ Qsuper = intern ("super");
+ Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
+ Qcontrol = intern ("control");
+ Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
+
+ /*PENDING: move to common code */
+ DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
+ doc: /* If not nil, Emacs uses toolkit scroll bars. */);
+#ifdef USE_TOOLKIT_SCROLL_BARS
+ Vx_toolkit_scroll_bars = Qt;
+#else
+ Vx_toolkit_scroll_bars = Qnil;
+#endif
+
+ /* these are unsupported but we need the declarations to avoid whining
+ messages from cus-start.el */
+ DEFVAR_BOOL ("x-use-underline-position-properties",
+ &x_use_underline_position_properties,
+ doc: /* NOT SUPPORTED UNDER NS.
+*Non-nil means make use of UNDERLINE_POSITION font properties.
+A value of nil means ignore them. If you encounter fonts with bogus
+UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
+to 4.1, set this to nil.
+
+NOTE: Not supported on Mac yet. */);
+ x_use_underline_position_properties = 0;
+
+ DEFVAR_BOOL ("x-underline-at-descent-line",
+ &x_underline_at_descent_line,
+ doc: /* NOT SUPPORTED UNDER NS.
+*Non-nil means to draw the underline at the same place as the descent line.
+A value of nil means to draw the underline according to the value of the
+variable `x-use-underline-position-properties', which is usually at the
+baseline level. The default value is nil. */);
+ x_underline_at_descent_line = 0;
+
+ /* Tell emacs about this window system. */
+ Fprovide (intern ("ns-windowing"), Qnil);
+ /* PENDING: try to move this back into lisp (ns-win.el loaded too late
+ right now */
+ {
+ Lisp_Object args[3] = { intern ("ns-version-string"), build_string ("9.0"),
+ build_string ("NS Window system port version number.") };
+ Fdefconst (Flist (3, args));
+ }
+}
+
+
+
+/* ==========================================================================
+
+ EmacsApp implementation
+
+ ==========================================================================
*/
+
+
address@hidden EmacsApp
+
+- (void)logNotification: (NSNotification *)notification
+{
+ const char *name = [[notification name] UTF8String];
+ if (!strstr (name, "Update") && !strstr (name, "NSMenu")
+ && !strstr (name, "WindowNumber"))
+ NSLog (@"notification: '%@'", [notification name]);
+}
+
+
+- (void)sendEvent: (NSEvent *)theEvent
+/* --------------------------------------------------------------------------
+ Events posted by ns_send_appdefined interrupt the run loop here
+ --------------------------------------------------------------------------
*/
+{
+ int type = [theEvent type];
+ NSWindow *window = [theEvent window];
+/* NSTRACE (sendEvent); */
+/*fprintf (stderr, "received event of type %d\n", [theEvent type]); */
+
+ if (type == NSCursorUpdate && window == nil)
+ {
+ fprintf (stderr, "Dropping external cursor update event.\n");
+ return;
+ }
+
+#ifdef NS_IMPL_COCOA
+ /* pass mouse down in resize handle and subsequent drags directly to
+ EmacsWindow so we can generate continuous redisplays */
+ if (ns_in_resize)
+ {
+ if (type == NSLeftMouseDragged)
+ {
+ [window mouseDragged: theEvent];
+ return;
+ }
+ else if (type == NSLeftMouseUp)
+ {
+ [window mouseUp: theEvent];
+ return;
+ }
+ }
+ else if (type == NSLeftMouseDown)
+ {
+ NSRect r = ns_resize_handle_rect (window);
+ if (NSPointInRect ([theEvent locationInWindow], r))
+ {
+ ns_in_resize = YES;
+ [window mouseDown: theEvent];
+ return;
+ }
+ }
+#endif
+
+ if (type == NSApplicationDefined)
+ {
+ last_appdefined_event = theEvent;
+ [self stop: self];
+ }
+
+ [super sendEvent: theEvent];
+}
+
+
+- (void)showPreferencesWindow: (id)sender
+{
+ if (prefsController == nil)
+ prefsController = [[EmacsPrefsController alloc] init];
+ [prefsController showForFrame: SELECTED_FRAME ()];
+}
+
+
+/* **************************************************************************
+
+ EmacsApp delegate implementation
+
+ **************************************************************************
*/
+
+- (void)applicationDidFinishLaunching: (NSNotification *)notification
+/* --------------------------------------------------------------------------
+ When application is loaded, terminate event loop in ns_term_init
+ --------------------------------------------------------------------------
*/
+{
+ NSTRACE (applicationDidFinishLaunching);
+ [NSApp setServicesProvider: NSApp];
+ ns_send_appdefined (-2);
+}
+
+
+- (void) terminate: (id)sender
+{
+ BLOCK_INPUT;
+ if (ns_shutdown_properly)
+ [super terminate: sender];
+ else
+ {
+/* Fkill_emacs (Qnil); */
+ ns_shutdown_properly = YES;
+ Feval (Fcons (intern ("save-buffers-kill-emacs"), Qnil));
+ }
+ UNBLOCK_INPUT;
+}
+
+
+- (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
+{
+ if (ns_shutdown_properly)
+ return NSTerminateNow;
+
+ Lisp_Object contents = list3 (build_string ("Exit requested. Would you like
to Save Buffers and Exit, or Cancel the request?"),
+ Fcons (build_string ("Cancel"), Qnil),
+ Fcons (build_string ("Save and Exit"), Qt));
+ Lisp_Object res = ns_popup_dialog (Qt, contents, Qnil);
+fprintf (stderr, "res = %d\n", res ==Qt);
+ if (res == Qt)
+ {
+ Feval (Fcons (intern ("save-buffers-kill-emacs"), Qnil));
+ return NSTerminateNow;
+ }
+ return NSTerminateCancel;
+}
+
+
+/* Open a file (used by below, after going into queue read by ns_read_socket)
*/
+-(BOOL) openFile: (NSString *)fileName
+{
+ struct frame *emacsframe = SELECTED_FRAME ();
+ NSEvent *theEvent = [NSApp currentEvent];
+
+ if (!emacs_event)
+ return NO;
+
+ emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
+ emacs_event->code = KEY_NS_OPEN_FILE_LINE;
+ ns_input_file = append2 (ns_input_file, build_string ([fileName
UTF8String]));
+ ns_input_line = Qnil; /* can be start or cons start,end */
+ emacs_event->modifiers =0;
+ EV_TRAILER (theEvent);
+
+ return YES;
+}
+
+
+/* Notification from the Workspace to open a file */
+- (BOOL)application: sender openFile: (NSString *)file
+{
+ [ns_pending_files addObject: file];
+ return YES;
+}
+
+
+/* Open a file as a temporary file */
+- (BOOL)application: sender openTempFile: (NSString *)file
+{
+ [ns_pending_files addObject: file];
+ return YES;
+}
+
+
+/* Notification from the Workspace to open a file noninteractively (?) */
+- (BOOL)application: sender openFileWithoutUI: (NSString *)file
+{
+ [ns_pending_files addObject: file];
+ return YES;
+}
+
+
+/* Notification from the Workspace to open multiple files */
+- (void)application: sender openFiles: (NSArray *)fileList
+{
+ NSEnumerator *files = [fileList objectEnumerator];
+ NSString *file;
+ while ((file = [files nextObject]) != nil)
+ [ns_pending_files addObject: file];
+ return YES;
+}
+
+/*PENDING: these may help w/IO switching btwn terminal and NSApp */
+- (void)applicationDidBecomeActive: (NSNotification *)notification
+{
+}
+- (void)applicationDidResignActive: (NSNotification *)notification
+{
+ ns_send_appdefined (-1);
+}
+
+
+
+/* ==========================================================================
+
+ EmacsApp aux handlers for managing event loop
+
+ ==========================================================================
*/
+
+
+- (void)timeout_handler: (NSTimer *)timedEntry
+/* --------------------------------------------------------------------------
+ The timeout specified to ns_select has passed.
+ --------------------------------------------------------------------------
*/
+{
+ /*NSTRACE (timeout_handler); */
+ ns_send_appdefined (-2);
+}
+
+extern void update_window_cursor (struct window *w, int on);
+
+- (void)cursor_blink_handler: (NSTimer *)cursorEntry
+/* --------------------------------------------------------------------------
+ Flash the cursor
+ --------------------------------------------------------------------------
*/
+{
+ struct ns_display_info *dpyinfo = ns_display_list; /*HACK, but OK for now */
+ struct frame *f = dpyinfo->ns_highlight_frame;
+ NSTRACE (cursor_blink_handler);
+
+ if (!f)
+ return;
+ if (f->output_data.ns->current_cursor == no_highlight)
+ {
+ Lisp_Object tem = get_frame_param (f, Qcursor_type);
+ f->output_data.ns->desired_cursor = ns_lisp_to_cursor_type (tem);
+ }
+ else
+ {
+ f->output_data.ns->desired_cursor = no_highlight;
+ }
+ update_window_cursor (XWINDOW (FRAME_SELECTED_WINDOW (f)), 1);
+ /*x_update_cursor (f, 1); */
+}
+
+
+- (void)fd_handler: (NSTimer *) fdEntry
+/* --------------------------------------------------------------------------
+ Check data waiting on file descriptors and terminate if so
+ --------------------------------------------------------------------------
*/
+{
+ int result;
+ /* NSTRACE (fd_handler); */
+
+ if (select_nfds == 0)
+ return;
+
+ memcpy (&t_readfds, &select_readfds, sizeof (fd_set));
+
+ select_timeout.tv_sec = select_timeout.tv_usec = 0;
+ result = select (select_nfds, &t_readfds, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
+ &select_timeout);
+ if (result)
+ {
+ memcpy (&select_readfds, &t_readfds, sizeof (fd_set));
+ ns_send_appdefined (result);
+ }
+}
+
+
+
+/* ==========================================================================
+
+ Service provision
+
+ ==========================================================================
*/
+
+/* called from system: queue for next pass through event loop */
+- (void)requestService: (NSPasteboard *)pboard
+ userData: (NSString *)userData
+ error: (NSString **)error
+{
+ [ns_pending_service_names addObject: userData];
+ [ns_pending_service_args addObject: [NSString stringWithUTF8String:
+ SDATA (ns_string_from_pasteboard (pboard))]];
+}
+
+
+/* called from ns_read_socket to clear queue */
+- (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
+{
+ struct frame *emacsframe = SELECTED_FRAME ();
+ NSEvent *theEvent = [NSApp currentEvent];
+
+ if (!emacs_event)
+ return NO;
+
+ emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
+ emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
+ ns_input_spi_name = build_string ([name UTF8String]);
+ ns_input_spi_arg = build_string ([arg UTF8String]);
+ emacs_event->modifiers = EV_MODIFIERS (theEvent);
+ EV_TRAILER (theEvent);
+
+ return YES;
+}
+
+
address@hidden /* EmacsApp */
+
+
+
+/* ==========================================================================
+
+ EmacsView implementation
+
+ ==========================================================================
*/
+
+
address@hidden EmacsView
+
+/* needed to inform when window closed from LISP */
+- (void) setWindowClosing: (BOOL)closing
+{
+ windowClosing = closing;
+}
+
+
+- (void)dealloc
+{
+ NSTRACE (EmacsView_dealloc);
+ [toolbar release];
+ [super dealloc];
+}
+
+
+/* called on font panel selection */
+- (void)changeFont: (id)sender
+{
+ NSEvent *e =[[self window] currentEvent];
+ struct face *face =FRAME_DEFAULT_FACE (emacsframe);
+ id newFont;
+ float size;
+
+ NSTRACE (changeFont);
+ if (!emacs_event)
+ return;
+
+ if (newFont = [sender convertFont:
+ ((struct nsfont_info *)face->font)->nsfont])
+ {
+ emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
+ emacs_event->modifiers = 0;
+ emacs_event->code = KEY_NS_CHANGE_FONT;
+
+ size = [newFont pointSize];
+ /* PENDING: stick w/integer sizes for now. */
+/* if (size == lrint (size)) */
+ ns_input_fontsize = make_number (lrint (size));
+/* else
+ ns_input_fontsize = make_float (size); */
+ ns_input_font = build_string ([[newFont familyName] UTF8String]);
+ EV_TRAILER (e);
+ }
+}
+
+
+- (BOOL)acceptsFirstResponder
+{
+ NSTRACE (acceptsFirstResponder);
+ return YES;
+}
+
+
+- (void)resetCursorRects
+{
+ NSRect visible = [self visibleRect];
+ NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
+ NSTRACE (resetCursorRects);
+
+ if (currentCursor == nil)
+ currentCursor = [NSCursor arrowCursor];
+
+ if (!NSIsEmptyRect (visible))
+ [self addCursorRect: visible cursor: currentCursor];
+ [currentCursor setOnMouseEntered: YES];
+}
+
+
+/*****************************************************************************/
+/* Keyboard handling. */
+#define NS_KEYLOG 0
+
+- (void)keyDown: (NSEvent *)theEvent
+{
+ struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
+ int code;
+ unsigned fnKeysym = 0;
+ int flags;
+ static NSMutableArray *nsEvArray;
+ static BOOL firstTime = YES;
+
+ NSTRACE (keyDown);
+
+ /* Rhapsody and OS X give up and down events for the arrow keys */
+ if ([theEvent type] != NSKeyDown)
+ return;
+
+ if (!emacs_event)
+ return;
+
+/*#if defined (COCOA_EXPERIMENTAL_CTRL_G) */
+ if (![[self window] isKeyWindow])
+ {
+ /* PENDING: Using NO_SOCK_SIGIO like Carbon causes a condition in which,
+ when Emacs display updates a different frame from the current one,
+ and temporarily selects it, then processes some interrupt-driven
+ input (dispnew.c:3878), OS will send the event to the correct NSWindow,
+ but for some reason that window has its first responder set to the
+ NSView most recently updated (I guess), which is not the correct one.
+ UPDATE: After multi-TTY merge this happens even w/o NO_SOCK_SIGIO */
+ if ([[theEvent window] isKindOfClass: [EmacsWindow class]])
+ [[(EmacsView *)[theEvent window] delegate] keyDown: theEvent];
+ return;
+ }
+/*#endif */
+
+ if (nsEvArray == nil)
+ nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
+
+ [NSCursor setHiddenUntilMouseMoves: YES];
+
+ if (dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
+ {
+ clear_mouse_face (dpyinfo);
+ dpyinfo->mouse_face_hidden = 1;
+ }
+
+ if (!processingCompose)
+ {
+ code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
+ 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
+ /* (Carbon way: [theEvent keyCode]) */
+
+ /* is it a "function key"? */
+ fnKeysym = ns_convert_key (code);
+ if (fnKeysym)
+ {
+ /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
+ because Emacs treats Delete and KP-Delete same (in simple.el). */
+ if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
+ code = 0xFF08; /* backspace */
+ else
+ code = fnKeysym;
+ }
+
+ /* are there modifiers? */
+ emacs_event->modifiers = 0;
+ flags = [theEvent modifierFlags];
+
+ if (flags & NSHelpKeyMask)
+ emacs_event->modifiers |= hyper_modifier;
+
+ if (flags & NSShiftKeyMask)
+ emacs_event->modifiers |= shift_modifier;
+
+ if (flags & NSCommandKeyMask)
+ {
+ emacs_event->modifiers |= lisp_to_mod (ns_command_modifier);
+ /* if super (default), take input manager's word so things like
+ dvorak / qwerty layout work */
+ if (EQ (ns_command_modifier, Qsuper)
+ && !fnKeysym
+ && [[theEvent characters] length] != 0)
+ {
+ /* PENDING: the code we get will be unshifted, so if we have
+ a shift modifier, must convert ourselves */
+ if (!(flags & NSShiftKeyMask))
+ code = [[theEvent characters] characterAtIndex: 0];
+#if 0
+ /* this is ugly and also requires linking w/Carbon framework
+ (for LMGetKbdType) so for now leave this rare (?) case
+ undealt with.. in future look into CGEvent methods */
+ else
+ {
+ long smv = GetScriptManagerVariable (smKeyScript);
+ Handle uchrHandle = GetResource
+ ('uchr', GetScriptVariable (smv, smScriptKeys));
+ UInt32 dummy = 0;
+ UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
+ [[theEvent characters] characterAtIndex: 0],
+ kUCKeyActionDisplay,
+ (flags & ~NSCommandKeyMask) >> 8,
+ LMGetKbdType (),
kUCKeyTranslateNoDeadKeysMask,
+ &dummy, 1, &dummy, &code);
+ code &= 0xFF;
+ }
+#endif
+ }
+ }
+
+ if (flags & NSControlKeyMask)
+ emacs_event->modifiers |= lisp_to_mod (ns_control_modifier);
+
+ if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
+ emacs_event->modifiers |= lisp_to_mod (ns_function_modifier);
+
+ if (flags & NSAlternateKeyMask) /* default = meta */
+ {
+ if (EQ (ns_alternate_modifier, Qnone) && !fnKeysym)
+ { /* accept pre-interp alt comb */
+ if ([[theEvent characters] length] > 0)
+ code = [[theEvent characters] characterAtIndex: 0];
+ /*HACK: clear lone shift modifier to stop next if from firing */
+ if (emacs_event->modifiers == shift_modifier)
+ emacs_event->modifiers = 0;
+ }
+ else
+ emacs_event->modifiers |= lisp_to_mod (ns_alternate_modifier);
+ }
+
+/*fprintf (stderr,"code =%x\tfnKey =%x\tflags = %x\tmods =
%x\n",code,fnKeysym,flags,emacs_event->modifiers); */
+
+ /* if it was a function key or had modifiers, pass it directly to emacs
*/
+ if (fnKeysym || (emacs_event->modifiers
+ && [[theEvent charactersIgnoringModifiers] length] > 0))
+/*[[theEvent characters] length] */
+ {
+ emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
+ if (code < 0x20)
+ code |= (1<<28)|(3<<16);
+ else if (code == 0x7f)
+ code |= (1<<28)|(3<<16);
+ else if (!fnKeysym)
+ emacs_event->kind = code > 0xFF
+ ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
+
+ emacs_event->code = code;
+ EV_TRAILER (theEvent);
+ return;
+ }
+ }
+
+ /* if we get here we should send the key for input manager processing */
+ if (firstTime && [[NSInputManager currentInputManager]
+ wantsToDelayTextChangeNotifications] == NO)
+ fprintf (stderr,
+ "Emacs: WARNING: TextInput mgr wants marked text to be
permanent!\n");
+ firstTime = NO;
+
+ if (NS_KEYLOG && !processingCompose)
+ fprintf (stderr, "Begin compose sequence.\n");
+
+ processingCompose = YES;
+ [nsEvArray addObject: theEvent];
+ [self interpretKeyEvents: nsEvArray];
+ [nsEvArray removeObject: theEvent];
+}
+
+
+/* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
+
+
+/* <NSTextInput>: called through when done composing */
+- (void)insertText: (id)aString
+{
+ int code;
+ int len = [(NSString *)aString length];
+ int i;
+
+if (NS_KEYLOG) NSLog (@"insertText '%@'\tlen = %d", aString, len);
+ processingCompose = NO;
+
+ if (!emacs_event)
+ return;
+
+ /* first, clear any working text */
+ if (workingText != nil)
+ [self deleteWorkingText];
+
+ /* now insert the string as keystrokes */
+ for (i =0; i<len; i++)
+ {
+ code = [aString characterAtIndex: i];
+ /* PENDING: still need this? */
+ if (code == 0x2DC)
+ code = '~'; /* 0x7E */
+ emacs_event->modifiers = 0;
+ emacs_event->kind =
+ code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
+ emacs_event->code = code;
+ EV_TRAILER ((id)nil);
+ }
+}
+
+
+/* <NSTextInput>: inserts display of composing characters */
+- (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
+{
+ NSString *str = [aString respondsToSelector: @selector (string)] ?
+ [aString string] : aString;
+ if (NS_KEYLOG)
+ NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
+ selRange.length, selRange.location);
+
+ if (workingText != nil)
+ [self deleteWorkingText];
+ if ([str length] == 0)
+ return;
+
+ if (!emacs_event)
+ return;
+
+ processingCompose = YES;
+ workingText = [str copy];
+ ns_working_text = build_string ([workingText UTF8String]);
+
+ /* if in "echo area", not true minibuffer, can't show chars in interactive
+ mode, so call using eval; otherwise we send a key event, which was the
+ original way this was done */
+ if (!EQ (Feval (Fcons (intern ("ns-in-echo-area"), Qnil)), Qnil))
+ {
+ Feval (Fcons (intern ("ns-echo-working-text"), Qnil));
+ ns_send_appdefined (-1);
+ }
+ else
+ {
+ emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
+ emacs_event->code = KEY_NS_INSERT_WORKING_TEXT;
+ EV_TRAILER ((id)nil);
+ }
+}
+
+
+/* delete display of composing characters [not in <NSTextInput>] */
+- (void)deleteWorkingText
+{
+ if (workingText == nil)
+ return;
+ if (NS_KEYLOG)
+ fprintf (stderr, "deleteWorkingText len =%d\n", [workingText length]);
+ [workingText release];
+ workingText = nil;
+ processingCompose = NO;
+
+ if (!emacs_event)
+ return;
+
+ if (!EQ (Feval (Fcons (intern ("ns-in-echo-area"), Qnil)), Qnil))
+ {
+ Feval (Fcons (intern ("ns-unecho-working-text"), Qnil));
+ ns_send_appdefined (-1);
+ }
+ else
+ {
+ emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
+ emacs_event->code = KEY_NS_DELETE_WORKING_TEXT;
+ EV_TRAILER ((id)nil);
+ }
+ }
+
+
+- (BOOL)hasMarkedText
+{
+ return workingText != nil;
+}
+
+- (NSRange)markedRange
+{
+ NSRange rng = workingText != nil
+ ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
+if (NS_KEYLOG) NSLog (@"markedRange request");
+ return rng;
+}
+
+- (void)unmarkText
+{
+if (NS_KEYLOG) NSLog (@"unmark (accept) text");
+ [self deleteWorkingText];
+ processingCompose = NO;
+}
+
+/* used to position char selection windows, etc. */
+- (NSRect)firstRectForCharacterRange: (NSRange)theRange
+{
+ NSRect rect;
+ NSPoint pt;
+ struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
+if (NS_KEYLOG) NSLog (@"firstRectForCharRange request");
+
+ rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
+ rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
+ pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
+ pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
+ +FRAME_LINE_HEIGHT (emacsframe));
+
+ pt = [self convertPoint: pt toView: nil];
+ pt = [[self window] convertBaseToScreen: pt];
+ rect.origin = pt;
+ return rect;
+}
+
+- (long)conversationIdentifier
+{
+ return (long)self;
+}
+
+/*PENDING: below here not yet implemented correctly, but may not be needed */
+
+- (void)doCommandBySelector: (SEL)aSelector
+{
+ if (NS_KEYLOG) NSLog (@"Do command by selector: %@",
+ NSStringFromSelector (aSelector));
+
+ if (aSelector == @selector (deleteBackward:))
+ {
+ /* happens when user backspaces over an ongoing composition:
+ throw a 'delete' into the event queue */
+ if (!emacs_event)
+ return;
+ emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
+ emacs_event->code = 0xFF08;
+ EV_TRAILER ((id)nil);
+ }
+}
+
+- (NSArray *)validAttributesForMarkedText
+{
+ static NSArray *arr = nil;
+ if (arr == nil) arr = [NSArray new];
+ /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
+ return arr;
+}
+
+- (NSRange)selectedRange
+{
+if (NS_KEYLOG) NSLog (@"selectedRange request");
+ return NSMakeRange (NSNotFound, 0);
+}
+
+- (unsigned int)characterIndexForPoint: (NSPoint)thePoint
+{
+if (NS_KEYLOG) NSLog (@"characterIndexForPoint request");
+ return 0;
+}
+
+- (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
+{
+ static NSAttributedString *str = nil;
+ if (str == nil) str = [NSAttributedString new];
+if (NS_KEYLOG) NSLog (@"attributedSubstringFromRange request");
+ return str;
+}
+
+/* End <NSTextInput> impl. */
+/*****************************************************************************/
+
+
+/* This is what happens when the user presses a mouse button. */
+- (void)mouseDown: (NSEvent *)theEvent
+{
+ NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
+ Lisp_Object window;
+
+ NSTRACE (mouseDown);
+
+ [self deleteWorkingText];
+
+ if (!emacs_event)
+ return;
+
+ last_mouse_frame = emacsframe;
+ /* appears to be needed to prevent spurious movement events generated on
+ button clicks */
+ last_mouse_frame->mouse_moved = 0;
+
+ if ([theEvent type] == NSScrollWheel)
+ {
+ float delta = [theEvent deltaY];
+ /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
+ if (delta == 0)
+ return;
+ emacs_event->kind = WHEEL_EVENT;
+ emacs_event->code = 0;
+ emacs_event->modifiers = EV_MODIFIERS (theEvent) |
+ ((delta > 0) ? up_modifier : down_modifier);
+ }
+ else
+ {
+ emacs_event->kind = MOUSE_CLICK_EVENT;
+ emacs_event->code = EV_BUTTON (theEvent);
+ emacs_event->modifiers = EV_MODIFIERS (theEvent)
+ | EV_UDMODIFIERS (theEvent);
+ }
+ XSETINT (emacs_event->x, lrint (p.x));
+ XSETINT (emacs_event->y, lrint (p.y));
+ EV_TRAILER (theEvent);
+}
+
+
+- (void)mouseUp: (NSEvent *)theEvent
+{
+ NSTRACE (mouseUp);
+ [self mouseDown: theEvent];
+}
+
+
+- (void)rightMouseDown: (NSEvent *)theEvent
+{
+ NSTRACE (rightMouseDown);
+ [self mouseDown: theEvent];
+}
+
+
+- (void)rightMouseUp: (NSEvent *)theEvent
+{
+ NSTRACE (rightMouseUp);
+ [self mouseDown: theEvent];
+}
+
+
+- (void) scrollWheel: (NSEvent *)theEvent
+{
+ NSTRACE (scrollWheel);
+ [self mouseDown: theEvent];
+}
+
+
+/* Tell emacs the mouse has moved. */
+- (void)mouseMoved: (NSEvent *)e
+{
+ struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
+ Lisp_Object frame;
+
+ NSTRACE (mouseMoved);
+
+ last_mouse_movement_time = EV_TIMESTAMP (e);
+ last_mouse_motion_position =
+ [self convertPoint: [e locationInWindow] fromView: nil];
+
+ /* update any mouse face */
+ if (dpyinfo->mouse_face_hidden)
+ {
+ dpyinfo->mouse_face_hidden = 0;
+ clear_mouse_face (dpyinfo);
+ }
+
+ /* tooltip handling */
+ previous_help_echo_string = help_echo_string;
+ help_echo_string = Qnil;
+
+ if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
+ last_mouse_motion_position.y))
+ help_echo_string = previous_help_echo_string;
+
+ XSETFRAME (frame, emacsframe);
+ if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
+ {
+ /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
+ (note_mouse_highlight), which is called through the
+ note_mouse_movement () call above */
+ gen_help_event (help_echo_string, frame, help_echo_window,
+ help_echo_object, help_echo_pos);
+ }
+ else
+ {
+ help_echo_string = Qnil;
+ gen_help_event (Qnil, frame, Qnil, Qnil, 0);
+ }
+
+ if (emacsframe->mouse_moved && send_appdefined)
+ ns_send_appdefined (-1);
+}
+
+
+- (void)mouseDragged: (NSEvent *)e
+{
+ NSTRACE (mouseDragged);
+ [self mouseMoved: e];
+}
+
+
+- (void)rightMouseDragged: (NSEvent *)e
+{
+ NSTRACE (rightMouseDragged);
+ [self mouseMoved: e];
+}
+
+
+- (BOOL)windowShouldClose: (id)sender
+{
+ NSEvent *e =[[self window] currentEvent];
+
+ NSTRACE (windowShouldClose);
+ windowClosing = YES;
+ if (ns_window_num <= 1)
+ return NO;
+ if (!emacs_event)
+ return NO;
+ emacs_event->kind = DELETE_WINDOW_EVENT;
+ emacs_event->modifiers = 0;
+ emacs_event->code = 0;
+ EV_TRAILER (e);
+ /* Don't close this window, let this be done from lisp code. */
+ return NO;
+}
+
+
+- (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
+/* normalize frame to gridded text size */
+{
+ NSTRACE (windowWillResize);
+/*fprintf (stderr,"Window will resize: %.0f x
%.0f\n",frameSize.width,frameSize.height); */
+
+ cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
+#ifdef NS_IMPL_GNUSTEP
+ frameSize.width + 3);
+#else
+ frameSize.width);
+#endif
+ if (cols < MINWIDTH)
+ cols = MINWIDTH;
+ frameSize.width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (emacsframe, cols);
+
+ rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, frameSize.height
+#ifdef NS_IMPL_GNUSTEP
+ - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + 3
+ - FRAME_NS_TOOLBAR_HEIGHT (emacsframe));
+#else
+ - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
+ - FRAME_NS_TOOLBAR_HEIGHT (emacsframe));
+#endif
+ if (rows < MINHEIGHT)
+ rows = MINHEIGHT;
+ frameSize.height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows)
+ + FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
+ + FRAME_NS_TOOLBAR_HEIGHT (emacsframe);
+#ifdef NS_IMPL_COCOA
+ {
+ /* this sets window title to have size in it; the wm does this under GS */
+ NSRect r = [[self window] frame];
+ if (r.size.height == frameSize.height && r.size.width == frameSize.width)
+ {
+ if (old_title != 0)
+ {
+ xfree (old_title);
+ old_title = 0;
+ }
+ }
+ else
+ {
+ char *size_title;
+ NSWindow *window = [self window];
+ if (old_title == 0)
+ {
+ const char *t = [[[self window] title] UTF8String];
+ char *pos = strstr (t, " â ");
+ if (pos)
+ *pos = '\0';
+ old_title = (char *) xmalloc (strlen (t) + 1);
+ strcpy (old_title, t);
+ }
+ size_title = xmalloc (strlen (old_title) + 40);
+ sprintf (size_title, "%s â (%d x %d)", old_title, cols, rows);
+ [window setTitle: [NSString stringWithUTF8String: size_title]];
+ [window display];
+ xfree (size_title);
+ }
+ }
+#endif /* NS_IMPL_COCOA */
+/*fprintf (stderr," ...size became %.0f x %.0f (%d x
%d)\n",frameSize.width,frameSize.height,cols,rows); */
+
+ return frameSize;
+}
+
+
+- (void)windowDidResize: (NSNotification *)notification
+{
+ NSWindow *theWindow = [notification object];
+
+#ifdef NS_IMPL_GNUSTEP
+ /* in GNUstep, at least currently, it's possible to get a didResize
+ without getting a willResize.. therefore we need to act as if we got
+ the willResize now */
+ NSSize sz = [theWindow frame].size;
+ sz = [self windowWillResize: theWindow toSize: sz];
+#endif /* NS_IMPL_GNUSTEP */
+
+ NSTRACE (windowDidResize);
+/*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
+
+#ifdef NS_IMPL_COCOA
+ if (old_title != 0)
+ {
+ xfree (old_title);
+ old_title = 0;
+ }
+#endif /* NS_IMPL_COCOA */
+
+ if (cols > 0 && rows > 0)
+ x_set_window_size (emacsframe, 0, cols, rows);
+
+ ns_send_appdefined (-1);
+ [NSApp stopModal];
+}
+
+
+- (void)windowDidBecomeKey: (NSNotification *)notification
+{
+ int val = ns_lisp_to_cursor_type (get_frame_param (emacsframe,
Qcursor_type));
+ struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
+ struct frame *old_focus = dpyinfo->ns_focus_frame;
+
+ NSTRACE (windowDidBecomeKey);
+
+ if (emacsframe != old_focus)
+ dpyinfo->ns_focus_frame = emacsframe;
+ /*/last_mouse_frame = emacsframe;? */
+
+ if (val >= 0)
+ {
+ FRAME_NEW_CURSOR (emacsframe) = val;
+/* x_update_cursor (emacsframe, 1); // will happen in ns_frame_rehighlight
*/
+ }
+
+ ns_frame_rehighlight (emacsframe);
+
+ if (emacs_event)
+ {
+ emacs_event->kind = FOCUS_IN_EVENT;
+ EV_TRAILER ((id)nil);
+ }
+}
+
+
+- (void)windowDidResignKey: (NSNotification *)notification
+{
+ struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
+ NSTRACE (windowDidResignKey);
+
+ if (!windowClosing && [[self window] isVisible] == YES)
+ {
+ FRAME_NEW_CURSOR (emacsframe) = hollow_box;
+ x_update_cursor (emacsframe, 1);
+ FRAME_LAST_INACTIVE (emacsframe) = YES;
+ }
+
+ if (dpyinfo->ns_highlight_frame == emacsframe)
+ dpyinfo->ns_highlight_frame = 0;
+ if (dpyinfo->ns_focus_frame == emacsframe)
+ dpyinfo->ns_focus_frame = 0;
+
+ if (dpyinfo->mouse_face_mouse_frame == emacsframe)
+ {
+ clear_mouse_face (dpyinfo);
+ dpyinfo->mouse_face_mouse_frame = 0;
+ }
+
+ if (emacs_event)
+ {
+ [self deleteWorkingText];
+ emacs_event->kind = FOCUS_IN_EVENT;
+ EV_TRAILER ((id)nil);
+ }
+}
+
+
+- (void)windowWillMiniaturize: sender
+{
+ NSTRACE (windowWillMiniaturize);
+}
+
+
+- (BOOL)isFlipped
+{
+ return YES;
+}
+
+
+- (BOOL)isOpaque
+{
+ return NO;
+}
+
+
+- initFrameFromEmacs: (struct frame *)f
+{
+ NSRect r, wr;
+ Lisp_Object tem;
+ NSWindow *win;
+ NSButton *toggleButton;
+ int vbextra = NS_SCROLL_BAR_WIDTH (f);
+ NSSize sz;
+ NSColor *col;
+ NSString *name;
+
+ NSTRACE (initFrameFromEmacs);
+
+ windowClosing = NO;
+ processingCompose = NO;
+ scrollbarsNeedingUpdate = 0;
+
+/*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
+
+ r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
+ FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
+ [self initWithFrame: r];
+
+ FRAME_NS_VIEW (f) = self;
+ emacsframe = f;
+ old_title = 0;
+
+ win = [[EmacsWindow alloc]
+ initWithContentRect: r
+ styleMask: (NSResizableWindowMask |
+ NSMiniaturizableWindowMask |
+ NSClosableWindowMask)
+ backing: NSBackingStoreBuffered
+ defer: YES];
+
+ wr = [win frame];
+ f->border_width = wr.size.width - r.size.width;
+ FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
+
+ [win setAcceptsMouseMovedEvents: YES];
+ [win setDelegate: self];
+ [win useOptimizedDrawing: YES];
+
+ sz.width = FRAME_COLUMN_WIDTH (f);
+ sz.height = FRAME_LINE_HEIGHT (f);
+ [win setResizeIncrements: sz];
+
+ [[win contentView] addSubview: self];
+
+ if (ns_drag_types)
+ [self registerForDraggedTypes: ns_drag_types];
+
+ tem = f->name;
+ name = [NSString stringWithUTF8String:
+ NILP (tem) ? (unsigned char *)"Emacs" : XSTRING
(tem)->data];
+ [win setTitle: name];
+
+ /* toolbar support */
+ toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
+ [NSString stringWithFormat: @"Emacs Frame %d",
+ ns_window_num]];
+ [win setToolbar: toolbar];
+ [toolbar setVisible: NO];
+#ifdef NS_IMPL_COCOA
+ toggleButton = [win standardWindowButton: NSWindowToolbarButton];
+ [toggleButton setTarget: self];
+ [toggleButton setAction: @selector (toggleToolbar: )];
+#endif
+ FRAME_NS_TOOLBAR_HEIGHT (f) = 0;
+
+ tem = f->icon_name;
+ if (!NILP (tem))
+ [win setMiniwindowTitle:
+ [NSString stringWithUTF8String: XSTRING (tem)->data]];
+
+ {
+ NSScreen *screen = [win screen];
+
+ if (screen != 0)
+ [win setFrameTopLeftPoint: NSMakePoint
+ (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
+ IN_BOUND (-SCREENMAX,
+ [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
+ }
+
+ [win makeFirstResponder: self];
+
+ col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
+ (FRAME_DEFAULT_FACE (emacsframe)),
emacsframe);
+ [win setBackgroundColor: col];
+ if ([col alphaComponent] != 1.0)
+ [win setOpaque: NO];
+
+ [self allocateGState];
+
+ ns_window_num++;
+ return self;
+}
+
+
+- (void)windowDidMove: sender
+{
+ NSWindow *win = [self window];
+ NSRect r = [win frame];
+ NSScreen *screen = [win screen];
+ NSRect sr = [screen frame];
+
+ NSTRACE (windowDidMove);
+
+ if (!emacsframe->output_data.ns)
+ return;
+ if (screen != nil)
+ {
+ emacsframe->left_pos = r.origin.x; /* - sr.origin.x; */
+ emacsframe->top_pos = sr.size.height -
+ (r.origin.y + r.size.height); /* + sr.origin.y; */
+ }
+}
+
+#ifdef NS_IMPL_COCOA
+/* if we don't do this manually, the window will resize but not move */
+- (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
+{
+ [[self window] setFrame: newFrame display: NO];
+ return YES;
+}
+#endif
+
+/* Implement this to control size of frame on zoom.
+- (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
+ defaultFrame:(NSRect)defaultFrame; */
+
+
+- (void)windowDidDeminiaturize: sender
+{
+ NSTRACE (windowDidDeminiaturize);
+ if (!emacsframe->output_data.ns)
+ return;
+ emacsframe->async_visible = 1;
+ emacsframe->async_iconified = 0;
+ windows_or_buffers_changed++;
+
+ if (emacs_event)
+ {
+ emacs_event->kind = ICONIFY_EVENT;
+ EV_TRAILER ((id)nil);
+ }
+}
+
+
+- (void)windowDidExpose: sender
+{
+ NSTRACE (windowDidExpose);
+ if (!emacsframe->output_data.ns)
+ return;
+ emacsframe->async_visible = 1;
+ SET_FRAME_GARBAGED (emacsframe);
+
+ if (send_appdefined)
+ ns_send_appdefined (-1);
+}
+
+
+- (void)windowDidMiniaturize: sender
+{
+ NSTRACE (windowDidMiniaturize);
+ if (!emacsframe->output_data.ns)
+ return;
+
+ emacsframe->async_iconified = 1;
+
+ if (emacs_event)
+ {
+ emacs_event->kind = ICONIFY_EVENT;
+ EV_TRAILER ((id)nil);
+ }
+}
+
+
+- (void)mouseEntered: (NSEvent *)theEvent
+{
+ NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
+ struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
+ NSTRACE (mouseEntered);
+
+ last_mouse_movement_time = EV_TIMESTAMP (theEvent);
+}
+
+
+- (void)mouseExited: (NSEvent *)theEvent
+{
+ NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
+ NSRect r;
+ struct ns_display_info *dpyinfo =
+ emacsframe ? FRAME_NS_DISPLAY_INFO (emacsframe) : NULL;
+
+ NSTRACE (mouseExited);
+
+ if (dpyinfo || !emacsframe)
+ return;
+
+ last_mouse_movement_time = EV_TIMESTAMP (theEvent);
+
+ if (emacsframe == dpyinfo->mouse_face_mouse_frame)
+ {
+ clear_mouse_face (dpyinfo);
+ dpyinfo->mouse_face_mouse_frame = 0;
+ }
+}
+
+
+- menuDown: sender
+{
+ NSTRACE (menuDown);
+ if (context_menu_value == -1)
+ context_menu_value = [sender tag];
+ else
+ find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
+ emacsframe->menu_bar_vector, [sender tag]);
+ ns_send_appdefined (-1);
+ return self;
+}
+
+
+- (EmacsToolbar *)toolbar
+{
+ return toolbar;
+}
+
+
+/* this gets called on toolbar button click */
+- toolbarClicked: (id)item
+{
+ NSEvent *theEvent;
+ int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
+
+ NSTRACE (toolbarClicked);
+
+ if (!emacs_event)
+ return self;
+
+ /* send first event (for some reason two needed) */
+ theEvent =[[self window] currentEvent];
+ emacs_event->kind = TOOL_BAR_EVENT;
+ XSETFRAME (emacs_event->arg, emacsframe);
+ EV_TRAILER (theEvent);
+
+ emacs_event->kind = TOOL_BAR_EVENT;
+/* XSETINT (emacs_event->code, 0); */
+ emacs_event->arg = AREF (emacsframe->tool_bar_items,
+ idx + TOOL_BAR_ITEM_KEY);
+ emacs_event->modifiers = EV_MODIFIERS (theEvent);
+ EV_TRAILER (theEvent);
+ return self;
+}
+
+
+- toggleToolbar: (id)sender
+{
+ Lisp_Object lispFrame;
+ XSETFRAME (lispFrame, emacsframe);
+ Feval (Fcons (intern ("ns-toggle-toolbar"), Fcons (lispFrame, Qnil)));
+ SET_FRAME_GARBAGED (emacsframe);
+ ns_send_appdefined (-1);
+}
+
+
+- (void)drawRect: (NSRect)rect
+{
+ int x = NSMinX (rect), y = NSMinY (rect);
+ int width = NSWidth (rect), height = NSHeight (rect);
+
+ NSTRACE (drawRect);
+
+ if (!emacsframe || !emacsframe->output_data.ns)
+ return;
+
+ if (!ns_in_resize)
+ ns_clear_frame_area (emacsframe, x, y, width, height);
+ expose_frame (emacsframe, x, y, width, height);
+
+ emacsframe->async_visible = 1;
+ emacsframe->async_iconified = 0;
+
+/* SET_FRAME_GARBAGED (emacsframe);
+ ns_send_appdefined (-1); */
+}
+
+
+/* NSDraggingDestination protocol methods. Actually this is not really a
+ protocol, but a category of Object. O well... */
+
+-(unsigned int) draggingEntered: (id <NSDraggingInfo>) sender
+{
+ NSTRACE (draggingEntered);
+ return NSDragOperationGeneric;
+}
+
+
+-(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
+{
+ return YES;
+}
+
+
+-(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
+{
+ id pb;
+ int x, y;
+ NSString *type;
+ NSEvent *theEvent = [[self window] currentEvent];
+ NSPoint position;
+
+ NSTRACE (performDragOperation);
+
+ if (!emacs_event)
+ return;
+
+ position = [self convertPoint: [sender draggingLocation] fromView: nil];
+ x = lrint (position.x); y = lrint (position.y);
+
+ pb = [sender draggingPasteboard];
+ type = [pb availableTypeFromArray: ns_drag_types];
+ if (type == 0)
+ {
+ return NO;
+ }
+ else if ([type isEqualToString: NSFilenamesPboardType])
+ {
+ NSArray *files;
+ NSEnumerator *fenum;
+ NSString *file;
+
+ if (!(files = [pb propertyListForType: type]))
+ return NO;
+
+ fenum = [files objectEnumerator];
+ while ( (file = [fenum nextObject]) )
+ {
+ emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
+ emacs_event->code = KEY_NS_DRAG_FILE;
+ XSETINT (emacs_event->x, x);
+ XSETINT (emacs_event->y, y);
+ ns_input_file = append2 (ns_input_file,
+ build_string ([file UTF8String]));
+ emacs_event->modifiers = EV_MODIFIERS (theEvent);
+ EV_TRAILER (theEvent);
+ }
+ return YES;
+ }
+ else if ([type isEqualToString: NSURLPboardType])
+ {
+ NSString *file;
+ NSURL *fileURL;
+
+ if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
+ [fileURL isFileURL] == NO)
+ return NO;
+
+ file = [fileURL path];
+ emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
+ emacs_event->code = KEY_NS_DRAG_FILE;
+ XSETINT (emacs_event->x, x);
+ XSETINT (emacs_event->y, y);
+ ns_input_file = append2 (ns_input_file, build_string ([file
UTF8String]));
+ emacs_event->modifiers = EV_MODIFIERS (theEvent);
+ EV_TRAILER (theEvent);
+ return YES;
+ }
+ else if ([type isEqualToString: NSStringPboardType]
+ || [type isEqualToString: NSTabularTextPboardType])
+ {
+ NSString *data;
+
+ if (! (data = [pb stringForType: type]))
+ return NO;
+
+ emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
+ emacs_event->code = KEY_NS_DRAG_TEXT;
+ XSETINT (emacs_event->x, x);
+ XSETINT (emacs_event->y, y);
+ ns_input_text = build_string ([data UTF8String]);
+ emacs_event->modifiers = EV_MODIFIERS (theEvent);
+ EV_TRAILER (theEvent);
+ return YES;
+ }
+ else if ([type isEqualToString: NSColorPboardType])
+ {
+ NSColor *c = [NSColor colorFromPasteboard: pb];
+ emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
+ emacs_event->code = KEY_NS_DRAG_COLOR;
+ XSETINT (emacs_event->x, x);
+ XSETINT (emacs_event->y, y);
+ ns_input_color = ns_color_to_lisp (c);
+ emacs_event->modifiers = EV_MODIFIERS (theEvent);
+ EV_TRAILER (theEvent);
+ return YES;
+ }
+ else if ([type isEqualToString: NSFontPboardType])
+ {
+ /* impl based on GNUstep NSTextView.m */
+ NSData *data = [pb dataForType: NSFontPboardType];
+ NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
+ NSFont *font = [dict objectForKey: NSFontAttributeName];
+ char fontSize[10];
+
+ if (font == nil)
+ return NO;
+
+ emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
+ emacs_event->code = KEY_NS_CHANGE_FONT;
+ XSETINT (emacs_event->x, x);
+ XSETINT (emacs_event->y, y);
+ ns_input_font = build_string ([[font fontName] UTF8String]);
+ snprintf (fontSize, 10, "%f", [font pointSize]);
+ ns_input_fontsize = build_string (fontSize);
+ emacs_event->modifiers = EV_MODIFIERS (theEvent);
+ EV_TRAILER (theEvent);
+ return YES;
+ }
+ else
+ {
+ error ("Invalid data type in dragging pasteboard.");
+ return NO;
+ }
+}
+
+
+- validRequestorForSendType: (NSString *)typeSent
+ returnType: (NSString *)typeReturned
+{
+ NSTRACE (validRequestorForSendType);
+ if ([ns_send_types indexOfObjectIdenticalTo: typeSent] != NSNotFound &&
+ [ns_return_types indexOfObjectIdenticalTo: typeSent] != NSNotFound)
+ return self;
+
+ return [super validRequestorForSendType: typeSent
+ returnType: typeReturned];
+}
+
+
+/* setMini =YES means set from internal (gives a finder icon), NO means set nil
+ (gives a miniaturized version of the window); currently we use the latter
for
+ frames whose active buffer doesn't correspond to any file
+ (e.g., '*scratch*') */
+- setMiniwindowImage: (BOOL) setMini
+{
+ id image = [[self window] miniwindowImage];
+ NSTRACE (setMiniwindowImage);
+
+ /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
+ about "AppleDockIconEnabled" notwithstanding, however the set message
+ below has its effect nonetheless. */
+ if (image != emacsframe->output_data.ns->miniimage)
+ {
+ if (image && [image isKindOfClass: [EmacsImage class]])
+ [image release];
+ [[self window] setMiniwindowImage:
+ setMini ? emacsframe->output_data.ns->miniimage : nil];
+ }
+
+ return self;
+}
+
+
+- (void) setRows: (int) r andColumns: (int) c
+{
+ rows = r;
+ cols = c;
+}
+
address@hidden /* EmacsView */
+
+
+
+/* ==========================================================================
+
+ EmacsWindow implementation
+
+ ==========================================================================
*/
+
address@hidden EmacsWindow
+
+/* called only on resize clicks by special case in EmacsApp-sendEvent */
+- (void)mouseDown: (NSEvent *)theEvent
+{
+ if (ns_in_resize)
+ {
+ NSSize size = [[theEvent window] frame].size;
+ grabOffset = [theEvent locationInWindow];
+ grabOffset.x = size.width - grabOffset.x;
+ }
+ else
+ [super mouseDown: theEvent];
+}
+
+
+/* stop resizing */
+- (void)mouseUp: (NSEvent *)theEvent
+{
+ if (ns_in_resize)
+ {
+ struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
+ ns_in_resize = NO;
+ ns_set_name_as_filename (f);
+ [self display];
+ ns_send_appdefined (-1);
+ }
+ else
+ [super mouseUp: theEvent];
+}
+
+
+/* send resize events */
+- (void)mouseDragged: (NSEvent *)theEvent
+{
+ if (ns_in_resize)
+ {
+ NSPoint p = [theEvent locationInWindow];
+ NSSize size, vettedSize, origSize = [self frame].size;
+
+ size.width = p.x + grabOffset.x;
+ size.height = origSize.height - p.y + grabOffset.y;
+
+ if (size.width == origSize.width && size.height == origSize.height)
+ return;
+
+ vettedSize = [[self delegate] windowWillResize: self toSize: size];
+ if (vettedSize.width != size.width || vettedSize.height != size.height)
+ {
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName: NSWindowDidResizeNotification
+ object: self];
+ }
+ }
+ else
+ [super mouseDragged: theEvent];
+}
+
address@hidden /* EmacsWindow */
+
+
+/* ==========================================================================
+
+ EmacsScroller implementation
+
+ ==========================================================================
*/
+
+
address@hidden EmacsScroller
+
+/* for repeat button push */
+#define SCROLL_BAR_FIRST_DELAY 0.5
+#define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
+
++ (float) scrollerWidth
+{
+ /* PENDING: if we want to allow variable widths, this is the place to do it,
+ however neither GNUstep nor Cocoa support it very well */
+ return [NSScroller scrollerWidth];
+}
+
+
+- initFrame: (NSRect )r window: (Lisp_Object)nwin
+{
+ NSTRACE (EmacsScroller_initFrame);
+
+ r.size.width = [EmacsScroller scrollerWidth];
+ [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
+ [self setContinuous: YES];
+ [self setEnabled: YES];
+
+ /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
+ locked against the right, top and bottom edges. */
+ [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
+
+ win = nwin;
+ condemned = NO;
+ pixel_height = NSHeight (r);
+ min_portion = 20 / pixel_height;
+
+ frame = XFRAME (XWINDOW (win)->frame);
+ if (FRAME_LIVE_P (frame))
+ {
+ int i;
+ EmacsView *view = FRAME_NS_VIEW (frame);
+ NSView *sview = [[view window] contentView];
+ NSArray *subs = [sview subviews];
+
+ /* disable optimization stopping redraw of other scrollbars */
+ view->scrollbarsNeedingUpdate = 0;
+ for (i =[subs count]-1; i >= 0; i--)
+ if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
+ view->scrollbarsNeedingUpdate++;
+ [sview addSubview: self];
+ }
+
+/* [self setFrame: r]; */
+
+ return self;
+}
+
+
+- (void)setFrame: (NSRect)newRect
+{
+ NSTRACE (EmacsScroller_setFrame);
+/* BLOCK_INPUT; */
+ pixel_height = NSHeight (newRect);
+ min_portion = 20 / pixel_height;
+ [super setFrame: newRect];
+ [self display];
+/* UNBLOCK_INPUT; */
+}
+
+
+- (void)dealloc
+{
+ NSTRACE (EmacsScroller_dealloc);
+ if (!NILP (win))
+ XWINDOW (win)->vertical_scroll_bar = Qnil;
+ [super dealloc];
+}
+
+
+- condemn
+{
+ NSTRACE (condemn);
+ condemned =YES;
+ return self;
+}
+
+
+- reprieve
+{
+ NSTRACE (reprieve);
+ condemned =NO;
+ return self;
+}
+
+
+- judge
+{
+ NSTRACE (judge);
+ if (condemned)
+ {
+ BLOCK_INPUT;
+ /* ensure other scrollbar updates after deletion */
+ EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
+ if (view != nil)
+ view->scrollbarsNeedingUpdate++;
+ [self removeFromSuperview];
+ [self release];
+ UNBLOCK_INPUT;
+ }
+ return self;
+}
+
+
+- (void)resetCursorRects
+{
+ NSRect visible = [self visibleRect];
+ NSTRACE (resetCursorRects);
+
+ if (!NSIsEmptyRect (visible))
+ [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
+ [[NSCursor arrowCursor] setOnMouseEntered: YES];
+}
+
+
+- (int) checkSamePosition: (int) position portion: (int) portion
+ whole: (int) whole
+{
+ return em_position ==position && em_portion ==portion && em_whole ==whole
+ && portion != whole; /* needed for resize empty buf */
+}
+
+
+- setPosition: (int)position portion: (int)portion whole: (int)whole
+{
+ NSTRACE (setPosition);
+
+ em_position = position;
+ em_portion = portion;
+ em_whole = whole;
+
+ if (portion >= whole)
+ [self setFloatValue: 0.0 knobProportion: 1.0];
+ else
+ {
+ float pos, por;
+ portion = max ((float)whole*min_portion/pixel_height, portion);
+ pos = (float)position / (whole - portion);
+ por = (float)portion/whole;
+ [self setFloatValue: pos knobProportion: por];
+ }
+#ifdef NS_IMPL_GNUSTEP
+ [self display];
+#endif
+ return self;
+}
+
+/* PENDING: unused at moment (see ns_mouse_position) at the moment because
+ drag events will go directly to the EmacsScroller. Leaving in for now. */
+-(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
+ x: (Lisp_Object *)x y: ( Lisp_Object *)y
+{
+ *part = last_hit_part;
+ *window = win;
+ XSETINT (*y, pixel_height);
+ if ([self floatValue] > 0.999)
+ XSETINT (*x, pixel_height);
+ else
+ XSETINT (*x, pixel_height * [self floatValue]);
+}
+
+
+/* set up emacs_event */
+- (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
+{
+ if (!emacs_event)
+ return;
+
+ emacs_event->part = last_hit_part;
+ emacs_event->code = 0;
+ emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
+ emacs_event->frame_or_window = win;
+ emacs_event->timestamp = EV_TIMESTAMP (e);
+ emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
+ emacs_event->arg = Qnil;
+ XSETINT (emacs_event->x, loc * pixel_height);
+ XSETINT (emacs_event->y, pixel_height-20);
+
+ n_emacs_events_pending++;
+ kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
+ EVENT_INIT (*emacs_event);
+ ns_send_appdefined (-1);
+}
+
+
+/* called manually thru timer to implement repeated button action w/hold-down
*/
+- repeatScroll: (NSTimer *)scrollEntry
+{
+ NSEvent *e = [[self window] currentEvent];
+ NSPoint p = [[self window] mouseLocationOutsideOfEventStream];
+ BOOL inKnob = [self testPart: p] == NSScrollerKnob;
+
+ /* clear timer if need be */
+ if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
+ {
+ [scroll_repeat_entry invalidate];
+ [scroll_repeat_entry release];
+ scroll_repeat_entry = nil;
+
+ if (inKnob)
+ return self;
+
+ scroll_repeat_entry =
+ [[NSTimer scheduledTimerWithTimeInterval:
+ SCROLL_BAR_CONTINUOUS_DELAY
+ target: self
+ selector: @selector (repeatScroll:)
+ userInfo: 0
+ repeats: YES]
+ retain];
+ }
+
+ [self sendScrollEventAtLoc: 0 fromEvent: e];
+ return self;
+}
+
+
+/* Asynchronous mouse tracking for scroller. This allows us to dispatch
+ mouseDragged events without going into a modal loop. */
+- (void)mouseDown: (NSEvent *)e
+{
+ NSRect sr, kr;
+ /* hitPart is only updated AFTER event is passed on */
+ NSScrollerPart part = [self testPart: [e locationInWindow]];
+ double inc = 0.0, loc, kloc, pos;
+ int edge = 0;
+
+ NSTRACE (EmacsScroller_mouseDown);
+
+ switch (part)
+ {
+ case NSScrollerDecrementPage:
+ last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
+ case NSScrollerIncrementPage:
+ last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
+ case NSScrollerDecrementLine:
+ last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
+ case NSScrollerIncrementLine:
+ last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
+ case NSScrollerKnob:
+ last_hit_part = scroll_bar_handle; break;
+ case NSScrollerKnobSlot: /* GNUstep-only */
+ last_hit_part = scroll_bar_move_ratio; break;
+ default: /* NSScrollerNoPart? */
+ fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %d\n", part);
+ return;
+ }
+
+ if (inc != 0.0)
+ {
+ pos = 0; /* ignored */
+
+ /* set a timer to repeat, as we can't let superclass do this modally */
+ scroll_repeat_entry =
+ [[NSTimer scheduledTimerWithTimeInterval: 0.5
+ target: self
+ selector: @selector (repeatScroll:)
+ userInfo: 0
+ repeats: YES]
+ retain];
+ }
+ else
+ {
+ /* handle, or on GNUstep possibly slot */
+ NSEvent *fake_event;
+
+ /* compute float loc in slot and mouse offset on knob */
+ sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
+ toView: nil];
+ loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
+ if (loc <= 0.0)
+ {
+ loc = 0.0;
+ edge = -1;
+ }
+ else if (loc >= NSHeight (sr))
+ {
+ loc = NSHeight (sr);
+ edge = 1;
+ }
+
+ if (edge)
+ kloc = 0.5 * edge;
+ else
+ {
+ kr = [self convertRect: [self rectForPart: NSScrollerKnob]
+ toView: nil];
+ kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
+ }
+ last_mouse_offset = kloc;
+
+ /* if knob, tell emacs a location offset by knob pos
+ (to indicate top of handle) */
+ if (part == NSScrollerKnob)
+ pos = (loc - last_mouse_offset) / NSHeight (sr);
+ else
+ /* else this is a slot click on GNUstep: go straight there */
+ pos = loc / NSHeight (sr);
+
+ /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
+ fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
+ location: [e locationInWindow]
+ modifierFlags: [e modifierFlags]
+ timestamp: [e timestamp]
+ windowNumber: [e windowNumber]
+ context: [e context]
+ eventNumber: [e eventNumber]
+ clickCount: [e clickCount]
+ pressure: [e pressure]];
+ [super mouseUp: fake_event];
+ }
+
+ if (part != NSScrollerKnob)
+ [self sendScrollEventAtLoc: pos fromEvent: e];
+}
+
+
+/* Called as we manually track scroller drags, rather than superclass. */
+- (void)mouseDragged: (NSEvent *)e
+{
+ NSRect sr;
+ double loc, pos;
+ int edge = 0;
+
+ NSTRACE (EmacsScroller_mouseDragged);
+
+ sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
+ toView: nil];
+ loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
+
+ if (loc <= 0.0)
+ {
+ loc = 0.0;
+ edge = -1;
+ }
+ else if (loc >= NSHeight (sr) + last_mouse_offset)
+ {
+ loc = NSHeight (sr) + last_mouse_offset;
+ edge = 1;
+ }
+
+ pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
+ [self sendScrollEventAtLoc: pos fromEvent: e];
+}
+
+
+- (void)mouseUp: (NSEvent *)e
+{
+ if (scroll_repeat_entry)
+ {
+ [scroll_repeat_entry invalidate];
+ [scroll_repeat_entry release];
+ scroll_repeat_entry = nil;
+ }
+ last_hit_part = 0;
+}
+
+
+/* treat scrollwheel events in the bar as though they were in the main window
*/
+- (void) scrollWheel: (NSEvent *)theEvent
+{
+ EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
+ [view mouseDown: theEvent];
+}
+
address@hidden /* EmacsScroller */
+
+
+
+/* ==========================================================================
+
+ EmacsPrefsController implementation
+
+ ==========================================================================
*/
+
+
address@hidden EmacsPrefsController
+
+/* in Tiger+, can just do [popup selectItemWithTag: tag]; */
+static void selectItemWithTag (NSPopUpButton *popup, int tag)
+{
+ NSEnumerator *items = [[popup itemArray] objectEnumerator];
+ NSMenuItem *item;
+ while (item = [items nextObject])
+ {
+ if ([item tag] == tag)
+ {
+ [popup selectItem: item];
+ return;
+ }
+ }
+}
+
+- init
+{
+ [NSBundle loadNibNamed: @"preferences" owner: self];
+ return self;
+}
+
+
+- (void) showForFrame: (struct frame *)f
+{
+ frame = f;
+ [self setPanelFromValues];
+ [prefsWindow makeKeyAndOrderFront: self];
+ [prefsWindow display];
+}
+
+
+- (void) setPanelFromValues
+{
+ int cursorType =
+ ns_lisp_to_cursor_type (get_frame_param (frame, Qcursor_type));
+ prevExpandSpace = XFLOATINT (ns_expand_space);
+ prevBlinkRate = NILP (ns_cursor_blink_rate)
+ ? 0 : XFLOATINT (ns_cursor_blink_rate);
+
+#ifdef NS_IMPL_COCOA
+ prevUseHighlightColor = ns_use_system_highlight_color;
+#endif
+
+ [expandSpaceSlider setFloatValue: prevExpandSpace];
+ [cursorBlinkSlider setFloatValue: prevBlinkRate];
+ [cursorTypeMatrix selectCellWithTag: (cursorType == filled_box ? 1 :
+ (cursorType == bar ? 2 :
+ (cursorType == underscore ? 3 : 4)))];
+ selectItemWithTag (alternateModMenu, lisp_to_mod (ns_alternate_modifier));
+ selectItemWithTag (commandModMenu, lisp_to_mod (ns_command_modifier));
+#ifdef NS_IMPL_COCOA
+ selectItemWithTag (controlModMenu, lisp_to_mod (ns_control_modifier));
+ selectItemWithTag (functionModMenu, lisp_to_mod (ns_function_modifier));
+ [smoothFontsCheck setState: ns_antialias_text ? YES : NO];
+ [useQuickdrawCheck setState: ns_use_qd_smoothing ? YES : NO];
+ [useSysHiliteCheck setState: prevUseHighlightColor ? YES : NO];
+#endif
+}
+
+
+- (void) setValuesFromPanel
+{
+ int cursorTag = [[cursorTypeMatrix selectedCell] tag];
+ int altTag = [[alternateModMenu selectedItem] tag];
+ int cmdTag = [[commandModMenu selectedItem] tag];
+#ifdef NS_IMPL_COCOA
+ int ctrlTag = [[controlModMenu selectedItem] tag];
+ int fnTag = [[functionModMenu selectedItem] tag];
+#endif
+ float blinkRate = [cursorBlinkSlider floatValue];
+ float expandSpace = [expandSpaceSlider floatValue];
+ Lisp_Object old_cursor_blink_mode;
+
+ if (expandSpace != prevExpandSpace)
+ {
+ ns_expand_space = make_float (expandSpace);
+ /* PENDING: more needed: store needed metrics in nsfont_info, update
+ frame default font max_bounds and fontp, recompute faces */
+/* FRAME_LINE_HEIGHT (frame) *= (expandSpace / prevExpandSpace);
+ x_set_window_size (frame, 0, frame->text_cols, frame->text_lines);
*/
+ prevExpandSpace = expandSpace;
+ }
+ if (blinkRate != prevBlinkRate)
+ {
+ old_cursor_blink_mode = ns_cursor_blink_mode;
+ if (blinkRate == 0.0)
+ {
+ ns_cursor_blink_rate = Qnil;
+ ns_cursor_blink_mode = Qnil;
+ }
+ else
+ {
+ ns_cursor_blink_rate = make_float (blinkRate);
+ ns_cursor_blink_mode = Qt;
+ }
+ if (ns_cursor_blink_mode != old_cursor_blink_mode)
+ Feval (Fcons (intern ("blink-cursor-mode"), Qnil));
+
+ if (blinkRate != 0.0 && prevBlinkRate != 0.0)
+ { /* if changed rates, remove blink handler so change picked up */
+ struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
+ [cursor_blink_entry invalidate];
+ [cursor_blink_entry release];
+ cursor_blink_entry = 0;
+ if (dpyinfo->ns_highlight_frame)
+ {
+ Lisp_Object tem =
+ get_frame_param (dpyinfo->ns_highlight_frame, Qcursor_type);
+ dpyinfo->ns_highlight_frame->output_data.ns->desired_cursor =
+ ns_lisp_to_cursor_type (tem);
+ }
+ }
+ prevBlinkRate = blinkRate;
+ }
+ FRAME_NEW_CURSOR (frame) =
+ (cursorTag == 1 ? filled_box :
+ (cursorTag == 2 ? bar :
+ (cursorTag == 3 ? underscore : hollow_box)));
+ store_frame_param (frame, Qcursor_type,
+ ns_cursor_type_to_lisp (FRAME_NEW_CURSOR (frame)));
+ ns_alternate_modifier = ns_mod_to_lisp (altTag);
+ ns_command_modifier = ns_mod_to_lisp (cmdTag);
+#ifdef NS_IMPL_COCOA
+ ns_control_modifier = ns_mod_to_lisp (ctrlTag);
+ ns_function_modifier = ns_mod_to_lisp (fnTag);
+ ns_antialias_text = [smoothFontsCheck state];
+ ns_use_qd_smoothing = [useQuickdrawCheck state];
+ ns_use_system_highlight_color = [useSysHiliteCheck state];
+ if (ns_use_system_highlight_color != prevUseHighlightColor)
+ {
+ prevUseHighlightColor = ns_use_system_highlight_color;
+ if (ns_use_system_highlight_color == YES)
+ {
+ ns_selection_color = [[NSUserDefaults standardUserDefaults]
+ stringForKey: @"AppleHighlightColor"];
+ if (ns_selection_color == nil)
+ ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
+ }
+ else
+ ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
+ }
+#endif /* NS_IMPL_COCOA */
+ Fcall_interactively (intern ("ns-save-preferences"), Qnil, Qnil);
+}
+
+
+/* buttons */
+- (IBAction)cancel: (id)sender
+{
+ [prefsWindow close];
+}
+
+
+- (IBAction)ok: (id)sender
+{
+ [self setValuesFromPanel];
+ [prefsWindow close];
+}
+
+
+- (IBAction)resetToDefaults: (id)sender
+{
+ ns_set_default_prefs ();
+ [self setPanelFromValues];
+}
+
+
+- (IBAction)runHelp: (id)sender
+{
+ Feval (Fcons (intern ("info"),
+ Fcons (build_string ("(ns-emacs)Preferences Panel"), Qnil)));
+ SET_FRAME_GARBAGED (frame);
+ ns_send_appdefined (-1);
+}
+
+
+- (IBAction)setColors: (id)sender
+{
+ Lisp_Object lispFrame;
+ XSETFRAME (lispFrame, frame);
+ Fns_popup_color_panel (lispFrame);
+}
+
+
+- (IBAction)setDefaultFont: (id)sender
+{
+ Lisp_Object lispFrame;
+ XSETFRAME (lispFrame, frame);
+ Fns_popup_font_panel (lispFrame);
+}
+
address@hidden /* EmacsPrefsController */
+
+
+
+
+/* ==========================================================================
+
+ Font-related functions; these used to be in nsfaces.m
+
+ ==========================================================================
*/
+
+
+Lisp_Object
+x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
+{
+ struct font *font = XFONT_OBJECT (font_object);
+
+ if (fontset < 0)
+ fontset = fontset_from_font (font_object);
+ FRAME_FONTSET (f) = fontset;
+
+ if (FRAME_FONT (f) == font)
+ /* This font is already set in frame F. There's nothing more to
+ do. */
+ return font_object;
+
+ FRAME_FONT (f) = font;
+
+ FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
+ FRAME_COLUMN_WIDTH (f) = font->average_width;
+ FRAME_SPACE_WIDTH (f) = font->space_width;
+ FRAME_LINE_HEIGHT (f) = font->height;
+
+ compute_fringe_widths (f, 1);
+
+ /* Compute the scroll bar width in character columns. */
+ if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
+ {
+ int wid = FRAME_COLUMN_WIDTH (f);
+ FRAME_CONFIG_SCROLL_BAR_COLS (f)
+ = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
+ }
+ else
+ {
+ int wid = FRAME_COLUMN_WIDTH (f);
+ FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
+ }
+
+ /* Now make the frame display the given font. */
+ if (FRAME_NS_WINDOW (f) != 0)
+ x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
+
+ return font_object;
+}
+
+
+Lisp_Object
+ns_list_fonts (FRAME_PTR f, Lisp_Object pattern, int size, int maxnames)
+/* --------------------------------------------------------------------------
+ This is used by the xfaces system. It is expected to speak XLFD.
+ --------------------------------------------------------------------------
*/
+{
+ Lisp_Object list = Qnil,
+ rpattern,
+ key,
+ tem,
+ args[2];
+ struct re_pattern_buffer *bufp;
+ id fm = [NSFontManager sharedFontManager];
+ NSEnumerator *fenum, *senum;
+ NSArray *membInfo;
+ NSString *fontname;
+ const char *xlfdName;
+ char *pattFam;
+ char *patt;
+ NSString *famName;
+
+ NSTRACE (ns_list_fonts);
+
+ CHECK_STRING (pattern);
+ patt = XSTRING (pattern)->data;
+
+#if 0
+/* temporary: for font_backend, we use fontsets, and when these are defined,
+ the old XLFD-based system is used; eventually this will be replaced by
+ backend code, but for now we allow specs that are just family names */
+ /* if pattern is not XLFD, panic now */
+ if (patt[0] != '-')
+ error ("ns_list_fonts: X font name (XLFD) expected.");
+
+ /* if unicode encoding not requested, also die */
+ if (!strstr (patt, "iso10646") && patt[strlen (patt)-3] != '*')
+ return Qnil;
+#endif /* 0 */
+
+ key = f ? Fcons (pattern, make_number (maxnames)) : Qnil;
+ tem = f ? XCDR (FRAME_NS_DISPLAY_INFO (f)->name_list_element) : Qnil;
+
+ /* See if we cached the result for this particular query.
+ The cache is an alist of the form:
+ ((((PATTERN . MAXNAMES) FONTNAME) ...) ...)
+ */
+ if (f && !NILP (list = Fassoc (key, tem)))
+ {
+ list = Fcdr_safe (list);
+ /* We have a cached list. Don't have to get the list again. */
+ if (!NILP (list))
+ return list;
+ }
+
+ if (patt[0] != '-')
+ pattFam = patt;
+ else
+ pattFam = ns_xlfd_to_fontname (patt);
+ /*PENDING: '*' at beginning matches literally.. */
+ if (pattFam[0] == '*')
+ pattFam[0] = '.';
+
+ /* must start w/family name, but can have other stuff afterwards
+ (usually bold and italic specifiers) */
+ args[0] = build_string ("^");
+ args[1] = build_string (pattFam);
+ rpattern = Fconcat (2, args);
+ bufp = compile_pattern (rpattern, 0, Vascii_canon_table, 0, 0);
+
+ list = Qnil;
+ fenum = [[fm availableFontFamilies] objectEnumerator];
+ while ( (famName = [fenum nextObject]) )
+ {
+ NSMutableString *tmp = [famName mutableCopy];
+ const char *fname;
+ NSRange r;
+
+ /* remove spaces, to look like postscript name */
+ while ((r = [tmp rangeOfString: @" "]).location != NSNotFound)
+ [tmp deleteCharactersInRange: r];
+
+ fname = [tmp UTF8String];
+ int len = strlen (fname);
+ BOOL foundItal;
+ const char *synthItalFont;
+
+ if (re_search (bufp, fname, len, 0, len, 0) >= 0)
+ {
+ /* Found a family. Add all variants. If we have no italic variant,
+ add a synthItal. */
+ senum =[[fm availableMembersOfFontFamily: famName] objectEnumerator];
+ foundItal = NO;
+ synthItalFont = NULL;
+ while (membInfo = [senum nextObject])
+ {
+ xlfdName =
+ ns_fontname_to_xlfd ([[membInfo objectAtIndex: 0] UTF8String]);
+ list = Fcons (build_string (xlfdName), list);
+ if (!synthItalFont)
+ {
+ NSString *synthName =
+ [[membInfo objectAtIndex: 0]
+ stringByAppendingString: @"-synthItal"];
+ synthItalFont = [synthName UTF8String];
+ }
+ else if ([[membInfo objectAtIndex: 3] intValue]
+ & NSItalicFontMask)
+ foundItal = YES;
+ }
+ if (foundItal == NO)
+ {
+ xlfdName = ns_fontname_to_xlfd (synthItalFont);
+ list = Fcons (build_string (xlfdName), list);
+ }
+ }
+ [tmp release];
+ }
+
+ /* fallback */
+ if (XFASTINT (Flength (list)) == 0)
+ list = Fcons (build_string (ns_fontname_to_xlfd ("Monaco")), list);
+
+ /* store result in cache */
+ if (f != NULL)
+ XCDR_AS_LVALUE (FRAME_NS_DISPLAY_INFO (f)->name_list_element)
+ = Fcons (Fcons (key, list),
+ XCDR (FRAME_NS_DISPLAY_INFO (f)->name_list_element));
+ return list;
+}
+
+
+/* XLFD:
-foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding
*/
+
+const char *
+ns_font_to_xlfd (NSFont *nsfont)
+/* --------------------------------------------------------------------------
+ Convert an NS font name to an X font name (XLFD).
+ The string returned is temporarily allocated.
+ --------------------------------------------------------------------------
*/
+{
+ NSFontManager *mgr = [NSFontManager sharedFontManager];
+ NSString *sname = [nsfont /*familyName*/fontName];
+ char *famName = [sname UTF8String];
+ char *weightStr = [mgr fontNamed: sname hasTraits: NSBoldFontMask] ?
+ "bold" : "medium";
+ char *slantStr = [mgr fontNamed: sname hasTraits: NSItalicFontMask] ?
+ "i" : "r";
+ int size = [nsfont pointSize];
+ int aWidth = lrint (10.0 * [nsfont widthOfString: @"a"]);
+ const char *xlfd;
+ int i, len;
+
+ /* change '-' to '$' to avoid messing w/XLFD separator */
+ for (len =strlen (famName), i =0; i<len; i++)
+ if (famName[i] == '-')
+ {
+ famName[i] = '\0';
+ break;
+ }
+
+ xlfd = [[NSString stringWithFormat:
+ @"-apple-%s-%s-%s-normal--%d-%d-75-75-m-%d-iso10646-1",
+ famName, weightStr, slantStr, size, 10*size, aWidth]
+ UTF8String];
+/*fprintf (stderr, "converted '%s' to '%s'\n",name,xlfd); */
+ return xlfd;
+}
+
+const char *
+ns_fontname_to_xlfd (const char *name)
+/* --------------------------------------------------------------------------
+ Convert an NS font name to an X font name (XLFD).
+ Sizes are set to 0.
+ The string returned is temporarily allocated.
+ --------------------------------------------------------------------------
*/
+{
+ char famName[180];
+ char *weightStr = strcasestr (name, "bold") ? "bold" : "medium";
+ char *slantStr = strcasestr (name, "italic") || strcasestr (name, "oblique")
+ || strcasestr (name, "synthital") ? "i" : "r";
+ int i, len;
+ const char *xlfd;
+
+ /* change '-' to '$' to avoid messing w/XLFD separator, and ' ' to '_' */
+ bzero (famName, 180);
+ bcopy (name, famName, max (strlen (name), 179));
+ for (len =strlen (famName), i =0; i<len; i++)
+ {
+ if (famName[i] == '-')
+ famName[i] = '$';
+ else if (famName[i] == ' ')
+ famName[i] = '_';
+ }
+
+ xlfd = [[NSString stringWithFormat:
+ @"-apple-%s-%s-%s-normal--0-0-75-75-m-0-iso10646-1",
+ famName, weightStr, slantStr]
+ UTF8String];
+/*fprintf (stderr, "converted '%s' to '%s'\n",name,xlfd); */
+ return xlfd;
+}
+
+
+const char *
+ns_xlfd_to_fontname (const char *xlfd)
+/* --------------------------------------------------------------------------
+ Convert an X font name (XLFD) to an NS font name.
+ Only family is used.
+ The string returned is temporarily allocated.
+ --------------------------------------------------------------------------
*/
+{
+ char *name = xmalloc (180);
+ int i, len;
+ const char *ret;
+
+ if (!strncmp (xlfd, "--", 2))
+ sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
+ else
+ sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
+
+ /* stopgap for malformed XLFD input */
+ if (strlen (name) == 0)
+ strcpy (name, "Monaco");
+
+ /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
+ also uppercase after '-' or ' ' */
+ name[0] = toupper (name[0]);
+ for (len =strlen (name), i =0; i<len; i++)
+ {
+ if (name[i] == '$')
+ {
+ name[i] = '-';
+ if (i+1<len)
+ name[i+1] = toupper (name[i+1]);
+ }
+ else if (name[i] == '_')
+ {
+ name[i] = ' ';
+ if (i+1<len)
+ name[i+1] = toupper (name[i+1]);
+ }
+ }
+/*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name); */
+ ret = [[NSString stringWithUTF8String: name] UTF8String];
+ xfree (name);
+ return ret;
+}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Emacs-diffs] Changes to src/nsterm.m,
Adrian Robert <=