--- /dev/null
+diff --git a/src/Makefile b/src/Makefile
+index e27a6ce..fb70481 100644
+--- a/src/Makefile
++++ b/src/Makefile
+@@ -290,7 +290,7 @@ CC=
+ # (X) How to include auto/config.mk depends on the version of "make" you have,
+ # if the current choice doesn't work, try the other one.
+
+-include auto/config.mk
++-include auto/config.mk
+ #.include "auto/config.mk"
+ CClink = $(CC)
+
+@@ -1011,7 +1011,7 @@ INSTALL_PROG = cp
+
+ # Program to install the data in the target directory. Cannot be "mv"!
+ INSTALL_DATA = cp
+-INSTALL_DATA_R = cp -r
++INSTALL_DATA_R = cp -R
+
+ ### Program to run on installed binary
+ #STRIP = strip
+@@ -1225,7 +1225,7 @@ PHOTONGUI_BUNDLE =
+ # CARBON GUI
+ CARBONGUI_SRC = gui.c gui_mac.c
+ CARBONGUI_OBJ = objects/gui.o objects/gui_mac.o objects/pty.o
+-CARBONGUI_DEFS = -DFEAT_GUI_MAC -fno-common -fpascal-strings \
++CARBONGUI_DEFS = -DFEAT_GUI_MAC -DFEAT_GUI_CARBON -fno-common -fpascal-strings \
+ -Wall -Wno-unknown-pragmas \
+ -mdynamic-no-pic -pipe
+ CARBONGUI_IPATH = -I. -Iproto
+@@ -1240,6 +1240,26 @@ CARBONGUI_BUNDLE = gui_bundle
+ APPDIR = $(VIMNAME).app
+ CARBONGUI_TESTARG = VIMPROG=../$(APPDIR)/Contents/MacOS/$(VIMTARGET)
+
++# COCOA GUI
++COCOAGUI_SRC = gui.c gui_mac.m
++PSMTBC_SRC = mac/PSMTabBarControl
++COCOAFMWK_DIR = mac/build/Release
++PSMTBC = $(COCOAFMWK_DIR)/PSMTabBarControl.framework
++COCOAGUI_OBJ = objects/gui.o objects/gui_nmac.o objects/pty.o
++COCOAGUI_DEFS = -DFEAT_GUI_MAC -DFEAT_GUI_COCOA -fno-common -fpascal-strings \
++ -Wall -Wno-unknown-pragmas \
++ -mdynamic-no-pic -pipe
++COCOAGUI_IPATH = -I. -Iproto -F$(COCOAFMWK_DIR)
++COCOAGUI_LIBS_DIR =
++COCOAGUI_LIBS1 = -framework Cocoa -framework PSMTabBarControl -F$(COCOAFMWK_DIR)
++COCOAGUI_LIBS2 =
++COCOAGUI_INSTALL = install_macosx
++COCOAGUI_TARGETS =
++COCOAGUI_MAN_TARGETS =
++COCOAGUI_TESTTARGET = gui
++COCOAGUI_BUNDLE = gui_bundle
++COCOAGUI_TESTARG = VIMPROG=../$(APPDIR)/Contents/MacOS/$(VIMTARGET)
++
+ # All GUI files
+ ALL_GUI_SRC = gui.c gui_gtk.c gui_gtk_f.c gui_motif.c gui_xmdlg.c gui_xmebw.c gui_athena.c gui_gtk_x11.c gui_x11.c gui_at_sb.c gui_at_fs.c pty.c
+ ALL_GUI_PRO = gui.pro gui_gtk.pro gui_motif.pro gui_xmdlg.pro gui_athena.pro gui_gtk_x11.pro gui_x11.pro gui_w16.pro gui_w32.pro gui_photon.pro
+@@ -1800,7 +1820,7 @@ installrtbase: $(HELPSOURCE)/vim.1 $(DEST_VIM) $(DEST_RT) \
+ -$(SHELL) ./installman.sh install $(DEST_MAN) "" $(INSTALLMANARGS)
+ @echo generating help tags
+ # Generate the help tags with ":helptags" to handle all languages.
+- -@cd $(HELPSOURCE); $(MAKE) VIMEXE=$(DEST_BIN)/$(VIMTARGET) vimtags
++ -@srcdir=`pwd`; cd $(HELPSOURCE); $(MAKE) VIMEXE=$$srcdir/$(APPDIR)/Contents/MacOS/$(VIMTARGET) vimtags
+ cd $(HELPSOURCE); \
+ files=`ls *.txt tags`; \
+ files="$$files `ls *.??x tags-?? 2>/dev/null || true`"; \
+@@ -2411,6 +2431,9 @@ objects/gui_photon.o: gui_photon.c
+ objects/gui_mac.o: gui_mac.c
+ $(CCC) -o $@ gui_mac.c
+
++objects/gui_nmac.o: gui_mac.m
++ $(CCC) -ObjC -o $@ gui_mac.m
++
+ objects/hangulin.o: hangulin.c
+ $(CCC) -o $@ hangulin.c
+
+@@ -2568,6 +2591,7 @@ Makefile:
+
+ REZ = /Developer/Tools/Rez
+ RESDIR = $(APPDIR)/Contents/Resources
++FMWKDIR = $(APPDIR)/Contents/Frameworks
+ VERSION = $(VIMMAJOR).$(VIMMINOR)
+
+ ### Common flags
+@@ -2579,7 +2603,7 @@ install_macosx: gui_bundle
+ -rm $(RESDIR)/vim/runtime
+ $(INSTALL_DATA_R) $(APPDIR) $(DESTDIR)$(prefix)
+ # Generate the help tags file now, it won't work with "make installruntime".
+- -@srcdir=`pwd`; cd $(HELPSOURCE); $(MAKE) VIMEXE=$$srcdir/$(VIMTARGET) vimtags
++ -@srcdir=`pwd`; cd $(HELPSOURCE); $(MAKE) VIMEXE=$$srcdir/$(APPDIR)/Contents/MacOS/$(VIMTARGET) vimtags
+ # Install the runtime files. Recursive!
+ -mkdir -p $(DESTDIR)$(prefix)/$(RESDIR)/vim/runtime
+ # -mkdir $(DESTDIR)$(prefix)/$(APPDIR)/bin
+@@ -2597,11 +2621,14 @@ install_macosx: gui_bundle
+ # TODO: Create the vimtutor and/or gvimtutor application.
+
+ gui_bundle: $(RESDIR) bundle-dir bundle-executable bundle-info bundle-resource \
+- bundle-language
++ bundle-language bundle-framework
+
+ $(RESDIR):
+ mkdir -p $@
+
++$(FMWKDIR):
++ mkdir -p $@
++
+ bundle-dir: $(APPDIR)/Contents $(VIMTARGET)
+ # Make a link to the runtime directory, so that we can try out the executable
+ # without installing it.
+@@ -2618,7 +2645,7 @@ bundle-info: bundle-dir
+ @echo "Creating Info.plist"
+ m4 $(M4FLAGSX) infplist.xml > $(APPDIR)/Contents/Info.plist
+
+-bundle-resource: bundle-dir bundle-rsrc
++bundle-resource: bundle-dir
+ cp -f $(RSRC_DIR)/*.icns $(RESDIR)
+
+ ### Classic resources
+@@ -2639,6 +2666,14 @@ bundle-rsrc: os_mac.rsr.hqx
+ # cd po && perl Make_osx.pl --outdir ../$(RESDIR) $(MULTILANG)
+ bundle-language: bundle-dir
+
++$(PSMTBC):
++ @echo "Creating $(PSMTBC)"
++ cd $(PSMTBC_SRC); xcodebuild
++
++bundle-framework: $(FMWKDIR) $(PSMTBC)
++ rm -rf $(FMWKDIR)/PSMTabBarControl.framework
++ cp -Rf $(PSMTBC) $(FMWKDIR)
++
+ $(APPDIR)/Contents:
+ -$(SHELL) ./mkinstalldirs $(APPDIR)/Contents/MacOS
+ -$(SHELL) ./mkinstalldirs $(RESDIR)/English.lproj
+diff --git a/src/configure.in b/src/configure.in
+index ff1bd0c..b911b81 100644
+--- a/src/configure.in
++++ b/src/configure.in
+@@ -127,7 +127,7 @@ if test "`(uname) 2>/dev/null`" = Darwin; then
+ save_cppflags="$CPPFLAGS"
+ save_cflags="$CFLAGS"
+ save_ldflags="$LDFLAGS"
+- CFLAGS="$CFLAGS -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc"
++ CFLAGS="$CFLAGS -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc -mmacosx-version-min=10.4"
+ AC_TRY_LINK([ ], [ ],
+ AC_MSG_RESULT(found, will make universal binary),
+
+@@ -162,11 +162,20 @@ if test "`(uname) 2>/dev/null`" = Darwin; then
+ CPPFLAGS="$CPPFLAGS -I/Developer/Headers/FlatCarbon"
+ fi
+
+- dnl If Carbon is found, assume we don't want X11
+- dnl unless it was specifically asked for (--with-x)
++ dnl If Carbon or Cocoa is found, assume we don't want
++ dnl X11 unless it was specifically asked for (--with-x)
+ dnl or Motif, Athena or GTK GUI is used.
+ AC_CHECK_HEADER(Carbon/Carbon.h, CARBON=yes)
+- if test "x$CARBON" = "xyes"; then
++
++ SAVE_CPPFLAGS=$CPPFLAGS
++ SAVE_CFLAGS=$CFLAGS
++ CPPFLAGS="$CPPFLAGS -ObjC"
++ CFLAGS="$CFLAGS -ObjC"
++ AC_CHECK_HEADER(Cocoa/Cocoa.h, COCOA=yes)
++ CPPFLAGS=$SAVE_CPPFLAGS
++ CFLAGS=$SAVE_CFLAGS
++
++ if test "x$CARBON" = "xyes" -o "x$COCOA" = "xyes"; then
+ if test -z "$with_x" -a "X$enable_gui" != Xmotif -a "X$enable_gui" != Xathena -a "X$enable_gui" != Xgtk -a "X$enable_gui" != Xgtk2; then
+ with_x=no
+ fi
+@@ -1200,7 +1209,7 @@ test "x$with_x" = xno -a "x$MACOSX" != "xyes" -a "x$QNX" != "xyes" && enable_gui
+
+ AC_MSG_CHECKING(--enable-gui argument)
+ AC_ARG_ENABLE(gui,
+- [ --enable-gui[=OPTS] X11 GUI [default=auto] [OPTS=auto/no/gtk/gtk2/gnome/gnome2/motif/athena/neXtaw/photon/carbon]], , enable_gui="auto")
++ [ --enable-gui[=OPTS] X11 GUI [default=auto] [OPTS=auto/no/gtk/gtk2/gnome/gnome2/motif/athena/neXtaw/photon/carbon/cocoa]], , enable_gui="auto")
+
+ dnl Canonicalize the --enable-gui= argument so that it can be easily compared.
+ dnl Do not use character classes for portability with old tools.
+@@ -1216,6 +1225,7 @@ SKIP_ATHENA=YES
+ SKIP_NEXTAW=YES
+ SKIP_PHOTON=YES
+ SKIP_CARBON=YES
++SKIP_COCOA=YES
+ GUITYPE=NONE
+
+ if test "x$QNX" = "xyes" -a "x$with_x" = "xno" ; then
+@@ -1232,14 +1242,20 @@ if test "x$QNX" = "xyes" -a "x$with_x" = "xno" ; then
+
+ elif test "x$MACOSX" = "xyes" -a "x$with_x" = "xno" ; then
+ SKIP_CARBON=
++ SKIP_COCOA=
+ case "$enable_gui_canon" in
+ no) AC_MSG_RESULT(no GUI support)
+- SKIP_CARBON=YES ;;
++ SKIP_CARBON=YES
++ SKIP_COCOA=YES ;;
+ yes|"") AC_MSG_RESULT(yes - automatic GUI support) ;;
+ auto) AC_MSG_RESULT(auto - automatic GUI support) ;;
+- carbon) AC_MSG_RESULT(Carbon GUI support) ;;
+- *) AC_MSG_RESULT([Sorry, $enable_gui GUI is not supported])
++ carbon) AC_MSG_RESULT(Carbon GUI support)
++ SKIP_COCOA=YES ;;
++ cocoa) AC_MSG_RESULT(Cocoa GUI support)
+ SKIP_CARBON=YES ;;
++ *) AC_MSG_RESULT([Sorry, $enable_gui GUI is not supported])
++ SKIP_CARBON=YES
++ SKIP_COCOA=YES ;;
+ esac
+
+ else
+@@ -1253,6 +1269,7 @@ else
+ SKIP_MOTIF=
+ SKIP_ATHENA=
+ SKIP_NEXTAW=
++ SKIP_COCOA=
+ SKIP_CARBON=;;
+ gtk) AC_MSG_RESULT(GTK+ 1.x GUI support)
+ SKIP_GTK=;;
+@@ -1357,12 +1374,30 @@ if test "x$SKIP_CARBON" != "xYES" -a "$enable_gui_canon" != "carbon"; then
+ fi
+ fi
+
++if test "x$SKIP_COCOA" != "xYES" -a "$enable_gui_canon" != "cocoa"; then
++ AC_MSG_CHECKING(whether or not to look for Cocoa)
++ AC_ARG_ENABLE(cocoa-check,
++ [ --enable-cocoa-check If auto-select GUI, check for Cocoa [default=yes]],
++ , enable_cocoa_check="yes")
++ AC_MSG_RESULT($enable_cocoa_check);
++ if test "x$enable_cocoa_check" = "xno"; then
++ SKIP_COCOA=YES
++ fi
++fi
++
++if test "x$MACOSX" = "xyes"; then
++ if test -z "$SKIP_CARBON" -a "x$CARBON" = "xyes"; then
++ AC_MSG_CHECKING(for Carbon GUI)
++ dnl already did the check, just give the message
++ AC_MSG_RESULT(yes);
++ GUITYPE=CARBONGUI
++ elif test -z "$SKIP_COCOA" -a "x$COCOA" = "xyes"; then
++ AC_MSG_CHECKING(for Cocoa GUI)
++ dnl already did the check, just give the message
++ AC_MSG_RESULT(yes);
++ GUITYPE=COCOAGUI
++ fi
+
+-if test "x$MACOSX" = "xyes" -a -z "$SKIP_CARBON" -a "x$CARBON" = "xyes"; then
+- AC_MSG_CHECKING(for Carbon GUI)
+- dnl already did the check, just give the message
+- AC_MSG_RESULT(yes);
+- GUITYPE=CARBONGUI
+ if test "$VIMNAME" = "vim"; then
+ VIMNAME=Vim
+ fi
+@@ -1383,6 +1418,7 @@ if test "x$MACOSX" = "xyes" -a -z "$SKIP_CARBON" -a "x$CARBON" = "xyes"; then
+ SKIP_ATHENA=YES;
+ SKIP_NEXTAW=YES;
+ SKIP_PHOTON=YES;
++ SKIP_COCOA=YES;
+ SKIP_CARBON=YES
+ fi
+
+@@ -3133,7 +3169,7 @@ if test "x$MACOSX" = "xyes" -a -n "$PERL"; then
+ fi
+
+ if test "x$MACOSX" = "xyes" && test "x$CARBON" = "xyes" \
+- && test "x$GUITYPE" != "xCARBONGUI"; then
++ && test "x$GUITYPE" != "xCARBONGUI" && test "x$GUITYPE" != "xCOCOAGUI"; then
+ AC_MSG_CHECKING(whether we need -framework Carbon)
+ dnl check for MACOSX without Carbon GUI, but with FEAT_MBYTE
+ if test "x$enable_multibyte" = "xyes" || test "x$features" = "xbig" \
+diff --git a/src/feature.h b/src/feature.h
+index ae16750..dd10bc8 100644
+--- a/src/feature.h
++++ b/src/feature.h
+@@ -760,7 +760,7 @@
+ #if defined(FEAT_WINDOWS) && defined(FEAT_NORMAL) \
+ && (defined(FEAT_GUI_GTK) \
+ || (defined(FEAT_GUI_MOTIF) && defined(HAVE_XM_NOTEBOOK_H)) \
+- || defined(FEAT_GUI_MAC) \
++ || defined(FEAT_GUI_COCOA) \
+ || (defined(FEAT_GUI_MSWIN) && (!defined(_MSC_VER) || _MSC_VER > 1020)))
+ # define FEAT_GUI_TABLINE
+ #endif
+@@ -807,7 +807,7 @@
+ #endif
+
+ /* Mac specific thing: Codewarrior interface. */
+-#ifdef FEAT_GUI_MAC
++#ifdef FEAT_GUI_CARBON
+ # define FEAT_CW_EDITOR
+ #endif
+
+@@ -1087,7 +1087,7 @@
+ /*
+ * +dnd Drag'n'drop support. Always used for the GTK+ GUI.
+ */
+-#if defined(FEAT_CLIPBOARD) && defined(FEAT_GUI_GTK)
++#if defined(FEAT_CLIPBOARD) && (defined(FEAT_GUI_GTK) || defined(FEAT_GUI_COCOA))
+ # define FEAT_DND
+ #endif
+
+diff --git a/src/gui.c b/src/gui.c
+index bcc3c68..ad30eb9 100644
+--- a/src/gui.c
++++ b/src/gui.c
+@@ -1167,7 +1167,7 @@ gui_position_components(total_width)
+ #endif
+
+ # if defined(FEAT_GUI_TABLINE) && (defined(FEAT_GUI_MSWIN) \
+- || defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_MAC))
++ || defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_COCOA))
+ if (gui_has_tabline())
+ text_area_y += gui.tabline_height;
+ #endif
+@@ -1254,7 +1254,7 @@ gui_get_base_height()
+ # endif
+ # endif
+ # if defined(FEAT_GUI_TABLINE) && (defined(FEAT_GUI_MSWIN) \
+- || defined(FEAT_GUI_MOTIF))
++ || defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_COCOA))
+ if (gui_has_tabline())
+ base_height += gui.tabline_height;
+ # endif
+@@ -2161,7 +2161,7 @@ gui_outstr_nowrap(s, len, flags, fg, bg, back)
+ if (back != 0 && ((draw_flags & DRAW_BOLD) || (highlight_mask & HL_ITALIC)))
+ return FAIL;
+
+-#if defined(RISCOS) || defined(HAVE_GTK2)
++#if defined(RISCOS) || defined(HAVE_GTK2) || defined(FEAT_GUI_COCOA)
+ /* If there's no italic font, then fake it.
+ * For GTK2, we don't need a different font for italic style. */
+ if (hl_mask_todo & HL_ITALIC)
+@@ -2281,7 +2281,7 @@ gui_outstr_nowrap(s, len, flags, fg, bg, back)
+ /* Draw a composing char on top of the previous char. */
+ if (comping)
+ {
+-# if (defined(__APPLE_CC__) || defined(__MRC__)) && TARGET_API_MAC_CARBON
++# if defined(FEAT_GUI_CARBON)
+ /* Carbon ATSUI autodraws composing char over previous char */
+ gui_mch_draw_string(gui.row, scol, s + i, cl,
+ draw_flags | DRAW_TRANSP);
+@@ -4027,7 +4027,7 @@ gui_update_scrollbars(force)
+ # endif
+ #endif
+
+-#if defined(FEAT_GUI_TABLINE) && defined(FEAT_GUI_MSWIN)
++#if defined(FEAT_GUI_TABLINE) && (defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_COCOA))
+ if (gui_has_tabline())
+ y += gui.tabline_height;
+ #endif
+diff --git a/src/gui.h b/src/gui.h
+index 875b5e4..4bbd803 100644
+--- a/src/gui.h
++++ b/src/gui.h
+@@ -34,6 +34,7 @@
+ #endif
+
+ #ifdef FEAT_GUI_MAC
++#ifndef FEAT_GUI_COCOA
+ # include <Types.h>
+ /*# include <Memory.h>*/
+ # include <Quickdraw.h>
+@@ -51,6 +52,7 @@
+ # include <ToolUtils.h>
+ # include <SegLoad.h>*/
+ #endif
++#endif
+
+ #ifdef RISCOS
+ # include "gui_riscos.h"
+@@ -151,7 +153,7 @@
+ #define DRAW_BOLD 0x02 /* draw bold text */
+ #define DRAW_UNDERL 0x04 /* draw underline text */
+ #define DRAW_UNDERC 0x08 /* draw undercurl text */
+-#if defined(RISCOS) || defined(HAVE_GTK2)
++#if defined(RISCOS) || defined(HAVE_GTK2) || defined(FEAT_GUI_COCOA)
+ # define DRAW_ITALIC 0x10 /* draw italic text */
+ #endif
+ #define DRAW_CURSOR 0x20 /* drawing block cursor (win32) */
+@@ -216,9 +218,13 @@ typedef struct GuiScrollbar
+ scroll_shift is set to the number of shifts
+ to reduce the count. */
+ #endif
+-#ifdef FEAT_GUI_MAC
++#ifdef FEAT_GUI_CARBON
+ ControlHandle id; /* A handle to the scrollbar */
+ #endif
++#ifdef FEAT_GUI_COCOA
++ void *scroller; /* instance of NSScroller */
++ int enabled;
++#endif
+ #ifdef RISCOS
+ int id; /* Window handle of scrollbar window */
+ #endif
+@@ -457,12 +463,14 @@ typedef struct Gui
+ #endif
+
+ #ifdef FEAT_GUI_MAC
++#ifndef FEAT_GUI_COCOA
+ WindowPtr VimWindow;
+ MenuHandle MacOSHelpMenu; /* Help menu provided by the MacOS */
+ int MacOSHelpItems; /* Nr of help-items supplied by MacOS */
+ WindowPtr wid; /* Window id of text area */
+ int visibility; /* Is window partially/fully obscured? */
+ #endif
++#endif
+
+ #ifdef RISCOS
+ int window_handle;
+diff --git a/src/gui_mac.m b/src/gui_mac.m
+new file mode 100755
+index 0000000..dff19bc
+--- /dev/null
++++ b/src/gui_mac.m
+@@ -0,0 +1,3777 @@
++/* vi:set ts=4 sts=4 sw=4 foldmethod=marker:
++ *
++ * VIM - Vi IMproved by Bram Moolenaar
++ * GUI/Motif support by Robert Webb
++ * Macintosh port by Dany St-Amant
++ * and Axel Kielhorn
++ * Port to MPW by Bernhard Pruemmer
++ * Initial Carbon port by Ammon Skidmore
++ * Initial Cocoa port by Jjgod Jiang
++ *
++ * Do ":help uganda" in Vim to read copying and usage conditions.
++ * Do ":help credits" in Vim to see a list of people who contributed.
++ * See README.txt for an overview of the Vim source code.
++ *
++ * TODO:
++ *
++ * 1. Toolbar.
++ * 2. GUI Tab.
++ * 3. Multiple Windows.
++ */
++
++#include "vim.h"
++#import <Cocoa/Cocoa.h>
++#import <PSMTabBarControl/PSMTabBarControl.h>
++
++#define GUI_MAC_DEBUG 1
++
++/* Internal Data Structures {{{ */
++
++#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
++typedef long NSInteger;
++#endif
++
++/* Key mapping {{{2 */
++
++static struct
++{
++ UniChar function_key;
++ int vim_key;
++} function_key_mapping[] =
++{
++ { NSUpArrowFunctionKey, K_UP },
++ { NSDownArrowFunctionKey, K_DOWN },
++ { NSLeftArrowFunctionKey, K_LEFT },
++ { NSRightArrowFunctionKey, K_RIGHT },
++
++ { NSF1FunctionKey, K_F1 },
++ { NSF2FunctionKey, K_F2 },
++ { NSF3FunctionKey, K_F3 },
++ { NSF4FunctionKey, K_F4 },
++ { NSF5FunctionKey, K_F5 },
++ { NSF6FunctionKey, K_F6 },
++ { NSF7FunctionKey, K_F7 },
++ { NSF8FunctionKey, K_F8 },
++ { NSF9FunctionKey, K_F9 },
++ { NSF10FunctionKey, K_F10 },
++
++ { NSF11FunctionKey, K_F11 },
++ { NSF12FunctionKey, K_F12 },
++ { NSF13FunctionKey, K_F13 },
++ { NSF14FunctionKey, K_F14 },
++ { NSF15FunctionKey, K_F15 },
++
++ { NSInsertFunctionKey, K_INS },
++ { NSDeleteFunctionKey, K_DEL },
++ { NSHomeFunctionKey, K_HOME },
++ { NSEndFunctionKey, K_END },
++
++ { NSPageUpFunctionKey, K_PAGEUP },
++ { NSPageDownFunctionKey, K_PAGEDOWN },
++
++ { '\t', '\t' }, /* tab */
++ { '\r', '\r' }, /* return */
++ { '\003', '\003' }, /* enter */
++ { '\031', K_S_TAB }, /* backtab */
++ { '\033', '\033' }, /* escape */
++ { '\177', K_BS }, /* backspace */
++
++ /* End of list marker: */
++ { 0, 0 },
++};
++
++/* 2}}} */
++
++#define VIM_MAX_COL_LEN 1024
++#define VIM_MAX_FONT_NAME_LEN 256
++#define VIM_MAX_BUTTON_TITLE 256
++#define VIM_DEFAULT_FONT_SIZE 9
++#define VIM_DEFAULT_FONT_NAME (char_u *) "Monaco:h12"
++#define VIM_MAX_CHAR_WIDTH 2
++
++#define GUI_MAC_DELAY_OPEN 1
++#define VIM_UNDERLINE_OFFSET 0
++#define VIM_UNDERLINE_HEIGHT 1
++#define VIM_UNDERCURL_HEIGHT 2
++#define VIM_UNDERCURL_OFFSET (-2)
++#define VIM_UNDERCURL_DOT_WIDTH 2
++#define VIM_UNDERCURL_DOT_DISTANCE 2
++
++#define VIMDropFilesEventSubtype 10001
++
++#define FF_Y(row) (gui_mac.main_height - FILL_Y(row))
++#define FT_Y(row) (gui_mac.main_height - TEXT_Y(row))
++#define VIM_BG_ALPHA ((100 - p_transp) / 100.0)
++
++/* A simple view to make setting text area, scrollbar position inside
++ * vim window easier */
++@interface VIMContentView: NSView {
++ NSTabView *tabView;
++ PSMTabBarControl *tabBarControl;
++}
++
++- (PSMTabBarControl *) tabBarControl;
++- (NSTabViewItem *) addNewTabViewItem;
++- (NSTabView *) tabView;
++
++@end
++
++@interface VIMTextView: NSView <NSTextInput>
++{
++ NSRange markedRange;
++ NSRange selectedRange;
++ NSAttributedString *markedText;
++ NSMutableDictionary *markedTextAttributes;
++
++ NSImage *contentImage;
++ NSString *lastSetTitle;
++}
++
++- (NSAttributedString *) markedText;
++- (void) setMarkedTextAttribute:(id)value forKey:(NSString *)key;
++- (void) mouseAction:(int)button repeated:(bool)repeated event:(NSEvent *)event;
++
++- (void) synchronizeContentImage;
++- (void) beginDrawing;
++- (void) endDrawing;
++
++- (void) clearAll;
++
++@end
++
++@interface NSWindow (Private)
++- (void) setBottomCornerRounded: (bool) rounded;
++- (void) _setContentHasShadow: (BOOL) has;
++@end
++
++@interface VIMWindow: NSWindow {
++ VIMTextView *textView;
++}
++
++- (VIMTextView *) textView;
++- (void) setTextView: (VIMTextView *) view;
++
++@end
++
++@interface VIMScroller : NSScroller
++{
++ scrollbar_T *vimScrollBar;
++}
++
++- (id)initWithVimScrollbar:(scrollbar_T *)scrollBar
++ orientation:(int)orientation;
++- (scrollbar_T *) vimScrollBar;
++- (void) setThumbValue:(long)value size:(long)size max:(long)max;
++
++@end
++
++static int VIMAlertTextFieldHeight = 22;
++
++@interface VIMAlert : NSAlert {
++ NSTextField *textField;
++}
++
++- (void) setTextFieldString:(NSString *)textFieldString;
++- (NSTextField *) textField;
++
++@end
++
++@interface VimAppController: NSObject
++- (void) alertDidEnd:(VIMAlert *)alert returnCode:(int)returnCode contextInfo:(void *)contextInfo;
++- (void) panelDidEnd:(NSSavePanel *)panel code:(int)code context:(void *)context;
++- (void) initializeApplicationTimer:(NSTimer *)timer;
++- (void) blinkCursorTimer:(NSTimer *)timer;
++- (void) menuAction:(id)sender;
++@end
++
++enum gui_mac_debug_level {
++ MSG_INFO = 0,
++ MSG_DEBUG = 1,
++ MSG_WARN = 2,
++ MSG_ERROR = 3
++};
++
++struct gui_mac_data {
++ NSColor *fg_color, *bg_color, *sp_color;
++
++ VIMWindow *current_window;
++
++ NSFont *current_font;
++ NSFont *selected_font;
++
++ int app_is_running;
++ CGFloat main_height;
++
++ int blink_state;
++ long blink_wait;
++ long blink_on;
++ long blink_off;
++ NSTimer *blink_timer;
++
++ bool input_received;
++ bool initialized;
++
++ int dialog_button;
++ NSString *selected_file;
++
++ int im_row, im_col;
++ NSEvent *last_mouse_down_event;
++
++ int debug_level;
++ BOOL showing_tabline;
++ BOOL selecting_tab;
++ BOOL window_opened;
++
++ CGSize single_advances[VIM_MAX_COL_LEN];
++ CGSize double_advances[VIM_MAX_COL_LEN];
++
++ VimAppController *app_delegate;
++ NSAutoreleasePool *app_pool;
++} gui_mac;
++
++#define FLIPPED_RECT(view, rect) NSMakeRect(rect.origin.x, \
++ [view frame].size.height - \
++ rect.origin.y - rect.size.height, \
++ rect.size.width, \
++ rect.size.height)
++#define FLIPPED_POINT(view, point) NSMakePoint(point.x, \
++ [view frame].size.height - point.y)
++
++#define gui_mac_run_app() gui_mac.app_is_running = TRUE
++#define gui_mac_stop_app(yn) { gui_mac.input_received = yn; gui_mac.app_is_running = FALSE; }
++#define gui_mac_app_is_running() (gui_mac.app_is_running == TRUE)
++#define gui_mac_get_scroller(sb) ((VIMScroller *) sb->scroller)
++
++/* Data Structures }}}*/
++
++/* Internal functions prototypes {{{ */
++
++@interface NSApplication (VimAdditions)
++- (void) setAppleMenu:(NSMenu *)aMenu;
++@end
++
++@interface NSFont (AppKitPrivate)
++- (ATSUFontID) _atsFontID;
++@end
++
++NSColor *NSColorFromGuiColor(guicolor_T color, float alpha);
++NSAlertStyle NSAlertStyleFromVim(int type);
++#define NSStringFromVim(str) ([NSString stringWithUTF8String: (const char *) str])
++NSRect NSRectFromVim(int row1, int col1, int row2, int col2);
++
++GuiFont gui_mac_create_related_font(GuiFont font, bool italic, bool bold);
++NSWindow *gui_mac_get_window(NSRect rect);
++int gui_mac_create_window(NSRect rect);
++void gui_mac_open_window();
++void gui_mac_set_application_menu();
++void gui_mac_send_dummy_event();
++void gui_mac_update();
++
++#define currentView ([gui_mac.current_window textView])
++#define gui_mac_begin_drawing() [currentView beginDrawing]
++#define gui_mac_end_drawing() [currentView endDrawing]
++#define gui_mac_begin_tab_action() (gui_mac.selecting_tab = YES)
++#define gui_mac_end_tab_action() (gui_mac.selecting_tab = NO)
++
++int gui_mac_hex_digit(int c);
++void gui_mac_redraw();
++void gui_mac_scroll_rect(NSRect rect, int lines);
++
++void print_vim_modifiers(unsigned int vim_modifiers);
++unsigned int gui_mac_key_modifiers_to_vim(unsigned int mac_modifiers);
++unsigned int gui_mac_mouse_modifiers_to_vim(unsigned int mac_modifiers);
++int gui_mac_function_key_to_vim(UniChar key_char, unsigned int vim_modifiers);
++int gui_mac_mouse_button_to_vim(int mac_button);
++
++GuiFont gui_mac_find_font(char_u *font_name);
++int gui_mac_points_to_pixels(char_u *str, char_u **end);
++NSFont *gui_mac_get_font(char_u *font_name, int size);
++
++int gui_mac_select_from_font_panel(char_u *font_name);
++void gui_mac_update_scrollbar(scrollbar_T *sb);
++void gui_mac_msg(int level, NSString *fmt, ...);
++
++#define NSShowRect(msg, rect) gui_mac_msg(MSG_DEBUG, @"%s: %g %g %g %g", msg, \
++ rect.origin.x, rect.origin.y, \
++ rect.size.width, rect.size.height)
++
++/* Internal functions prototypes }}} */
++
++/* Initializtion and Finalization {{{ */
++
++int gui_mch_init()
++{
++ gui_mac_msg(MSG_INFO, @"gui_mch_init: %s", exe_name);
++
++ gui_mac.app_pool = [NSAutoreleasePool new];
++
++ [NSApplication sharedApplication];
++
++ gui_mac.app_delegate = [VimAppController new];
++ [NSApp setDelegate: gui_mac.app_delegate];
++
++ [NSApp setMainMenu: [[NSMenu new] autorelease]];
++ gui_mac_set_application_menu();
++
++ gui.char_width = 0;
++ gui.char_height = 0;
++ gui.char_ascent = 0;
++ gui.num_rows = 24;
++ gui.num_cols = 80;
++ gui.tabline_height = 22;
++ gui.in_focus = TRUE;
++
++ gui.norm_pixel = 0x00000000;
++ gui.back_pixel = 0x00FFFFFF;
++ set_normal_colors();
++
++ gui_check_colors();
++ gui.def_norm_pixel = gui.norm_pixel;
++ gui.def_back_pixel = gui.back_pixel;
++
++ /* Get the colors for the highlight groups (gui_check_colors() might have
++ * changed them) */
++ highlight_gui_started();
++
++#ifdef FEAT_MENU
++ gui.menu_height = 0;
++#endif
++ gui.scrollbar_height = gui.scrollbar_width = [VIMScroller scrollerWidth];
++ gui.border_offset = gui.border_width = 2;
++
++ gui_mac.current_window = nil;
++ gui_mac.input_received = NO;
++ gui_mac.initialized = NO;
++ gui_mac.showing_tabline = NO;
++ gui_mac.selecting_tab = NO;
++ gui_mac.window_opened = NO;
++
++ return OK;
++}
++
++int gui_mch_init_check()
++{
++ gui_mac_msg(MSG_INFO, @"gui_mch_init_check");
++
++ /* see main.c for reason to disallow */
++ if (disallow_gui)
++ return FAIL;
++
++ return OK;
++}
++
++void gui_mch_exit(int rc)
++{
++ gui_mac_msg(MSG_INFO, @"gui_mch_exit\n");
++
++ [gui_mac.last_mouse_down_event release];
++ [gui_mac.selected_file release];
++ [gui_mac.app_delegate release];
++ [gui_mac.app_pool release];
++
++ [[NSUserDefaults standardUserDefaults] synchronize];
++
++ exit(rc);
++}
++
++int gui_mch_open()
++{
++ gui_mac_msg(MSG_INFO, @"gui_mch_open: %d %d", gui_win_x, gui_win_y);
++
++#if GUI_MAC_DELAY_OPEN
++#else
++ gui_mac_open_window();
++
++ if (gui_win_x != -1 && gui_win_y != -1)
++ gui_mch_set_winpos(gui_win_x, gui_win_y);
++#endif
++ return OK;
++}
++
++void gui_mch_prepare(int *argc, char **argv)
++{
++ NSAutoreleasePool *pool = [NSAutoreleasePool new];
++
++ NSString *path = [[NSBundle mainBundle] executablePath];
++
++ gui_mac.debug_level = MSG_DEBUG;
++ gui_mac_msg(MSG_INFO, @"gui_mch_prepare: %@", path);
++
++ exe_name = vim_strsave((char_u *) [path fileSystemRepresentation]);
++
++ [pool release];
++}
++
++void gui_mch_set_shellsize(
++ int width,
++ int height,
++ int min_width,
++ int min_height,
++ int base_width,
++ int base_height,
++ int direction)
++{
++ NSWindow *window = gui_mac_get_window(NSMakeRect(0, 0, width, height));
++ NSRect contentRect = [window contentRectForFrameRect: [window frame]];
++
++ /* keep the top left corner not change */
++ contentRect.origin.y += contentRect.size.height - height;
++ contentRect.size.width = width;
++ contentRect.size.height = height;
++
++ gui_mac_msg(MSG_INFO, @"gui_mch_set_shellsize: "
++ "(%d, %d, %d, %d, %d, %d, %d)\n",
++ width, height, min_width, min_height,
++ base_width, base_height, direction);
++
++ gui_mac_msg(MSG_INFO, @"gui.num_rows (%d) * gui.char_height (%d) = %d",
++ gui.num_rows, gui.char_height, gui.num_rows * gui.char_height);
++
++ gui_mac_msg(MSG_INFO, @"gui.num_cols (%d) * gui.char_width (%d) = %d",
++ gui.num_cols, gui.char_width, gui.num_cols * gui.char_width);
++
++ NSRect frame = [window frameRectForContentRect: contentRect];
++ [window setFrame: frame display: NO];
++}
++
++void gui_mch_set_text_area_pos(int x, int y, int w, int h)
++{
++ gui_mac_msg(MSG_INFO, @"gui_mch_set_text_area_pos: "
++ "%d, %d, %d, %d", x, y, w, h);
++
++ NSRect viewRect = NSMakeRect(x, y, w, h);
++ // If we don't have a text view yet, allocate it first
++ if (! currentView)
++ {
++ // NSShowRect("create textView: ", viewRect);
++ VIMTextView *textView = [[VIMTextView alloc] initWithFrame: viewRect];
++ [textView setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
++
++ [gui_mac.current_window setTextView: textView];
++ [textView release];
++ }
++ else
++ {
++ if (! NSEqualRects([currentView frame], viewRect))
++ [currentView setFrame: viewRect];
++
++ [currentView synchronizeContentImage];
++
++ if ([currentView inLiveResize])
++ [gui_mac.current_window setTitle:
++ [NSString stringWithFormat: @"VIM - %d×%d", gui.num_cols, gui.num_rows]];
++ }
++}
++
++/* Initializtion and Finalization }}} */
++
++/* Event related {{{ */
++
++void gui_mch_update()
++{
++ // gui_mch_wait_for_chars(0);
++}
++
++/* wtime < 0: wait forever
++ * wtime > 0: wait wtime milliseconds
++ * wtime = 0: don't wait, only poll existing events
++ */
++int gui_mch_wait_for_chars(int wtime)
++{
++ NSEvent *event;
++ NSAutoreleasePool *pool;
++ NSDate *date;
++
++ pool = [[NSAutoreleasePool alloc] init];
++
++ // TODO: only redraw modified part
++ if (wtime != 0)
++ gui_mac_redraw();
++
++ if (wtime == 0)
++ {
++ // gui_mac_msg(MSG_DEBUG, @"gui_mch_wait_for_chars: don't wait");
++ date = [NSDate distantPast];
++ }
++ else if (wtime > 0)
++ {
++ // gui_mac_msg(MSG_DEBUG, @"gui_mch_wait_for_chars: wait for %d ms", wtime);
++ date = [NSDate dateWithTimeIntervalSinceNow: (double) wtime / 1000.0];
++ }
++ /* wtime < 0, wait forever */
++ else
++ {
++ // gui_mac_msg(MSG_DEBUG, @"gui_mch_wait_for_chars: wait forever");
++ date = [NSDate distantFuture];
++ }
++
++ /* It's tricky here: we don't want to use -[NSApplication run:]
++ * all the time, but we need it to do some initialization for
++ * the first time this app starts. So we install a timer to
++ * stop: NSApp just after it runs.
++ */
++ if (gui_mac.initialized == NO)
++ {
++ // gui_mac_msg(MSG_DEBUG, @"first time, begin initialization...");
++ [NSTimer scheduledTimerWithTimeInterval: 0.1
++ target: gui_mac.app_delegate
++ selector: @selector(initializeApplicationTimer:)
++ userInfo: 0
++ repeats: NO];
++ [NSApp run];
++
++ gui_mac.initialized = YES;
++ // gui_mac_msg(MSG_DEBUG, @"end initialization.");
++ }
++
++ gui_mac_run_app();
++ while (gui_mac_app_is_running() &&
++ (event = [NSApp nextEventMatchingMask: NSAnyEventMask
++ untilDate: date
++ inMode: NSDefaultRunLoopMode
++ dequeue: YES]) != nil)
++ {
++ [NSApp sendEvent: event];
++ }
++
++ BOOL last_received = gui_mac.input_received;
++
++ gui_mac.input_received = NO;
++
++ [pool release];
++ return last_received;
++}
++
++/* Event related }}} */
++
++/* Input Method Handling {{{ */
++
++int im_get_status()
++{
++ if (! gui.in_use)
++ return 0;
++
++ return 0;
++}
++
++void im_set_active(int active)
++{
++}
++
++void im_set_position(int row, int col)
++{
++ gui_mac_msg(MSG_INFO, @"im_set_position: (%d, %d)", row, col);
++ gui_mac.im_row = row;
++ gui_mac.im_col = col;
++}
++
++/* Input Method Handling }}} */
++
++/* Misc Stuff {{{ */
++
++void gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
++{
++ CGRect rect;
++
++ rect = CGDisplayBounds(CGMainDisplayID());
++
++ *screen_w = (int) rect.size.width;
++ *screen_h = (int) rect.size.height;
++
++ gui_mac_msg(MSG_INFO, @"gui_mch_get_screen_dimensions: %d, %d",
++ *screen_w, *screen_h);
++}
++
++#ifdef USE_MCH_ERRMSG
++
++void display_errors()
++{
++ fflush(stderr);
++}
++
++#endif
++
++int gui_mch_haskey(char_u *name)
++{
++ return OK;
++}
++
++void gui_mch_beep()
++{
++ NSBeep();
++}
++
++void gui_mch_toggle_tearoffs(int enable)
++{
++ /* no tearoff menus */
++}
++
++/* Misc Stuff }}} */
++
++/* Font Handling {{{ */
++
++int gui_mch_init_font(char_u *font_name, int fontset)
++{
++ NSAutoreleasePool *pool;
++ NSFont *mac_font;
++ CTFontRef ctFont;
++ GuiFont vim_font;
++ int i;
++ NSSize advance;
++ char_u used_font_name[VIM_MAX_FONT_NAME_LEN];
++
++ if (font_name == NULL)
++ font_name = VIM_DEFAULT_FONT_NAME;
++
++ gui_mac_msg(MSG_INFO, @"gui_mch_init_font: %s", font_name);
++
++ if (STRCMP(font_name, "*") == 0)
++ {
++ char_u *new_p_guifont;
++
++ if (gui_mac_select_from_font_panel(font_name) != OK)
++ return FAIL;
++
++ /* Set guifont to the name of the selected font. */
++ new_p_guifont = alloc(STRLEN(font_name) + 1);
++ if (new_p_guifont != NULL)
++ {
++ STRCPY(new_p_guifont, font_name);
++ vim_free(p_guifont);
++ p_guifont = new_p_guifont;
++ /* Replace spaces in the font name with underscores. */
++ for ( ; *new_p_guifont; ++new_p_guifont)
++ {
++ if (*new_p_guifont == ' ')
++ *new_p_guifont = '_';
++ }
++ }
++ }
++
++ pool = [NSAutoreleasePool new];
++ vim_font = gui_mac_find_font(font_name);
++
++ if (vim_font == NOFONT)
++ {
++ gui_mac_msg(MSG_WARN, @"find_font failed");
++ return FAIL;
++ }
++
++ gui.norm_font = vim_font;
++ gui.ital_font = gui_mac_create_related_font(vim_font, true, false);
++ gui.bold_font = gui_mac_create_related_font(vim_font, false, true);
++ gui.boldital_font = gui_mac_create_related_font(vim_font, true, true);
++
++ // NSLog(@"i(%@), b(%@), ib(%@)", gui.ital_font, gui.bold_font, gui.boldital_font);
++ vim_strncpy(used_font_name, font_name, sizeof(used_font_name) - 1);
++
++ gui_mac_msg(MSG_INFO, @"gui_mch_init_font: font_name: '%s'", font_name);
++
++ hl_set_font_name(used_font_name);
++
++ mac_font = (NSFont *) vim_font;
++ ctFont = (CTFontRef) mac_font;
++ advance = [mac_font advancementForGlyph: (NSGlyph) '_'];
++
++ /* in 72 DPI, 1 point = 1 pixel */
++ gui.char_ascent = roundf(CTFontGetAscent(ctFont));
++ gui.char_width = roundf(advance.width);
++
++ // Initialize advances array, it's a pre-mature optimization, evil
++ for (i = 0; i < VIM_MAX_COL_LEN; i++)
++ {
++ gui_mac.single_advances[i] = CGSizeMake(gui.char_width, 0);
++ gui_mac.double_advances[i] = CGSizeMake(gui.char_width * 2, 0);
++ }
++
++ /* Character placement in a line:
++ *
++ * +-----------------------+ <- top
++ * | p_linespace
++ * +--------------
++ * | Ascent
++ * +---------------- <- origin.y
++ * | Descent
++ * +------------------
++ * | Leading
++ * +------------------------+ <- bottom
++ *
++ * The real situation is a bit complicated than we thought,
++ * basically, some fonts may find the Descent + Leading not
++ * enough to put every details of their characters (i.e. the
++ * descent part of a 'g' or 'y' may exceeds the bottom line).
++ * However, we must fill the entire rectangle ranged from
++ * top to bottom. So in consequence, the rect of the next
++ * line can overwrites some of the descent part of the upper
++ * line, which is bad, but no better solutions. */
++
++ float height = CTFontGetAscent(ctFont) +
++ CTFontGetDescent(ctFont) +
++ CTFontGetLeading(ctFont);
++ // NSLog(@"Ascent = %g, Descent = %g, Leading = %g",
++ // CTFontGetAscent(ctFont), CTFontGetDescent(ctFont), CTFontGetLeading(ctFont));
++ gui.char_height = roundf(height) + p_linespace;
++
++ [gui_mac.current_window setResizeIncrements: NSMakeSize(gui.char_width, gui.char_height)];
++
++#if 0
++ gui_mac_msg(MSG_INFO, @"ascent = %d, width = %d, height = %d, %f, %f",
++ gui.char_ascent, gui.char_width, gui.char_height,
++ [mac_font ascender], [mac_font descender]);
++#endif
++ [pool release];
++
++ return OK;
++}
++
++void gui_mch_free_font(GuiFont font)
++{
++ [(NSFont *) font release];
++}
++
++void gui_mch_set_font(GuiFont font)
++{
++ gui_mac.current_font = (NSFont *) font;
++ [currentView setMarkedTextAttribute: gui_mac.current_font
++ forKey: NSFontAttributeName];
++}
++
++GuiFont gui_mch_get_font(char_u *name, int giveErrorIfMissing)
++{
++ GuiFont font;
++
++ gui_mac_msg(MSG_INFO, @"gui_mch_get_font: %s", name);
++ font = gui_mac_find_font(name);
++
++ if (font == NOFONT)
++ {
++ if (giveErrorIfMissing)
++ EMSG2(_(e_font), name);
++ return NOFONT;
++ }
++ /*
++ * TODO : Accept only monospace
++ */
++
++ return font;
++}
++
++char_u *gui_mch_get_fontname(GuiFont font, char_u *name)
++{
++ if (name == NULL)
++ return NULL;
++
++ return vim_strsave(name);
++}
++
++int gui_mch_adjust_charheight()
++{
++ CTFontRef mac_font = (CTFontRef) gui_mac.current_font;
++
++ if (mac_font == nil)
++ return OK;
++
++ /* in 72 DPI, 1 point = 1 pixel */
++ gui.char_ascent = roundf(CTFontGetAscent(mac_font));
++ gui.char_height = roundf(CTFontGetAscent(mac_font) +
++ CTFontGetDescent(mac_font) +
++ CTFontGetLeading(mac_font)) + p_linespace;
++ return OK;
++}
++
++/* Font Handling }}} */
++
++/* Window Handling {{{ */
++
++@implementation VIMWindow
++
++- (id) initWithContentRect:(NSRect)contentRect
++{
++ unsigned int windowStyle = NSTitledWindowMask |
++ NSMiniaturizableWindowMask |
++ NSClosableWindowMask |
++ NSResizableWindowMask |
++ NSUnifiedTitleAndToolbarWindowMask |
++ NSTexturedBackgroundWindowMask;
++
++ // NSShowRect("VIMWindow initWithContentRect", contentRect);
++ if ([super initWithContentRect: contentRect
++ styleMask: windowStyle
++ backing: NSBackingStoreBuffered
++ defer: YES])
++ {
++ // [self setBackgroundColor: [NSColor clearColor]];
++ // [self setOpaque: YES];
++ [self setViewsNeedDisplay: NO];
++ [self setTitle: @"gVIM on Macintosh"];
++ [self setResizeIncrements: NSMakeSize(gui.char_width, gui.char_height)];
++ [self setDelegate: gui_mac.app_delegate];
++
++ [self _setContentHasShadow: NO];
++ [self setOpaque: NO];
++
++ textView = nil;
++
++ VIMContentView *contentView = [[VIMContentView alloc] initWithFrame: contentRect];
++ [self setContentView: contentView];
++ [contentView release];
++
++ if ([self respondsToSelector: @selector(setBottomCornerRounded:)])
++ [self setBottomCornerRounded: NO];
++
++ [self makeFirstResponder: textView];
++ }
++
++ return self;
++}
++
++- (VIMTextView *) textView
++{
++ return textView;
++}
++
++- (void) setTextView: (VIMTextView *) view
++{
++ if (textView)
++ [textView removeFromSuperview];
++
++ textView = view;
++ [[self contentView] addSubview: textView];
++ // [textView setHidden: YES];
++}
++
++@end
++
++void gui_mch_set_foreground()
++{
++ // gui_mac_msg(MSG_DEBUG, @"gui_mch_set_foreground");
++ [gui_mac.current_window orderFront: nil];
++}
++
++void gui_mch_set_winpos(int x, int y)
++{
++ gui_mac_msg(MSG_INFO, @"gui_mch_set_winpos: %d, %d", x, y);
++
++ /* Get the visiable area (excluding menubar and dock) of screen */
++ NSRect visibleFrame = [[NSScreen mainScreen] visibleFrame];
++ NSPoint topLeft = NSMakePoint(x + visibleFrame.origin.x,
++ visibleFrame.origin.y + visibleFrame.size.height - y);
++ [gui_mac.current_window setFrameTopLeftPoint: topLeft];
++}
++
++int gui_mch_get_winpos(int *x, int *y)
++{
++ NSRect windowRect = [gui_mac.current_window frame];
++ NSRect visibleFrame = [[NSScreen mainScreen] visibleFrame];
++
++ // NSShowRect("windowRect", windowRect);
++
++ float X_vim = windowRect.origin.x - visibleFrame.origin.x;
++ float Y_vim = visibleFrame.origin.y + visibleFrame.size.height -
++ (windowRect.origin.y + windowRect.size.height);
++
++ gui_mac_msg(MSG_INFO, @"X_vim = %g - %g = %g", windowRect.origin.x,
++ visibleFrame.origin.x, X_vim);
++ gui_mac_msg(MSG_INFO, @"Y_vim = %g + %g - (%g + %g) = %g", visibleFrame.origin.y,
++ visibleFrame.size.height, windowRect.origin.y, windowRect.size.height,
++ Y_vim);
++
++ if (X_vim < 0)
++ X_vim = 0;
++ if (X_vim > visibleFrame.size.width)
++ X_vim = visibleFrame.size.width;
++
++ if (Y_vim < 0)
++ Y_vim = 0;
++ if (Y_vim > visibleFrame.size.height)
++ Y_vim = visibleFrame.size.height;
++
++ *x = (int) X_vim;
++ *y = (int) Y_vim;
++
++ return OK;
++}
++
++void gui_mch_settitle(char_u *title, char_u *icon)
++{
++ gui_mac_msg(MSG_INFO, @"gui_mch_set_title: (%s, %s)", title, icon);
++
++ [gui_mac.current_window setTitle: NSStringFromVim(title)];
++}
++
++void gui_mch_iconify()
++{
++ gui_mac_msg(MSG_INFO, @"gui_mch_iconify");
++}
++
++/* Window Handling }}} */
++
++/* Menu Handling {{{ */
++
++NSMenuItem *gui_mac_insert_menu_item(vimmenu_T *menu)
++{
++ vimmenu_T *parent, *brother;
++ NSMenu *parent_menu = nil;
++ NSMenuItem *mac_menu_item, *item;
++ int alloc = 0, index, len;
++
++ brother = menu->next;
++ /* My brother could be the PopUp, find my real brother */
++ while ((brother != NULL) && (! menu_is_menubar(brother->name)))
++ brother = brother->next;
++
++ len = STRLEN(menu->dname);
++ // A menu separator must starts with a '-' and ends with a '-'
++ if (len > 2 && menu->dname[0] == '-' && menu->dname[len - 1] == '-')
++ mac_menu_item = [NSMenuItem separatorItem];
++ else
++ {
++ NSString *title = NSStringFromVim(menu->dname);
++ mac_menu_item = [[NSMenuItem alloc] initWithTitle: title
++ action: @selector(menuAction:)
++ keyEquivalent: @""];
++ [mac_menu_item setTarget: gui_mac.app_delegate];
++ [mac_menu_item setTag: (int) menu];
++ alloc = 1;
++
++ if (menu->actext != NULL)
++ {
++ NSString *tooltip = NSStringFromVim(menu->actext);
++
++ [mac_menu_item setToolTip: tooltip];
++ }
++ }
++ menu->item_handle = (void *) mac_menu_item;
++
++ parent = menu->parent;
++ if (parent == NULL)
++ {
++ if (menu_is_menubar(menu->name))
++ parent_menu = [NSApp mainMenu];
++ }
++ else
++ parent_menu = (NSMenu *) parent->menu_handle;
++
++ if (parent_menu)
++ {
++ /* If index == -1, means in parent menu we cannot find
++ * this menu item, must be something wrong, but we still
++ * need to handle this gracefully */
++ if (brother != NULL &&
++ (item = (NSMenuItem *) brother->item_handle) != NULL &&
++ (index = [parent_menu indexOfItem: item]) != -1)
++ [parent_menu insertItem: mac_menu_item
++ atIndex: index];
++ else
++ [parent_menu addItem: mac_menu_item];
++ } else
++ [mac_menu_item retain];
++
++ if (alloc)
++ [mac_menu_item release];
++
++ return mac_menu_item;
++}
++
++void gui_mch_add_menu(vimmenu_T *menu, int idx)
++{
++ gui_mac_msg(MSG_INFO, @"gui_mch_add_menu: %s, %d", menu->dname, idx);
++
++ NSString *title = NSStringFromVim(menu->dname);
++ NSMenu *mac_menu = [[NSMenu alloc] initWithTitle: title];
++ NSMenuItem *mac_menu_item = gui_mac_insert_menu_item(menu);
++
++ [mac_menu_item setSubmenu: mac_menu];
++ menu->menu_handle = (void *) mac_menu;
++
++ [mac_menu release];
++}
++
++void gui_mch_add_menu_item(vimmenu_T *menu, int idx)
++{
++ gui_mac_msg(MSG_INFO, @"gui_mch_add_menu_item: %s, %d", menu->dname, idx);
++
++ gui_mac_insert_menu_item(menu);
++}
++
++void gui_mch_destroy_menu(vimmenu_T *menu)
++{
++ NSMenu *parent_menu = nil;
++
++ if (menu == NULL)
++ return;
++
++ if (menu->parent == NULL)
++ {
++ if (menu_is_menubar(menu->name))
++ parent_menu = [NSApp mainMenu];
++ else
++ [(NSMenu *) menu->menu_handle release];
++ }
++ else
++ parent_menu = (NSMenu *) menu->parent->menu_handle;
++
++ if (parent_menu)
++ [parent_menu removeItem: (NSMenuItem *) menu->item_handle];
++
++ menu->item_handle = NULL;
++}
++
++void gui_mch_draw_menubar()
++{
++}
++
++void gui_mch_menu_grey(vimmenu_T *menu, int grey)
++{
++ NSMenuItem *item;
++
++ if (menu == NULL)
++ return;
++
++ item = (NSMenuItem *) menu->item_handle;
++ [item setEnabled: grey ? NO : YES];
++}
++
++void gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
++{
++ /* There's no hidden mode on MacOS */
++ gui_mch_menu_grey(menu, hidden);
++}
++
++void gui_mch_show_popupmenu(vimmenu_T *menu)
++{
++ NSMenu *mac_menu = (NSMenu *) menu->menu_handle;
++ NSEvent *event = gui_mac.last_mouse_down_event;
++
++ gui_update_cursor(TRUE, TRUE);
++ gui_mac_redraw();
++
++ [NSMenu popUpContextMenu: mac_menu
++ withEvent: event
++ forView: currentView];
++}
++
++void gui_make_popup(char_u *path_name, int mouse_pos)
++{
++ vimmenu_T *menu = gui_find_menu(path_name);
++
++ if (menu == NULL)
++ return;
++
++ NSMenu *mac_menu = (NSMenu *) menu->menu_handle;
++ NSEvent *event;
++ NSPoint point;
++
++ if (mouse_pos)
++ point = [gui_mac.current_window convertScreenToBase: [NSEvent mouseLocation]];
++ else
++ {
++ int row = curwin->w_wrow;
++ int col = curwin->w_wcol;
++
++ point = NSMakePoint(FILL_X(col), FILL_Y(row));
++ point = [currentView convertPoint: point toView: nil];
++ }
++
++ event = [NSEvent mouseEventWithType: NSRightMouseDown
++ location: point
++ modifierFlags: 0
++ timestamp: 0
++ windowNumber: [gui_mac.current_window windowNumber]
++ context: nil
++ eventNumber: 0
++ clickCount: 0
++ pressure: 1.0];
++
++ [NSMenu popUpContextMenu: mac_menu
++ withEvent: event
++ forView: currentView];
++}
++
++void gui_mch_enable_menu(int flag)
++{
++ /* menu is always active */
++}
++
++void gui_mch_set_menu_pos(int x, int y, int w, int h)
++{
++ /* menu position is fixed, always at the top */
++}
++
++/* Menu Handling }}} */
++
++/* Dialog related {{{ */
++
++char_u *gui_mch_browse(
++ int saving,
++ char_u *title,
++ char_u *dflt,
++ char_u *ext,
++ char_u *initdir,
++ char_u *filter)
++{
++ NSString *dir = nil, *file = nil;
++
++ if (initdir != NULL)
++ dir = NSStringFromVim(initdir);
++
++ if (dflt != NULL)
++ file = NSStringFromVim(dflt);
++
++ gui_mac.selected_file = nil;
++ if (saving)
++ {
++ NSSavePanel *panel = [NSSavePanel savePanel];
++
++ [panel setTitle: NSStringFromVim(title)];
++ [panel beginSheetForDirectory: dir
++ file: file
++ modalForWindow: gui_mac.current_window
++ modalDelegate: gui_mac.app_delegate
++ didEndSelector: @selector(panelDidEnd:code:context:)
++ contextInfo: NULL];
++ } else
++ {
++ NSOpenPanel *panel = [NSOpenPanel openPanel];
++
++ [panel setTitle: NSStringFromVim(title)];
++ [panel setAllowsMultipleSelection: NO];
++
++ [panel beginSheetForDirectory: dir
++ file: file
++ types: nil
++ modalForWindow: gui_mac.current_window
++ modalDelegate: gui_mac.app_delegate
++ didEndSelector: @selector(panelDidEnd:code:context:)
++ contextInfo: NULL];
++ }
++
++ [NSApp run];
++ [gui_mac.current_window makeKeyAndOrderFront: nil];
++
++ if (! gui_mac.selected_file)
++ return NULL;
++
++ char_u *s = vim_strsave((char_u *) [gui_mac.selected_file fileSystemRepresentation]);
++ [gui_mac.selected_file release];
++ gui_mac.selected_file = nil;
++
++ return s;
++}
++
++int gui_mch_dialog(
++ int type,
++ char_u *title,
++ char_u *message,
++ char_u *buttons,
++ int dfltbutton,
++ char_u *textfield)
++{
++ gui_mac_redraw();
++
++ VIMAlert *alert = [[VIMAlert alloc] init];
++ char_u *p, button_title[VIM_MAX_BUTTON_TITLE];
++ int len;
++ NSString *textFieldString = @"", *messageString;
++
++ if (textfield)
++ {
++ if (textfield[0] != '\0')
++ textFieldString = NSStringFromVim(textfield);
++
++ [alert setTextFieldString: textFieldString];
++ }
++
++ [alert setAlertStyle: NSAlertStyleFromVim(type)];
++
++ if (title)
++ [alert setMessageText: NSStringFromVim(title)];
++
++ if (message)
++ {
++ messageString = NSStringFromVim(message);
++
++ if (! title)
++ {
++ // HACK! If there is a '\n\n' or '\n' sequence in the message, then
++ // make the part up to there into the title. We only do this
++ // because Vim has lots of dialogs without a title and they look
++ // ugly that way.
++ // TODO: Fix the actual dialog texts.
++ NSRange eolRange = [messageString rangeOfString: @"\n\n"];
++ if (eolRange.location == NSNotFound)
++ eolRange = [messageString rangeOfString: @"\n"];
++
++ if (eolRange.location != NSNotFound)
++ {
++ [alert setMessageText: [messageString substringToIndex: eolRange.location]];
++
++ messageString = [messageString substringFromIndex: NSMaxRange(eolRange)];
++ }
++ }
++
++ [alert setInformativeText: messageString];
++ } else if (textFieldString)
++ {
++ // Make sure there is always room for the input text field.
++ [alert setInformativeText: @""];
++ }
++
++ for (p = buttons; *p != 0; p++)
++ {
++ len = 0;
++
++ for (; *p != DLG_BUTTON_SEP && *p != '\0' && len < VIM_MAX_BUTTON_TITLE - 1; p++)
++ if (*p != DLG_HOTKEY_CHAR)
++ button_title[len++] = *p;
++
++ button_title[len] = '\0';
++ [alert addButtonWithTitle: NSStringFromVim(button_title)];
++
++ if (*p == '\0')
++ break;
++ }
++
++ [alert beginSheetModalForWindow: gui_mac.current_window
++ modalDelegate: gui_mac.app_delegate
++ didEndSelector: @selector(alertDidEnd:returnCode:contextInfo:)
++ contextInfo: (void *) textfield];
++
++ /* Because vim runs it's own event loop, when it's calling gui_mch_dialog(),
++ * maybe the event loop is stopped, then no one will receive and dispatch
++ * events during the modal dialog opens, then button clicked event won't be
++ * received, so here we must run an event loop and try to receive that event
++ * inside this loop. */
++ [NSApp run];
++ [gui_mac.current_window makeKeyAndOrderFront: nil];
++
++ [alert release];
++
++ gui_mac_redraw();
++ /* The result vim expected start from 1 */
++ return gui_mac.dialog_button;
++}
++
++/* Dialog related }}} */
++
++/* Color related {{{ */
++
++/* Colors Macros */
++#define RGB(r,g,b) ((r) << 16) + ((g) << 8) + (b)
++#define Red(c) ((c & 0x00FF0000) >> 16)
++#define Green(c) ((c & 0x0000FF00) >> 8)
++#define Blue(c) ((c & 0x000000FF) >> 0)
++
++long_u gui_mch_get_rgb(guicolor_T pixel)
++{
++ return (Red(pixel) << 16) + (Green(pixel) << 8) + Blue(pixel);
++}
++
++void gui_mch_new_colors()
++{
++}
++
++guicolor_T gui_mch_get_color(char_u *name)
++{
++ typedef struct guicolor_tTable
++ {
++ char *name;
++ guicolor_T color;
++ } guicolor_tTable;
++
++ /*
++ * The comment at the end of each line is the source
++ * (Mac, Window, Unix) and the number is the unix rgb.txt value
++ */
++ static guicolor_tTable table[] =
++ {
++ { "Black", RGB(0x00, 0x00, 0x00) },
++ { "darkgray", RGB(0x80, 0x80, 0x80) }, /*W*/
++ { "darkgrey", RGB(0x80, 0x80, 0x80) }, /*W*/
++ { "Gray", RGB(0xC0, 0xC0, 0xC0) }, /*W*/
++ { "Grey", RGB(0xC0, 0xC0, 0xC0) }, /*W*/
++ { "lightgray", RGB(0xE0, 0xE0, 0xE0) }, /*W*/
++ { "lightgrey", RGB(0xE0, 0xE0, 0xE0) }, /*W*/
++ { "gray10", RGB(0x1A, 0x1A, 0x1A) }, /*W*/
++ { "grey10", RGB(0x1A, 0x1A, 0x1A) }, /*W*/
++ { "gray20", RGB(0x33, 0x33, 0x33) }, /*W*/
++ { "grey20", RGB(0x33, 0x33, 0x33) }, /*W*/
++ { "gray30", RGB(0x4D, 0x4D, 0x4D) }, /*W*/
++ { "grey30", RGB(0x4D, 0x4D, 0x4D) }, /*W*/
++ { "gray40", RGB(0x66, 0x66, 0x66) }, /*W*/
++ { "grey40", RGB(0x66, 0x66, 0x66) }, /*W*/
++ { "gray50", RGB(0x7F, 0x7F, 0x7F) }, /*W*/
++ { "grey50", RGB(0x7F, 0x7F, 0x7F) }, /*W*/
++ { "gray60", RGB(0x99, 0x99, 0x99) }, /*W*/
++ { "grey60", RGB(0x99, 0x99, 0x99) }, /*W*/
++ { "gray70", RGB(0xB3, 0xB3, 0xB3) }, /*W*/
++ { "grey70", RGB(0xB3, 0xB3, 0xB3) }, /*W*/
++ { "gray80", RGB(0xCC, 0xCC, 0xCC) }, /*W*/
++ { "grey80", RGB(0xCC, 0xCC, 0xCC) }, /*W*/
++ { "gray90", RGB(0xE5, 0xE5, 0xE5) }, /*W*/
++ { "grey90", RGB(0xE5, 0xE5, 0xE5) }, /*W*/
++ { "white", RGB(0xFF, 0xFF, 0xFF) },
++ { "darkred", RGB(0x80, 0x00, 0x00) }, /*W*/
++ { "red", RGB(0xDD, 0x08, 0x06) }, /*M*/
++ { "lightred", RGB(0xFF, 0xA0, 0xA0) }, /*W*/
++ { "DarkBlue", RGB(0x00, 0x00, 0x80) }, /*W*/
++ { "Blue", RGB(0x00, 0x00, 0xD4) }, /*M*/
++ { "lightblue", RGB(0xA0, 0xA0, 0xFF) }, /*W*/
++ { "DarkGreen", RGB(0x00, 0x80, 0x00) }, /*W*/
++ { "Green", RGB(0x00, 0x64, 0x11) }, /*M*/
++ { "lightgreen", RGB(0xA0, 0xFF, 0xA0) }, /*W*/
++ { "DarkCyan", RGB(0x00, 0x80, 0x80) }, /*W ?0x307D7E */
++ { "cyan", RGB(0x02, 0xAB, 0xEA) }, /*M*/
++ { "lightcyan", RGB(0xA0, 0xFF, 0xFF) }, /*W*/
++ { "darkmagenta",RGB(0x80, 0x00, 0x80) }, /*W*/
++ { "magenta", RGB(0xF2, 0x08, 0x84) }, /*M*/
++ { "lightmagenta",RGB(0xF0, 0xA0, 0xF0) }, /*W*/
++ { "brown", RGB(0x80, 0x40, 0x40) }, /*W*/
++ { "yellow", RGB(0xFC, 0xF3, 0x05) }, /*M*/
++ { "lightyellow",RGB(0xFF, 0xFF, 0xA0) }, /*M*/
++ { "darkyellow", RGB(0xBB, 0xBB, 0x00) }, /*U*/
++ { "SeaGreen", RGB(0x2E, 0x8B, 0x57) }, /*W 0x4E8975 */
++ { "orange", RGB(0xFC, 0x80, 0x00) }, /*W 0xF87A17 */
++ { "Purple", RGB(0xA0, 0x20, 0xF0) }, /*W 0x8e35e5 */
++ { "SlateBlue", RGB(0x6A, 0x5A, 0xCD) }, /*W 0x737CA1 */
++ { "Violet", RGB(0x8D, 0x38, 0xC9) }, /*U*/
++ };
++
++ int r, g, b;
++ int i;
++
++ if (name[0] == '#' && strlen((char *) name) == 7)
++ {
++ /* Name is in "#rrggbb" format */
++ r = gui_mac_hex_digit(name[1]) * 16 + gui_mac_hex_digit(name[2]);
++ g = gui_mac_hex_digit(name[3]) * 16 + gui_mac_hex_digit(name[4]);
++ b = gui_mac_hex_digit(name[5]) * 16 + gui_mac_hex_digit(name[6]);
++ if (r < 0 || g < 0 || b < 0)
++ return INVALCOLOR;
++ return RGB(r, g, b);
++ }
++ else
++ {
++ if (STRICMP(name, "hilite") == 0)
++ {
++ float red, green, blue, alpha;
++ [[NSColor highlightColor] getRed: &red
++ green: &green
++ blue: &blue
++ alpha: &alpha];
++ return (RGB(r, g, b));
++ }
++
++ /* Check if the name is one of the colors we know */
++ for (i = 0; i < sizeof(table) / sizeof(table[0]); i++)
++ if (STRICMP(name, table[i].name) == 0)
++ return table[i].color;
++ }
++
++ /*
++ * Last attempt. Look in the file "$VIM/rgb.txt".
++ */
++#define LINE_LEN 100
++ FILE *fd;
++ char line[LINE_LEN];
++ char_u *fname;
++
++ fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt");
++ if (fname == NULL)
++ return INVALCOLOR;
++
++ fd = fopen((char *)fname, "rt");
++ vim_free(fname);
++ if (fd == NULL)
++ return INVALCOLOR;
++
++ while (! feof(fd))
++ {
++ int len;
++ int pos;
++ char *color;
++
++ fgets(line, LINE_LEN, fd);
++ len = strlen(line);
++
++ if (len <= 1 || line[len-1] != '\n')
++ continue;
++
++ line[len-1] = '\0';
++
++ i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos);
++ if (i != 3)
++ continue;
++
++ color = line + pos;
++
++ if (STRICMP(color, name) == 0)
++ {
++ fclose(fd);
++ return (guicolor_T) RGB(r, g, b);
++ }
++ }
++
++ fclose(fd);
++
++ return INVALCOLOR;
++}
++
++void gui_mch_set_fg_color(guicolor_T color)
++{
++ gui_mac.fg_color = NSColorFromGuiColor(color, 1.0);
++
++ // TODO: should set for all views
++ [currentView setMarkedTextAttribute: gui_mac.fg_color
++ forKey: NSForegroundColorAttributeName];
++}
++
++void gui_mch_set_bg_color(guicolor_T color)
++{
++ gui_mac.bg_color = NSColorFromGuiColor(color, VIM_BG_ALPHA);
++
++ // TODO: should set for all views
++ [currentView setMarkedTextAttribute: gui_mac.bg_color
++ forKey: NSBackgroundColorAttributeName];
++}
++
++void gui_mch_set_sp_color(guicolor_T color)
++{
++ gui_mac.sp_color = NSColorFromGuiColor(color, 1.0);
++}
++
++/* Color related }}} */
++
++/* Drawing related {{{ */
++
++void gui_mch_flush()
++{
++ // gui_mac_msg(MSG_DEBUG, @"gui_mch_flush");
++ // gui_mac_redraw();
++}
++
++static inline CGRect CGRectFromNSRect(NSRect nsRect) { return *(CGRect*)&nsRect; }
++
++void gui_mch_invert_rectangle(int r, int c, int nr, int nc)
++{
++ NSRect rect;
++
++ gui_mac_begin_drawing();
++
++ rect = NSRectFromVim(r, c, r + nr, c + nc);
++
++ CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
++ CGContextSaveGState (context);
++ CGContextSetBlendMode(context, kCGBlendModeDifference);
++ CGContextSetRGBFillColor (context, 1.0, 1.0, 1.0, 1.0);
++ CGContextFillRect (context, CGRectFromNSRect(rect));
++ CGContextRestoreGState (context);
++
++ gui_mac_end_drawing();;
++}
++
++void gui_mch_flash(int msec)
++{
++}
++
++void gui_mch_clear_all()
++{
++ [currentView clearAll];
++#if GUI_MAC_DELAY_OPEN
++ if (! gui_mac.window_opened)
++ gui_mac_open_window();
++#endif
++}
++
++void gui_mch_clear_block(int row1, int col1, int row2, int col2)
++{
++ NSRect rect;
++
++ // NSLog(@"clearBlock: (%d, %d) - (%d, %d)", row1, col1, row2, col2);
++
++ gui_mch_set_bg_color(gui.back_pixel);
++
++ gui_mac_begin_drawing();
++
++ rect = NSRectFromVim(row1, col1, row2, col2);
++ // NSShowRect("clearBlock", rect);
++
++ [gui_mac.bg_color set];
++ NSRectFill(rect);
++
++ gui_mac_end_drawing();
++}
++
++void gui_mch_delete_lines(int row, int num_lines)
++{
++ NSRect src_rect;
++
++ // NSLog(@"deleteLines: (%d, %d)", row, num_lines);
++ src_rect = NSRectFromVim(row + num_lines, // row1
++ gui.scroll_region_left, // col1
++ gui.scroll_region_bot, // row2
++ gui.scroll_region_right); // col2
++
++ // NSShowRect("src_rect", src_rect);
++ // move src_dest up for numlines
++ gui_mac_scroll_rect(src_rect, -num_lines);
++
++ gui_clear_block(gui.scroll_region_bot - num_lines + 1,
++ gui.scroll_region_left,
++ gui.scroll_region_bot,
++ gui.scroll_region_right);
++}
++
++void gui_mch_insert_lines(int row, int num_lines)
++{
++ NSRect src_rect;
++
++ // NSLog(@"insertLines: (%d, %d)", row, num_lines);
++ src_rect = NSRectFromVim(row, // row1
++ gui.scroll_region_left, // col1
++ gui.scroll_region_bot - num_lines, // row2
++ gui.scroll_region_right); // col2
++
++ // move src_dest down for num_lines
++ gui_mac_scroll_rect(src_rect, num_lines);
++
++ /* Update gui.cursor_row if the cursor scrolled or copied over */
++ if (gui.cursor_row >= gui.row
++ && gui.cursor_col >= gui.scroll_region_left
++ && gui.cursor_col <= gui.scroll_region_right)
++ {
++ if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
++ gui.cursor_row += num_lines;
++ else if (gui.cursor_row <= gui.scroll_region_bot)
++ gui.cursor_is_valid = FALSE;
++ }
++
++ gui_clear_block(row, gui.scroll_region_left,
++ row + num_lines - 1,
++ gui.scroll_region_right);
++}
++
++void gui_mch_draw_hollow_cursor(guicolor_T color)
++{
++}
++
++void gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
++{
++ NSRect rect;
++ int left;
++
++#ifdef FEAT_RIGHTLEFT
++ /* vertical line should be on the right of current point */
++ if (CURSOR_BAR_RIGHT)
++ left = FILL_X(gui.col + 1) - w;
++ else
++#endif
++ left = FILL_X(gui.col);
++
++ rect = NSMakeRect(left, FF_Y(gui.row + 2) + h, w, h);
++
++ gui_mac_begin_drawing();
++ [NSColorFromGuiColor(color, 1.0) set];
++ // gui_mac_msg(MSG_DEBUG, @"rect = %g %g %g %g",
++ // rect.origin.x, rect.origin.y,
++ // rect.size.width, rect.size.height);
++ [NSBezierPath fillRect: rect];
++ gui_mac_end_drawing();
++}
++
++void print_draw_flags(int flags)
++{
++ if (flags & DRAW_BOLD)
++ fprintf(stderr, "bold, ");
++
++ if (flags & DRAW_ITALIC)
++ fprintf(stderr, "italic, ");
++
++ if (flags & DRAW_UNDERL)
++ fprintf(stderr, "underline");
++
++ if (flags & DRAW_UNDERC)
++ fprintf(stderr, "undercurl");
++
++ if (flags && ! (flags & DRAW_TRANSP))
++ fprintf(stderr, "\n");
++}
++
++void gui_mac_draw_ct_line(CGContextRef context, CTLineRef line,
++ NSPoint origin, int row);
++
++void gui_mch_draw_string(int row, int col, char_u *s, int len, int flags)
++{
++ // gui_mac_msg(MSG_DEBUG, @"gui_mch_draw_string: %d, %d, %d", row, col, len);
++ CTLineRef line;
++ CFStringRef string;
++ CFDictionaryRef attributes;
++ CFAttributedStringRef attrString;
++ CTFontRef font = (CTFontRef) gui_mac.current_font;
++
++ CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName };
++ CFTypeRef values[] = { font, gui_mac.fg_color };
++
++ // Create a CFString from the original UTF-8 string 's'
++ string = CFStringCreateWithBytes(kCFAllocatorDefault,
++ s, len,
++ kCFStringEncodingUTF8,
++ false);
++
++ // Create the attribute for Core Text layout
++ attributes = CFDictionaryCreate(kCFAllocatorDefault,
++ (const void **) &keys,
++ (const void **) &values,
++ sizeof(keys) / sizeof(keys[0]),
++ &kCFTypeDictionaryKeyCallBacks,
++ &kCFTypeDictionaryValueCallBacks);
++
++ attrString = CFAttributedStringCreate(kCFAllocatorDefault,
++ string,
++ attributes);
++ CFRelease(string);
++ CFRelease(attributes);
++
++ line = CTLineCreateWithAttributedString(attrString);
++ if (! line)
++ return;
++
++ NSRect rect = NSMakeRect(FILL_X(col), FF_Y(row + 1),
++ gui.char_width * len, gui.char_height);
++ if (has_mbyte)
++ {
++ int cell_len = 0;
++ int n;
++
++ /* Compute the length in display cells. */
++ for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
++ cell_len += (*mb_ptr2cells)(s + n);
++
++ rect.size.width = gui.char_width * cell_len;
++ }
++
++ gui_mac_begin_drawing();
++
++ CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
++ CGAffineTransform transform = CGAffineTransformIdentity;
++
++ /* NOTE: Since we already set 'gui.ital_font' and 'gui.boldital_font',
++ * then if gui.c really called us with DRAW_ITALIC flags, it means
++ * there is no italic font available, we must faking the italic by
++ * slant the upright (norm_font) to the right in a small angle, that's
++ * what we are doing in the next line.
++ *
++ * However, things get complicated when a character is slanted, it
++ * may (almost sure will) expand to the space on the right side of
++ * that character. There is no problem when a whole bunch of chars
++ * are drawn with this flag, but if the next call still ask us to
++ * draw on the same line, following the slanted texts, the new part
++ * will overwrite some part of the slanted characters we've drawn
++ * before, it's ugly, but I haven't found a better solution. */
++ transform.c = (flags & DRAW_ITALIC) ? Fix2X(kATSItalicQDSkew) : 0.0;
++
++ CGContextSetTextMatrix(context, transform);
++ CGContextSetAllowsAntialiasing(context, p_antialias);
++
++ if (! (flags & DRAW_TRANSP))
++ {
++ [gui_mac.bg_color set];
++ NSRectFill(rect);
++ }
++
++ CGContextSetRGBFillColor(context,
++ [gui_mac.fg_color redComponent],
++ [gui_mac.fg_color greenComponent],
++ [gui_mac.fg_color blueComponent],
++ 1.0);
++
++ NSPoint textOrigin = NSMakePoint(rect.origin.x,
++ FT_Y(row) - p_linespace);
++ CGContextSetTextPosition(context, textOrigin.x, textOrigin.y);
++
++ gui_mac_draw_ct_line(context, line, textOrigin, row);
++
++ if (flags & DRAW_UNDERL)
++ {
++ [gui_mac.sp_color set];
++ NSRectFill(NSMakeRect(rect.origin.x,
++ rect.origin.y + VIM_UNDERLINE_OFFSET,
++ rect.size.width, VIM_UNDERLINE_HEIGHT));
++ }
++
++ if (flags & DRAW_UNDERC)
++ {
++ [gui_mac.sp_color set];
++
++ float line_end_x = rect.origin.x + rect.size.width;
++ int i = 0;
++ NSRect line_rect = NSMakeRect(rect.origin.x,
++ rect.origin.y,
++ VIM_UNDERCURL_DOT_WIDTH,
++ VIM_UNDERCURL_HEIGHT);
++
++ while (line_rect.origin.x < line_end_x)
++ {
++ if (i % 2)
++ NSRectFill(line_rect);
++
++ line_rect.origin.x += VIM_UNDERCURL_DOT_DISTANCE;
++ i++;
++ }
++ }
++
++ gui_mac_end_drawing();
++
++ CFRelease(line);
++}
++
++void gui_mac_draw_ct_line(CGContextRef context, CTLineRef line, NSPoint origin, int row)
++{
++ CFArrayRef runArray = CTLineGetGlyphRuns(line);
++ CFIndex runCount = CFArrayGetCount(runArray);
++ CFIndex i, glyphOffset;
++ CGFloat x;
++
++ for (i = 0, x = origin.x, glyphOffset = 0; i < runCount; i++)
++ {
++ CTRunRef run = (CTRunRef) CFArrayGetValueAtIndex(runArray, i);
++ CFDictionaryRef attrDict = CTRunGetAttributes(run);
++ CTFontRef runFont = (CTFontRef) CFDictionaryGetValue(attrDict,
++ kCTFontAttributeName);
++ bool isDouble = (runFont != (CTFontRef) gui_mac.current_font);
++ CFIndex len = CTRunGetGlyphCount(run);
++ CGFloat advance = len * gui.char_width;
++ if (isDouble)
++ advance *= 2;
++
++ CGContextSetTextPosition(context, x, origin.y);
++
++ // NSLog(@"r%d, %d, %g, (%g, %g), run[%d] len = %d, font = %@",
++ // row, isDouble, advance, x, origin.y, i, len, [runFont fontName]);
++ x += advance;
++ CGFontRef cgFont = CTFontCopyGraphicsFont(runFont, NULL);
++ CGContextSetFont(context, cgFont);
++ CGContextSetFontSize(context, CTFontGetSize(runFont));
++
++ const CGGlyph *glyphs = CTRunGetGlyphsPtr(run);
++
++ CGContextShowGlyphsWithAdvances(context, glyphs,
++ isDouble ? gui_mac.double_advances
++ : gui_mac.single_advances,
++ len);
++ CFRelease(cgFont);
++ }
++}
++
++/* Drawing related }}} */
++
++/* Clipboard related {{{ */
++
++void clip_mch_lose_selection(VimClipboard *cbd)
++{
++}
++
++int clip_mch_own_selection(VimClipboard *cbd)
++{
++ return OK;
++}
++
++/* copy from system clipboard, paste to vim */
++void clip_mch_set_selection(VimClipboard *cbd)
++{
++ // If the '*' register isn't already filled in, fill it in now.
++ cbd->owned = TRUE;
++ clip_get_selection(cbd);
++ cbd->owned = FALSE;
++
++ // Get the text to put on the pasteboard.
++ long_u len = 0; char_u *str = 0;
++ int type = clip_convert_selection(&str, &len, cbd);
++ if (type < 0)
++ return;
++
++ NSString *string = [[NSString alloc] initWithBytes: str
++ length: len
++ encoding: NSUTF8StringEncoding];
++
++ NSPasteboard *pb = [NSPasteboard generalPasteboard];
++
++ [pb declareTypes: [NSArray arrayWithObject: NSStringPboardType] owner: nil];
++ [pb setString: string
++ forType: NSStringPboardType];
++
++ [string release];
++ vim_free(str);
++}
++
++/* copy from vim, paste to system clipboard */
++void clip_mch_request_selection(VimClipboard *cbd)
++{
++ NSPasteboard *pb = [NSPasteboard generalPasteboard];
++ NSString *type = [pb availableTypeFromArray: [NSArray arrayWithObject: NSStringPboardType]];
++
++ if (type)
++ {
++ NSMutableString *string = [[pb stringForType: NSStringPboardType] mutableCopy];
++
++ // Replace unrecognized end-of-line sequences with \x0a (line feed).
++ NSRange range = NSMakeRange(0, [string length]);
++ unsigned n = [string replaceOccurrencesOfString: @"\x0d\x0a"
++ withString: @"\x0a"
++ options: 0
++ range: range];
++ if (n == 0)
++ n = [string replaceOccurrencesOfString: @"\x0d"
++ withString: @"\x0a"
++ options: 0
++ range: range];
++
++ // Scan for newline character to decide whether the string should be
++ // pasted linewise or characterwise.
++ int char_type = MCHAR;
++ if (0 < n || NSNotFound != [string rangeOfString: @"\n"].location)
++ char_type = MLINE;
++
++ const char *utf8chars = [string UTF8String];
++ clip_yank_selection(char_type, (char_u*) utf8chars, strlen(utf8chars), cbd);
++ }
++}
++
++/* Clipboard related }}} */
++
++/* Scrollbar related {{{ */
++
++const char *scrollbar_desc(scrollbar_T *sb)
++{
++ switch (sb->type)
++ {
++ case SBAR_LEFT:
++ return "LEFT";
++
++ case SBAR_RIGHT:
++ return "RIGHT";
++
++ case SBAR_BOTTOM:
++ return "BOTTOM";
++
++ default:
++ return "NONE";
++ }
++}
++
++void gui_mch_create_scrollbar(scrollbar_T *sb, int orient)
++{
++ gui_mac_msg(MSG_INFO, @"gui_mch_create_scrollbar: ident = %ld, "
++ "type = %s, value = %ld, size = %ld, "
++ "max = %ld, top = %d, height = %d, "
++ "width = %d, status_height = %d, %s",
++ sb->ident, scrollbar_desc(sb),
++ sb->value, sb->size, sb->max,
++ sb->top, sb->height, sb->width, sb->status_height,
++ orient == SBAR_HORIZ ? "H" : "V");
++ VIMScroller *scroller;
++
++ scroller = [[VIMScroller alloc] initWithVimScrollbar: sb
++ orientation: orient];
++ sb->scroller = (void *) scroller;
++}
++
++void gui_mch_destroy_scrollbar(scrollbar_T *sb)
++{
++ VIMScroller *scroller = gui_mac_get_scroller(sb);
++
++ gui_mac_msg(MSG_INFO, @"gui_mch_destroy_scrollbar: %s (%ld)",
++ scrollbar_desc(sb), sb->ident);
++
++ sb->enabled = FALSE;
++ gui_mac_update_scrollbar(sb);
++
++ if (scroller != nil)
++ [scroller release];
++
++ sb->scroller = NULL;
++}
++
++void gui_mch_enable_scrollbar(scrollbar_T *sb, int flag)
++{
++ gui_mac_msg(MSG_INFO, @"%s scrollbar: %s (%d)",
++ flag == TRUE ? "enable" : "disable", scrollbar_desc(sb),
++ sb->ident);
++
++ sb->enabled = flag;
++ gui_mac_update_scrollbar(sb);
++
++ VIMScroller *scroller = gui_mac_get_scroller(sb);
++ [scroller setHidden: flag == TRUE ? NO : YES];
++}
++
++void gui_mch_set_scrollbar_pos(
++ scrollbar_T *sb,
++ int x,
++ int y,
++ int w,
++ int h)
++{
++ gui_mac_msg(MSG_INFO, @"set scrollbar pos: %s (%ld), (%d, %d, %d, %d)",
++ scrollbar_desc(sb), sb->ident, x, y, w, h);
++
++ gui_mac_update_scrollbar(sb);
++
++ VIMScroller *scroller = gui_mac_get_scroller(sb);
++ [scroller setFrame: NSMakeRect(x, y, w, h)];
++}
++
++void gui_mch_set_scrollbar_thumb(
++ scrollbar_T *sb,
++ long val,
++ long size,
++ long max)
++{
++ VIMScroller *scroller = (VIMScroller *) sb->scroller;
++ [scroller setThumbValue: val
++ size: size
++ max: max];
++}
++
++/* Scrollbar related }}} */
++
++/* Mouse related {{{ */
++
++void gui_mch_getmouse(int *x, int *y)
++{
++
++}
++
++void gui_mch_setmouse(int x, int y)
++{
++}
++
++/* Mouse related }}} */
++
++/* Cursor blinking stuff {{{ */
++
++enum blink_state {
++ BLINK_NONE, /* not blinking at all */
++ BLINK_OFF, /* blinking, cursor is not shown */
++ BLINK_ON /* blinking, cursor is shown */
++};
++
++void gui_mch_set_blinking(long wait, long on, long off)
++{
++ gui_mac.blink_wait = wait;
++ gui_mac.blink_on = on;
++ gui_mac.blink_off = off;
++}
++
++void gui_mch_stop_blink()
++{
++ return;
++
++ [gui_mac.blink_timer invalidate];
++
++ if (gui_mac.blink_state == BLINK_OFF)
++ gui_update_cursor(TRUE, FALSE);
++
++ gui_mac.blink_state = BLINK_NONE;
++ gui_mac.blink_timer = nil;
++}
++
++void gui_mch_start_blink()
++{
++ return;
++
++ if (gui_mac.blink_timer != nil)
++ [gui_mac.blink_timer invalidate];
++
++ if (gui_mac.blink_wait && gui_mac.blink_on &&
++ gui_mac.blink_off && gui.in_focus)
++ {
++ gui_mac.blink_timer = [NSTimer scheduledTimerWithTimeInterval: gui_mac.blink_wait / 1000.0
++ target: gui_mac.app_delegate
++ selector: @selector(blinkCursorTimer:)
++ userInfo: nil
++ repeats: NO];
++ gui_mac.blink_state = BLINK_ON;
++ gui_update_cursor(TRUE, FALSE);
++ }
++}
++
++/* Cursor blinking stuff }}} */
++
++/* GUI tab stuff {{{ */
++
++void gui_mch_set_curtab(int nr)
++{
++ gui_mac_msg(MSG_INFO, @"gui_mch_set_curtab(%d)", nr);
++}
++
++void gui_mch_show_tabline(int showit)
++{
++ VIMContentView *view;
++
++ gui_mac.showing_tabline = showit;
++
++ gui_mac_msg(MSG_INFO, @"gui_mch_show_tabline: %s", showit ? "YES" : "NO");
++ view = [gui_mac.current_window contentView];
++ [[view tabBarControl] setHidden: (showit ? NO : YES)];
++ // NSShowRect("tabBarControl", [[view tabBarControl] frame]);
++}
++
++int gui_mch_showing_tabline()
++{
++ return gui_mac.showing_tabline == YES;
++}
++
++void gui_mch_update_tabline()
++{
++ tabpage_T *tp;
++ VIMContentView *view = [gui_mac.current_window contentView];
++ NSTabView *tabView = [view tabView];
++ NSArray *tabViewItems = [[view tabBarControl] representedTabViewItems];
++ int i, j, originalTabCount = [tabViewItems count];
++ NSTabViewItem *item;
++ int currentTabIndex = tabpage_index(curtab) - 1;
++
++ gui_mac_msg(MSG_INFO, @"gui_mch_update_tabline: cti = %d, otc = %d",
++ currentTabIndex, originalTabCount);
++
++ for (tp = first_tabpage, i = 0;
++ tp != NULL;
++ tp = tp->tp_next, i++)
++ {
++ // This function puts the label of the tab in the global 'NameBuff'.
++ get_tabline_label(tp, FALSE);
++ char_u *s = NameBuff;
++ int len = STRLEN(s);
++ if (len <= 0) continue;
++
++ s = CONVERT_TO_UTF8(s);
++ // gui_mac_msg(MSG_DEBUG, @"label (%d): %s", i, s);
++ if (i >= originalTabCount)
++ {
++ gui_mac_begin_tab_action();
++ item = [view addNewTabViewItem];
++ gui_mac_end_tab_action();
++ }
++ else
++ item = [tabViewItems objectAtIndex: i];
++
++ [item setLabel: NSStringFromVim(s)];
++
++ CONVERT_TO_UTF8_FREE(s);
++ }
++
++ // gui_mac_msg(MSG_DEBUG, @"total tab count = %d", i);
++ for (j = originalTabCount - 1; j >= i; j--)
++ {
++ NSTabViewItem *item = [tabViewItems objectAtIndex: i];
++ [tabView removeTabViewItem: item];
++ }
++
++ tabViewItems = [[view tabBarControl] representedTabViewItems];
++ if (currentTabIndex < [tabViewItems count])
++ {
++ item = [tabViewItems objectAtIndex: currentTabIndex];
++
++ gui_mac_begin_tab_action();
++ [tabView selectTabViewItem: item];
++ gui_mac_end_tab_action();
++ }
++}
++
++/* GUI tab stuff }}} */
++
++/* GUI popup menu stuff {{{ */
++
++void gui_mch_pum_display(pumitem_T *array, int size, int selected)
++{
++
++}
++
++/* GUI popup menu stuff }}} */
++
++/* Private Functions {{{1 */
++
++int gui_mac_hex_digit(int c)
++{
++ if (isdigit(c))
++ return c - '0';
++
++ c = TOLOWER_ASC(c);
++
++ if (c >= 'a' && c <= 'f')
++ return c - 'a' + 10;
++
++ return -1000;
++}
++
++NSAlertStyle NSAlertStyleFromVim(int type)
++{
++ switch (type)
++ {
++ case VIM_GENERIC:
++ case VIM_INFO:
++ case VIM_QUESTION:
++ return NSInformationalAlertStyle;
++
++ case VIM_WARNING:
++ return NSWarningAlertStyle;
++
++ case VIM_ERROR:
++ return NSCriticalAlertStyle;
++
++ default:
++ return NSInformationalAlertStyle;
++ }
++}
++
++NSColor *NSColorFromGuiColor(guicolor_T color, float alpha)
++{
++ float red, green, blue;
++
++ red = (float) Red(color) / (float) 0xFF;
++ green = (float) Green(color) / (float) 0xFF;
++ blue = (float) Blue(color) / (float) 0xFF;
++
++ return [NSColor colorWithDeviceRed: red
++ green: green
++ blue: blue
++ alpha: alpha];
++}
++
++NSRect NSRectFromVim(int row1, int col1, int row2, int col2)
++{
++ return NSMakeRect(FILL_X(col1), FF_Y(row2 + 1),
++ FILL_X(col2 + 1) - FILL_X(col1),
++ FILL_Y(row2 + 1) - FILL_Y(row1));
++}
++
++void gui_mac_msg(int level, NSString *fmt, ...)
++{
++#if GUI_MAC_DEBUG
++ if (level >= gui_mac.debug_level)
++ {
++ va_list ap;
++
++ va_start(ap, fmt);
++ NSLogv(fmt, ap);
++ va_end(ap);
++ }
++#endif
++}
++
++/* Application Related Utilities {{{2 */
++
++/* Force it to update instantly */
++void gui_mac_update()
++{
++ gui_mac_send_dummy_event();
++ gui_mac_stop_app(YES);
++}
++
++void gui_mac_send_dummy_event()
++{
++ NSEvent *event;
++ event = [NSEvent otherEventWithType: NSApplicationDefined
++ location: NSZeroPoint
++ modifierFlags: 0
++ timestamp: 0
++ windowNumber: 0
++ context: nil
++ subtype: 0
++ data1: 0
++ data2: 0];
++ [NSApp postEvent: event atStart: YES];
++}
++
++unsigned int has_fname(char_u *fname)
++{
++ int i;
++
++ for (i = 0; i < global_alist.al_ga.ga_len; i++)
++ if (STRCMP(AARGLIST(&global_alist)[i].ae_fname, fname) == 0)
++ return 1;
++ return 0;
++}
++
++@implementation VimAppController
++
++- (void) application:(NSApplication *)sender openFiles:(NSArray *)filenames
++{
++ char_u **fnames;
++ unsigned int i, count;
++
++ count = [filenames count];
++ fnames = (char_u **) alloc(count * sizeof(char_u *));
++
++ for (i = 0; i < count; i++)
++ {
++ NSString *filename = [filenames objectAtIndex: i];
++
++ fnames[i] = vim_strsave((char_u *) [filename fileSystemRepresentation]);
++ }
++
++ shorten_filenames(fnames, count);
++
++ /* if vim is starting, we can not use handle_drop, instead, we
++ * put files into global alist, vim will open those files later
++ * at appropriate time */
++ if (starting > 0)
++ {
++ int i;
++ char_u *p;
++
++ /* these are the initial files dropped on the Vim icon */
++ for (i = 0; i < count; i++)
++ {
++ if (has_fname(fnames[i]))
++ continue;
++
++ if (ga_grow(&global_alist.al_ga, 1) == FAIL ||
++ (p = vim_strsave(fnames[i])) == NULL)
++ mch_exit(2);
++ else
++ alist_add(&global_alist, p, 2);
++ }
++
++ /* Change directory to the location of the first file. */
++ if (GARGCOUNT > 0 && vim_chdirfile(alist_name(&GARGLIST[0])) == OK)
++ shorten_fnames(TRUE);
++
++ goto finish;
++ }
++
++ char_u *p = vim_strsave(fnames[0]);
++ handle_drop(count, fnames, FALSE);
++
++ if (p != NULL)
++ {
++ if (mch_isdir(p))
++ {
++ if (mch_chdir((char *)p) == 0)
++ shorten_fnames(TRUE);
++ }
++ else if (vim_chdirfile(p) == OK)
++ shorten_fnames(TRUE);
++
++ vim_free(p);
++ }
++
++ /* Update the screen display */
++ update_screen(NOT_VALID);
++#ifdef FEAT_MENU
++ gui_update_menus(0);
++#endif
++ setcursor();
++ out_flush();
++
++ gui_mac_redraw();
++
++finish:
++ [NSApp replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
++}
++
++- (BOOL) applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
++{
++ return YES;
++}
++
++- (NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication *)sender
++{
++ int reply = NSTerminateNow;
++ BOOL modifiedBuffers = NO;
++
++ buf_T *buf;
++ for (buf = firstbuf; buf != NULL; buf = buf->b_next)
++ {
++ if (bufIsChanged(buf))
++ {
++ modifiedBuffers = YES;
++ break;
++ }
++ }
++
++ if (modifiedBuffers) {
++ NSAlert *alert = [[NSAlert alloc] init];
++ [alert addButtonWithTitle: @"Quit"];
++ [alert addButtonWithTitle: @"Cancel"];
++ [alert setMessageText: @"Quit without saving?"];
++ [alert setInformativeText: @"There are modified buffers, "
++ " if you quit now all changes will be lost. Quit anyway?"];
++ [alert setAlertStyle: NSWarningAlertStyle];
++
++ [alert beginSheetModalForWindow: gui_mac.current_window
++ modalDelegate: gui_mac.app_delegate
++ didEndSelector: @selector(alertDidEnd:returnCode:contextInfo:)
++ contextInfo: NULL];
++ [NSApp run];
++
++ if (gui_mac.dialog_button != 1) {
++ reply = NSTerminateCancel;
++ [gui_mac.current_window makeKeyAndOrderFront: nil];
++ }
++
++ [alert release];
++ }
++
++ return reply;
++}
++
++- (void) applicationDidFinishLaunching:(NSNotification *)aNotification
++{
++}
++
++- (BOOL) windowShouldClose:(id)sender
++{
++ if ([sender isEqual: gui_mac.current_window])
++ {
++ gui_shell_closed();
++ return NO;
++ }
++
++ return YES;
++}
++
++- (void) alertDidEnd:(VIMAlert *)alert returnCode:(int)returnCode contextInfo:(void *)contextInfo
++{
++ gui_mac.dialog_button = returnCode - NSAlertFirstButtonReturn + 1;
++
++ if ([alert isKindOfClass: [VIMAlert class]] &&
++ [alert textField] && contextInfo)
++ STRCPY((char_u *) contextInfo, [[[alert textField] stringValue] UTF8String]);
++
++ [NSApp stop: self];
++}
++
++- (void) panelDidEnd:(NSSavePanel *)panel code:(int)code context:(void *)context
++{
++ NSString *string = (code == NSOKButton) ? [panel filename] : nil;
++ gui_mac.selected_file = [string copy];
++
++ [NSApp stop: self];
++}
++
++- (void) initializeApplicationTimer:(NSTimer *)timer
++{
++ [NSApp stop: self];
++
++ gui_mac_send_dummy_event();
++}
++
++- (void) blinkCursorTimer:(NSTimer *)timer
++{
++ NSTimeInterval on_time, off_time;
++
++ gui_mac_msg(MSG_DEBUG, @"blinkCursorTimer: %s",
++ gui_mac.blink_state == BLINK_ON ? "BLINK_ON"
++ : (gui_mac.blink_state == BLINK_OFF ? "BLINK_OFF"
++ : "BLINK_NONE"));
++
++ [gui_mac.blink_timer invalidate];
++ if (gui_mac.blink_state == BLINK_ON)
++ {
++ gui_undraw_cursor();
++ gui_mac.blink_state = BLINK_OFF;
++
++ off_time = gui_mac.blink_off / 1000.0;
++ gui_mac.blink_timer = [NSTimer scheduledTimerWithTimeInterval: off_time
++ target: gui_mac.app_delegate
++ selector: @selector(blinkCursorTimer:)
++ userInfo: nil
++ repeats: NO];
++ }
++ else if (gui_mac.blink_state == BLINK_OFF)
++ {
++ gui_update_cursor(TRUE, FALSE);
++ gui_mac.blink_state = BLINK_ON;
++
++ on_time = gui_mac.blink_on / 1000.0;
++ gui_mac.blink_timer = [NSTimer scheduledTimerWithTimeInterval: on_time
++ target: gui_mac.app_delegate
++ selector: @selector(blinkCursorTimer:)
++ userInfo: nil
++ repeats: NO];
++ }
++}
++
++- (void) menuAction:(id)sender
++{
++ NSMenuItem *item = (NSMenuItem *) sender;
++ vimmenu_T *menu;
++
++ /* NSMenuItem does not have a specifically
++ * made "user data" to contain vimmenu_T,
++ * so we have to use this trick, cast an
++ * int to a pointer, hopefully in all Macs
++ * they are in the same length */
++ if ((menu = (vimmenu_T *)[item tag]) == NULL)
++ return;
++
++ if (menu->cb != NULL)
++ gui_menu_cb(menu);
++
++ // gui_mac_redraw();
++
++ /* HACK: NSApp won't react directly until some event comes,
++ * while clicking a menu item does not send any event */
++ gui_mac_update();
++}
++
++- (void) applicationWillTerminate:(NSNotification *)aNotification
++{
++ // [gui_mac.app_pool release];
++ mch_exit(0);
++}
++
++- (void) windowWillClose:(NSNotification *)aNotification
++{
++ if ([aNotification object] != [NSFontPanel sharedFontPanel])
++ return;
++
++ NSFont *selected_font = [[NSFontManager sharedFontManager] selectedFont];
++ // gui_mac_msg(MSG_DEBUG, @"font panel will close: %@", selected_font);
++
++ gui_mac.selected_font = selected_font;
++ [NSApp stop: self];
++}
++
++- (void) windowDidResize:(NSNotification *)aNotification
++{
++ NSSize size;
++ int width, height;
++
++ if ([aNotification object] != gui_mac.current_window)
++ return;
++
++ // if the textView is not allocated yet, it means initialization
++ // code from vim is not executed, so we don't need to pass this
++ // windowDidResize event to vim
++ if (! [gui_mac.current_window textView])
++ return;
++
++ size = [[gui_mac.current_window contentView] frame].size;
++ width = (int) size.width;
++ height = (int) size.height;
++
++ // gui_mac_msg(MSG_DEBUG, @"windowDidResize: (%d, %d)", width, height);
++ gui_resize_shell(width, height);
++
++ gui_mac_update();
++}
++
++- (void) windowDidMove:(NSNotification *)notification
++{
++ NSRect frame = [gui_mac.current_window frame];
++ NSPoint topLeft = NSMakePoint(frame.origin.x, NSMaxY(frame));
++ NSString *topLeftString = NSStringFromPoint(topLeft);
++
++ [[NSUserDefaults standardUserDefaults]
++ setObject: topLeftString forKey: @"VIMTopLeftPoint"];
++}
++
++@end
++
++/* Application Related Utilities 2}}} */
++
++/* Menu Related Utilities {{{2 */
++
++void gui_mac_set_application_menu()
++{
++ NSMenu *appleMenu, *services;
++ NSMenuItem *menuItem;
++ NSString *title;
++ NSString *appName;
++
++ appName = @"Vim";
++ appleMenu = [[NSMenu alloc] initWithTitle: @""];
++
++ /* Add menu items */
++ title = [@"About " stringByAppendingString: appName];
++ [appleMenu addItemWithTitle: title
++ action: @selector(orderFrontStandardAboutPanel:)
++ keyEquivalent: @""];
++
++ [appleMenu addItem:[NSMenuItem separatorItem]];
++
++ // Services Menu
++ services = [[[NSMenu alloc] init] autorelease];
++ [appleMenu addItemWithTitle: @"Services"
++ action: nil
++ keyEquivalent: @""];
++ [appleMenu setSubmenu: services forItem: [appleMenu itemWithTitle: @"Services"]];
++
++ // Hide AppName
++ title = [@"Hide " stringByAppendingString:appName];
++ [appleMenu addItemWithTitle: title action: @selector(hide:) keyEquivalent: @"h"];
++
++ // Hide Others
++ menuItem = (NSMenuItem *)[appleMenu addItemWithTitle: @"Hide Others"
++ action: @selector(hideOtherApplications:)
++ keyEquivalent: @"h"];
++ [menuItem setKeyEquivalentModifierMask: (NSAlternateKeyMask | NSCommandKeyMask)];
++
++ // Show All
++ [appleMenu addItemWithTitle: @"Show All"
++ action: @selector(unhideAllApplications:)
++ keyEquivalent: @""];
++
++ [appleMenu addItem: [NSMenuItem separatorItem]];
++
++ // Quit AppName
++ title = [@"Quit " stringByAppendingString: appName];
++ [appleMenu addItemWithTitle: title
++ action: @selector(terminate:)
++ keyEquivalent: @"q"];
++
++ /* Put menu into the menubar */
++ menuItem = [[NSMenuItem alloc] initWithTitle: @""
++ action: nil
++ keyEquivalent: @""];
++ [menuItem setSubmenu: appleMenu];
++ [[NSApp mainMenu] addItem: menuItem];
++
++ /* Tell the application object that this is now the application menu */
++ [NSApp setAppleMenu: appleMenu];
++ [NSApp setServicesMenu: services];
++
++ /* Finally give up our references to the objects */
++ [appleMenu release];
++ [menuItem release];
++}
++
++/* Menu Related Utilities 2}}} */
++
++/* Window related Utilities {{{2 */
++
++int gui_mac_create_window(NSRect rect)
++{
++ VIMWindow *window;
++
++ window = [[VIMWindow alloc] initWithContentRect: rect];
++ gui_mac.current_window = window;
++
++ [NSApp activateIgnoringOtherApps: YES];
++
++ return OK;
++}
++
++NSWindow *gui_mac_get_window(NSRect rect)
++{
++ if (gui_mac.current_window == nil)
++ gui_mac_create_window(rect);
++
++ return gui_mac.current_window;
++}
++
++void gui_mac_open_window()
++{
++ NSWindow *window = gui_mac.current_window;
++ NSPoint topLeft = NSZeroPoint;
++
++ NSString *topLeftString =
++ [[NSUserDefaults standardUserDefaults] stringForKey: @"VIMTopLeftPoint"];
++ if (topLeftString)
++ topLeft = NSPointFromString(topLeftString);
++
++ if (NSEqualPoints(topLeft, NSZeroPoint))
++ [window center];
++ else
++ [window setFrameTopLeftPoint: topLeft];
++
++ [window makeKeyAndOrderFront: nil];
++ gui_mac.window_opened = YES;
++}
++
++/* Window related Utilities 2}}} */
++
++/* View related Utilities 2{{{ */
++
++@implementation VIMContentView
++
++- (id) initWithFrame:(NSRect)rect
++{
++ if ([super initWithFrame: rect])
++ {
++ // NSShowRect("VIMContentView initWithFrame", rect);
++ tabView = [[NSTabView alloc] initWithFrame:NSZeroRect];
++ NSRect tabFrame = NSMakeRect(0, 0,
++ rect.size.width, gui.tabline_height);
++ tabBarControl = [[PSMTabBarControl alloc] initWithFrame: tabFrame];
++ [tabView setDelegate: tabBarControl];
++
++ [tabBarControl setTabView: tabView];
++ [tabBarControl setDelegate: self];
++ [tabBarControl setHidden: YES];
++
++ [tabBarControl setCellMinWidth: 64];
++ [tabBarControl setCellMaxWidth: 64 * 6];
++ [tabBarControl setCellOptimumWidth: 132];
++
++ [tabBarControl setAutoresizingMask: NSViewWidthSizable | NSViewMaxYMargin];
++
++ [tabBarControl awakeFromNib];
++ [self addSubview: tabBarControl];
++ }
++
++ return self;
++}
++
++- (void) dealloc
++{
++ [tabBarControl release];
++ [tabView release];
++
++ [super dealloc];
++}
++
++- (PSMTabBarControl *) tabBarControl
++{
++ return tabBarControl;
++}
++
++- (NSTabView *) tabView
++{
++ return tabView;
++}
++
++- (NSTabViewItem *) addNewTabViewItem
++{
++ NSTabViewItem *item = [[NSTabViewItem alloc] initWithIdentifier: nil];
++ [tabView addTabViewItem: item];
++ [item release];
++ return item;
++}
++
++- (BOOL) isFlipped
++{
++ return YES;
++}
++
++- (void) drawRect:(NSRect)rect
++{
++ [[NSColor whiteColor] set];
++ NSRectFill(rect);
++}
++
++/* PSMTabBarControl delegate {{{2 */
++
++- (BOOL) tabView: (NSTabView *) theTabView
++shouldSelectTabViewItem: (NSTabViewItem *) tabViewItem
++{
++ gui_mac_msg(MSG_INFO, @"tabView:shouldSelectTabViewItem: %@, %s",
++ tabViewItem, gui_mac.selecting_tab == YES ? "YES" : "NO");
++
++ if (gui_mac.selecting_tab == NO)
++ {
++ NSArray *tabViewItems = [tabBarControl representedTabViewItems];
++ int idx = [tabViewItems indexOfObject: tabViewItem] + 1;
++
++ send_tabline_event(idx);
++ gui_mac_update();
++ }
++
++ return gui_mac.selecting_tab;
++}
++
++- (BOOL) tabView: (NSTabView *) theTabView
++shouldCloseTabViewItem: (NSTabViewItem *) tabViewItem
++{
++ NSArray *tabViewItems = [tabBarControl representedTabViewItems];
++ int idx = [tabViewItems indexOfObject: tabViewItem] + 1;
++
++ send_tabline_menu_event(idx, TABLINE_MENU_CLOSE);
++ gui_mac_update();
++
++ return NO;
++}
++
++- (void) tabView: (NSTabView *) theTabView
++didDragTabViewItem: (NSTabViewItem *) tabViewItem
++ toIndex: (int) idx
++{
++ gui_mac_msg(MSG_INFO, @"tabView:didDragTabViewItem: %@ toIndex: %d",
++ tabViewItem, idx);
++ tabpage_move(idx);
++ gui_mac_update();
++}
++
++/* PSMTabBarControl delegate 2}}} */
++
++@end
++
++@implementation VIMTextView
++
++- (id) initWithFrame:(NSRect)rect
++{
++ if ((self = [super initWithFrame: rect])) {
++ markedText = nil;
++ markedTextAttributes = [[NSMutableDictionary dictionaryWithObjectsAndKeys:
++ [NSNumber numberWithInt: (NSUnderlineStyleSingle |
++ NSUnderlinePatternSolid)],
++ NSUnderlineStyleAttributeName,
++ nil] retain];
++
++ [self registerForDraggedTypes: [NSArray arrayWithObjects:
++ NSFilenamesPboardType, NSStringPboardType, nil]];
++
++ if (! NSEqualRects(rect, NSZeroRect))
++ {
++ contentImage = [[NSImage alloc] initWithSize: rect.size];
++ gui_mac.main_height = rect.size.height;
++ }
++
++ else contentImage = nil;
++ }
++
++ return self;
++}
++
++- (void) synchronizeContentImage
++{
++ NSSize size = [self frame].size;
++
++ if (! NSEqualSizes([contentImage size], size))
++ {
++ gui_mac_msg(MSG_INFO, @"REALLOCATE content image to: (%g, %g)",
++ size.width, size.height);
++ [contentImage release];
++ contentImage = [[NSImage alloc] initWithSize: size];
++ gui_mac.main_height = size.height;
++ }
++}
++
++- (void) viewWillStartLiveResize
++{
++ lastSetTitle = [[gui_mac.current_window title] retain];
++ [super viewWillStartLiveResize];
++}
++
++- (void) viewDidEndLiveResize
++{
++ [gui_mac.current_window setTitle: lastSetTitle];
++ [lastSetTitle release];
++ lastSetTitle = nil;
++
++ [super viewDidEndLiveResize];
++}
++
++- (void) dealloc
++{
++ [markedTextAttributes release];
++ [markedText release];
++ [contentImage release];
++ [lastSetTitle release];
++
++ [super dealloc];
++}
++
++- (void) beginDrawing
++{
++ [contentImage lockFocus];
++}
++
++- (void) endDrawing
++{
++ [contentImage unlockFocus];
++}
++
++- (void) clearAll
++{
++ gui_mch_set_bg_color(gui.back_pixel);
++
++ [contentImage lockFocus];
++
++ [gui_mac.bg_color set];
++ NSRectFill([self bounds]);
++
++ [contentImage unlockFocus];
++}
++
++- (NSAttributedString *) markedText
++{
++ return markedText;
++}
++
++- (void) setMarkedTextAttribute:(id)value forKey:(NSString *)key
++{
++ [markedTextAttributes setObject: value
++ forKey: key];
++}
++
++- (BOOL) isOpaque
++{
++ return YES;
++}
++
++- (BOOL) hasMarkedText
++{
++ return markedRange.length > 0 ? YES : NO;
++}
++
++- (NSRange) markedRange
++{
++ return markedRange;
++}
++
++- (NSRange) selectedRange
++{
++ return NSMakeRange(NSNotFound, 0);
++}
++
++- (void) setMarkedText:(id)aString selectedRange:(NSRange)selRange
++{
++ // gui_mac_msg(MSG_DEBUG, @"setMarkedText: %@ (%u, %u)", aString,
++ // selRange.location, selRange.length);
++
++ markedRange = NSMakeRange(0, [aString length]);
++
++ [markedText release];
++ if ([aString isKindOfClass: [NSAttributedString class]])
++ markedText = [[NSAttributedString alloc] initWithString: [aString string]
++ attributes: markedTextAttributes];
++ else
++ markedText = [[NSAttributedString alloc] initWithString: aString
++ attributes: markedTextAttributes];
++
++ if (markedRange.length > 0)
++ {
++ } else
++ {
++ // gui_mac_msg(MSG_DEBUG, @"clear markedText");
++ gui_update_cursor(TRUE, FALSE);
++ }
++
++ gui_mac_redraw();
++}
++
++- (void) unmarkText
++{
++ markedRange = NSMakeRange(NSNotFound, 0);
++
++ // gui_mac_msg(MSG_DEBUG, @"unmarkText");
++}
++
++- (NSArray *) validAttributesForMarkedText
++{
++ return nil;
++}
++
++- (NSAttributedString *) attributedSubstringFromRange:(NSRange)theRange
++{
++ return nil;
++}
++
++- (unsigned int) characterIndexForPoint:(NSPoint)thePoint
++{
++ // gui_mac_msg(MSG_DEBUG, @"characterIndexForPoint: x = %g, y = %g", thePoint.x, thePoint.y);
++ return NSNotFound;
++}
++
++- (NSRect) firstRectForCharacterRange:(NSRange)theRange
++{
++ NSRect rect = NSMakeRect(FILL_X(gui_mac.im_col),
++ FILL_Y(gui_mac.im_row + 1),
++ theRange.length * gui.char_width,
++ gui.char_height);
++
++ rect.origin = FLIPPED_POINT(self, rect.origin);
++ rect.origin = [[self window] convertBaseToScreen:
++ [self convertPoint: rect.origin toView: nil]];
++
++ return rect;
++}
++
++- (NSInteger) conversationIdentifier
++{
++ return (NSInteger) self;
++}
++
++- (void) doCommandBySelector:(SEL)aSelector
++{
++
++}
++
++#define INLINE_KEY_BUFFER_SIZE 256
++#define add_to_key_buffer(buf, len, k1, k2, k3) { buf[len++] = k1; buf[len++] = k2; buf[len++] = k3; }
++
++- (void) insertText:(id)aString
++{
++ char_u *to;
++ unichar *text;
++ int i;
++ size_t u16_len, enc_len, result_len = 0;
++ char_u result[INLINE_KEY_BUFFER_SIZE];
++
++ // gui_mac_msg(MSG_DEBUG, @"insertText: %@", aString);
++
++ u16_len = [aString length] * 2;
++ text = (unichar *) alloc(u16_len);
++ if (! text)
++ return;
++
++ [aString getCharacters: text];
++ to = mac_utf16_to_enc(text, u16_len, &enc_len);
++
++ if (! to)
++ return;
++
++ /* This is basically add_to_input_buf_csi() */
++ for (i = 0; i < enc_len && result_len < (INLINE_KEY_BUFFER_SIZE - 1); ++i)
++ {
++ result[result_len++] = to[i];
++ if (to[i] == CSI)
++ {
++ result[result_len++] = KS_EXTRA;
++ result[result_len++] = (int)KE_CSI;
++ }
++ }
++ vim_free(to);
++
++ /* clear marked text */
++ markedRange = NSMakeRange(NSNotFound, 0);
++ [markedText release];
++ markedText = nil;
++
++ if (result_len > 0)
++ {
++ add_to_input_buf(result, result_len);
++ gui_mac_stop_app(YES);
++ }
++}
++
++#define LIGHT_WEIGHT_LIVE_RESIZE 0
++
++- (void) drawRect:(NSRect)rect
++{
++#if 0
++ gui_mac_msg(MSG_INFO, @"drawRect: (%f, %f), (%f, %f)",
++ rect.origin.x, rect.origin.y,
++ rect.size.width, rect.size.height);
++#endif
++#if LIGHTWEIDHT_LIVE_RESIZE
++ if ([self inLiveResize])
++ {
++ NSFont *font;
++ NSString *size_desc;
++ NSDictionary *attrib;
++
++ [NSColorFromGuiColor(gui.back_pixel, VIM_BG_ALPHA) set];
++ [NSBezierPath fillRect: rect];
++
++ font = [NSFont boldSystemFontOfSize: 48.0];
++
++ size_desc = [NSString stringWithFormat: @"%d x %d (%d x %d)",
++ (int) rect.size.width,
++ (int) rect.size.height,
++ (int) rect.size.width / gui.char_width,
++ (int) rect.size.height / gui.char_height];
++ attrib = [NSDictionary dictionaryWithObjectsAndKeys:
++ [NSColor whiteColor], NSForegroundColorAttributeName,
++ font, NSFontAttributeName, nil];
++
++ NSSize desc_size = [size_desc sizeWithAttributes: attrib];
++
++ [size_desc drawAtPoint: NSMakePoint(rect.size.width / 2 - desc_size.width / 2,
++ rect.size.height / 2 - desc_size.height / 2)
++ withAttributes: attrib];
++ return;
++ }
++ else
++ {
++#endif
++ [contentImage compositeToPoint: rect.origin
++ fromRect: rect
++ operation: NSCompositeCopy];
++
++ if ([self hasMarkedText])
++ {
++ // gui_mac_msg(MSG_DEBUG, @"redraw: %@", markedText);
++ NSPoint cursorPoint = NSMakePoint(FILL_X(gui_mac.im_col), FILL_Y(gui_mac.im_row + 1));
++ [markedText drawAtPoint: FLIPPED_POINT(self, cursorPoint)];
++ }
++#if LIGHTWEIDHT_LIVE_RESIZE
++ }
++#endif
++}
++
++- (BOOL) wantsDefaultClipping
++{
++ return NO;
++}
++
++- (BOOL) isFlipped
++{
++ return NO;
++}
++
++- (BOOL) acceptsFirstResponder
++{
++ return YES;
++}
++
++- (void) scrollWheel:(NSEvent *)event
++{
++ if ([event deltaY] == 0)
++ return;
++
++ [self mouseAction: [event deltaY] > 0 ? MOUSE_4 : MOUSE_5
++ repeated: NO
++ event: event];
++}
++
++- (void) mouseAction:(int)button repeated:(bool)repeated event:(NSEvent *)event
++{
++ NSPoint point = [self convertPoint: [event locationInWindow]
++ fromView: nil];
++
++ point = FLIPPED_POINT(self, point);
++
++ int flags = gui_mac_mouse_modifiers_to_vim([event modifierFlags]);
++ gui_send_mouse_event(button, point.x, point.y, repeated, flags);
++ gui_mac_stop_app(YES);
++}
++
++- (void) mouseDown:(NSEvent *)event
++{
++ int button = gui_mac_mouse_button_to_vim([event buttonNumber]);
++
++ gui_mac.last_mouse_down_event = [event copy];
++
++ // gui_mac_msg(MSG_DEBUG, @"mouseDown: %s",
++ // button == MOUSE_LEFT ? "MOUSE_LEFT" : "MOUSE_RIGHT");
++
++ [self mouseAction: button
++ repeated: [event clickCount] != 0
++ event: event];
++}
++
++- (void) rightMouseDown:(NSEvent *)event
++{
++ [self mouseDown: event];
++}
++
++- (void) otherMouseDown:(NSEvent *)event
++{
++ [self mouseDown: event];
++}
++
++- (void) mouseUp:(NSEvent *)event
++{
++ [self mouseAction: MOUSE_RELEASE
++ repeated: NO
++ event: event];
++}
++
++- (void) rightMouseUp:(NSEvent *)event
++{
++ [self mouseUp: event];
++}
++
++- (void) otherMouseUp:(NSEvent *)event
++{
++ [self mouseUp: event];
++}
++
++- (void) mouseDragged:(NSEvent *)event
++{
++ [self mouseAction: MOUSE_DRAG
++ repeated: NO
++ event: event];
++}
++
++- (void) rightMouseDragged:(NSEvent *)event
++{
++ [self mouseDragged: event];
++}
++
++- (void) otherMouseDragged:(NSEvent *)event
++{
++ [self mouseDragged: event];
++}
++
++- (NSDragOperation) draggingEntered:(id <NSDraggingInfo>)sender
++{
++ NSDragOperation sourceDragMask = [sender draggingSourceOperationMask];
++ NSPasteboard *pboard = [sender draggingPasteboard];
++
++ if (([[pboard types] containsObject: NSFilenamesPboardType] ||
++ [[pboard types] containsObject: NSStringPboardType]) &&
++ (sourceDragMask & NSDragOperationCopy))
++ return NSDragOperationCopy;
++
++ return NSDragOperationNone;
++}
++
++- (NSDragOperation) draggingUpdated:(id <NSDraggingInfo>)sender
++{
++ return [self draggingEntered: sender];
++}
++
++- (BOOL) performDragOperation:(id <NSDraggingInfo>)sender
++{
++ NSPasteboard *pboard = [sender draggingPasteboard];
++
++ if ([[pboard types] containsObject: NSFilenamesPboardType])
++ {
++ NSArray *files = [pboard propertyListForType: NSFilenamesPboardType];
++ int i, count = [files count];
++ NSPoint point = [self convertPoint: [sender draggingLocation]
++ fromView: nil];
++
++ point = FLIPPED_POINT(self, point);
++
++ char_u **fnames = (char_u **) alloc(count * sizeof(char_u *));
++ for (i = 0; i < count; ++i)
++ {
++ NSString *file = [files objectAtIndex: i];
++
++ fnames[i] = vim_strsave((char_u *)[file fileSystemRepresentation]);
++ }
++
++ gui_handle_drop(point.x, point.y, 0, fnames, count);
++ gui_mac_update();
++ return YES;
++ }
++
++ else if ([[pboard types] containsObject: NSStringPboardType])
++ {
++#ifdef FEAT_DND
++ NSString *dragString = [pboard stringForType: NSStringPboardType];
++ char_u dropkey[3] = { CSI, KS_EXTRA, (char_u) KE_DROP };
++
++ NSMutableString *string = [NSMutableString stringWithString: dragString];
++
++ // Replace unrecognized end-of-line sequences with \x0a (line feed).
++ NSRange range = NSMakeRange(0, [string length]);
++ unsigned n = [string replaceOccurrencesOfString: @"\x0d\x0a"
++ withString: @"\x0a"
++ options: 0
++ range: range];
++ if (n == 0)
++ [string replaceOccurrencesOfString: @"\x0d"
++ withString: @"\x0a"
++ options: 0
++ range: range];
++
++ dnd_yank_drag_data((char_u *)[string UTF8String],
++ [string lengthOfBytesUsingEncoding: NSUTF8StringEncoding]);
++ add_to_input_buf(dropkey, sizeof(dropkey));
++
++ gui_mac_redraw();
++ gui_mac_update();
++#endif
++ return YES;
++ }
++
++ return NO;
++}
++
++- (BOOL) performKeyEquivalent:(NSEvent *)event
++{
++ // Called for Cmd+key keystrokes, function keys, arrow keys, page
++ // up/down, home, end.
++ if ([event type] != NSKeyDown)
++ return NO;
++
++ // HACK! Let the main menu try to handle any key down event, before
++ // passing it on to vim, otherwise key equivalents for menus will
++ // effectively be disabled.
++ if ([[NSApp mainMenu] performKeyEquivalent: event])
++ return YES;
++
++ // HACK! KeyCode 50 represent the key which switches between windows
++ // within an application (like Cmd+Tab is used to switch between
++ // applications). Return NO here, else the window switching does not work.
++ //
++ // Will this hack work for all languages / keyboard layouts?
++ if ([event keyCode] == 50)
++ return NO;
++
++ if ([event modifierFlags] & NSCommandKeyMask)
++ {
++ [self keyDown: event];
++ return YES;
++ }
++
++ return NO;
++}
++
++- (void) keyDown:(NSEvent *)event
++{
++ UniChar modified_char, original_char;
++ unsigned int mac_modifiers, vim_modifiers;
++ char_u result[INLINE_KEY_BUFFER_SIZE];
++ int len = 0;
++ int vim_key_char;
++
++ [NSCursor setHiddenUntilMouseMoves: YES];
++
++ /* get key code and modifier flags from event */
++ mac_modifiers = [event modifierFlags];
++
++ /* convert NS* style modifier flags to vim style */
++ vim_modifiers = gui_mac_key_modifiers_to_vim(mac_modifiers);
++
++ // gui_mac_msg(MSG_DEBUG, @"keyDown: characters = %d", [[event characters] length]);
++
++ if ([[event characters] length] == 1)
++ {
++ modified_char = [[event characters] characterAtIndex: 0];
++ original_char = [[event charactersIgnoringModifiers] characterAtIndex: 0];
++
++ /* Intercept CMD-. and CTRL-c */
++ if ((modified_char == Ctrl_C && ctrl_c_interrupts) ||
++ (modified_char == intr_char && intr_char != Ctrl_C))
++ {
++ trash_input_buf();
++ got_int = TRUE;
++ }
++
++ // gui_mac_msg(MSG_DEBUG, @"original_char %d, modified_char: %d",
++ // original_char, modified_char);
++
++ vim_key_char = gui_mac_function_key_to_vim(original_char, vim_modifiers);
++ // gui_mac_msg(MSG_DEBUG, @"vim_key_char: %d", vim_key_char);
++
++ switch (vim_modifiers)
++ {
++ case MOD_MASK_ALT:
++ case MOD_MASK_SHIFT:
++ if (vim_key_char == 0)
++ goto insert_text;
++ break;
++
++ default:
++ if (vim_modifiers & MOD_MASK_CTRL)
++ {
++ result[len++] = modified_char;
++ add_to_input_buf(result, len);
++ // gui_mac_msg(MSG_DEBUG, @"CTRL-%c, add_to_input_buf: %d", original_char, len);
++
++ gui_mac_stop_app(YES);
++ return;
++ }
++ }
++
++ /* if it's normal key, not special one, then Shift is already applied */
++ if (vim_key_char == 0 ||
++ ! (vim_key_char == ' ' ||
++ vim_key_char == 0xa0 ||
++ (vim_modifiers & MOD_MASK_CMD) ||
++ vim_key_char == 0x9 ||
++ vim_key_char == 0xd ||
++ vim_key_char == ESC))
++ vim_modifiers &= ~MOD_MASK_SHIFT;
++
++ if (vim_modifiers)
++ {
++ add_to_key_buffer(result, len, CSI, KS_MODIFIER, vim_modifiers);
++
++ // gui_mac_msg(MSG_DEBUG, "vim_modifiers: ");
++ // print_vim_modifiers(vim_modifiers);
++ }
++
++ if (IS_SPECIAL(vim_key_char) || vim_key_char > 0)
++ {
++ if ([self hasMarkedText])
++ goto insert_text;
++
++ /* must be enter, esc, backspace, tab, add to input buffer directly */
++ if (vim_key_char > 0)
++ result[len++] = vim_key_char;
++
++ else
++ add_to_key_buffer(result, len, CSI,
++ K_SECOND(vim_key_char),
++ K_THIRD(vim_key_char));
++
++ // gui_mac_msg(MSG_DEBUG, @"IS_SPECIAL, add_to_input_buf: %d", len);
++ }
++
++ /* now here are normal characters */
++ else if (vim_modifiers)
++ {
++ result[len++] = original_char;
++ // gui_mac_msg(MSG_DEBUG, @"original_char %c, add_to_input_buf: %d",
++ // original_char, len);
++ }
++
++ if (len > 0)
++ {
++ add_to_input_buf(result, len);
++ gui_mac_stop_app(YES);
++ return;
++ }
++ }
++
++insert_text:
++ [self interpretKeyEvents: [NSArray arrayWithObject: event]];
++}
++
++@end
++
++/* View related Utilities 2}}} */
++
++/* Drawing related Utilities {{{2 */
++
++void gui_mac_scroll_rect(NSRect rect, int lines)
++{
++ NSPoint dest_point = rect.origin;
++ dest_point.y -= lines * gui.char_height;
++
++ gui_mac_begin_drawing();
++ NSCopyBits(0, rect, dest_point);
++ gui_mac_end_drawing();
++}
++
++void gui_mac_redraw()
++{
++ [currentView setNeedsDisplay: YES];
++}
++
++/* Drawing related Utilities 2}}} */
++
++/* Keyboard Related Utilities 2{{{ */
++
++int gui_mac_function_key_to_vim(UniChar key_char, unsigned int vim_modifiers)
++{
++ int i;
++
++ for (i = 0; function_key_mapping[i].function_key != 0; i++)
++ if (key_char == function_key_mapping[i].function_key)
++ return simplify_key(function_key_mapping[i].vim_key,
++ (int *) &vim_modifiers);
++
++ return 0;
++}
++
++unsigned int gui_mac_key_modifiers_to_vim(unsigned int mac_modifiers)
++{
++ unsigned int vim_modifiers = 0;
++
++ if (mac_modifiers & NSShiftKeyMask)
++ vim_modifiers |= MOD_MASK_SHIFT;
++ if (mac_modifiers & NSControlKeyMask)
++ vim_modifiers |= MOD_MASK_CTRL;
++ if (mac_modifiers & NSAlternateKeyMask)
++ vim_modifiers |= MOD_MASK_ALT;
++ if (mac_modifiers & NSCommandKeyMask)
++ vim_modifiers |= MOD_MASK_CMD;
++
++ return vim_modifiers;
++}
++
++void print_vim_modifiers(unsigned int vim_modifiers)
++{
++ if (vim_modifiers & MOD_MASK_SHIFT)
++ fprintf(stderr, "SHIFT-");
++
++ if (vim_modifiers & MOD_MASK_CMD)
++ fprintf(stderr, "CMD-");
++
++ if (vim_modifiers & MOD_MASK_ALT)
++ fprintf(stderr, "ALT-");
++
++ if (vim_modifiers & MOD_MASK_CTRL)
++ fprintf(stderr, "CTRL-");
++}
++
++unsigned int gui_mac_mouse_modifiers_to_vim(unsigned int mac_modifiers)
++{
++ unsigned int vim_modifiers = 0;
++
++ if (mac_modifiers & NSShiftKeyMask)
++ vim_modifiers |= MOUSE_SHIFT;
++ if (mac_modifiers & NSControlKeyMask)
++ vim_modifiers |= MOUSE_CTRL;
++ if (mac_modifiers & NSAlternateKeyMask)
++ vim_modifiers |= MOUSE_ALT;
++
++ return vim_modifiers;
++}
++
++int gui_mac_mouse_button_to_vim(int mac_button)
++{
++ static int vim_buttons[] = { MOUSE_LEFT, MOUSE_RIGHT,
++ MOUSE_MIDDLE, MOUSE_X1,
++ MOUSE_X2 };
++
++ return vim_buttons[mac_button < 5 ? mac_button : 0];
++}
++
++/* Keyboard Related Utilities 2}}} */
++
++/* Font Related Utilities 2{{{ */
++
++NSFont *gui_mac_get_font(char_u *font_name, int size)
++{
++ // gui_mac_msg(MSG_DEBUG, @"get_font: %s", font_name);
++ NSString *mac_font_name = NSStringFromVim(font_name);
++
++ // gui_mac_msg(MSG_DEBUG, @"fontWithName: %@, %d", mac_font_name, size);
++
++ return [NSFont fontWithName: mac_font_name
++ size: size];
++}
++
++GuiFont gui_mac_find_font(char_u *font_spec)
++{
++ int len = 0, size = VIM_DEFAULT_FONT_SIZE;
++ NSFont *font;
++ char_u *font_style, *p;
++ char_u font_name[VIM_MAX_FONT_NAME_LEN];
++
++ // gui_mac_msg(MSG_DEBUG, @"find_font: %s", font_spec);
++
++ font_style = vim_strchr(font_spec, ':');
++ len = font_style - font_spec;
++
++ if (len < 0 || len >= VIM_MAX_FONT_NAME_LEN)
++ return NOFONT;
++
++ vim_strncpy(font_name, font_spec, len);
++ font_name[len] = '\0';
++
++ if (*font_style == ':')
++ {
++ p = font_style + 1;
++ /* Set the values found after ':' */
++ while (*p)
++ {
++ switch (*p++)
++ {
++ case 'h':
++ size = gui_mac_points_to_pixels(p, &p);
++ break;
++ /*
++ * TODO: Maybe accept width and styles
++ */
++ }
++
++ while (*p == ':')
++ p++;
++ }
++ }
++
++ font = gui_mac_get_font(font_name, size);
++ if (font == nil)
++ {
++ /*
++ * Try again, this time replacing underscores in the font name
++ * with spaces (:set guifont allows the two to be used
++ * interchangeably; the Font Manager doesn't).
++ */
++ int i, changed = FALSE;
++
++ for (i = font_name[0]; i > 0; --i)
++ {
++ if (font_name[i] == '_')
++ {
++ font_name[i] = ' ';
++ changed = TRUE;
++ }
++ }
++
++ if (changed)
++ font = gui_mac_get_font(font_name, size);
++ }
++
++ if (font == nil)
++ return NOFONT;
++
++ [font retain];
++ return (long_u) font;
++}
++
++int gui_mac_points_to_pixels(char_u *str, char_u **end)
++{
++ int pixels;
++ int points = 0;
++ int divisor = 0;
++
++ while (*str)
++ {
++ if (*str == '.' && divisor == 0)
++ {
++ /* Start keeping a divisor, for later */
++ divisor = 1;
++ continue;
++ }
++
++ if (! isdigit(*str))
++ break;
++
++ points *= 10;
++ points += *str - '0';
++ divisor *= 10;
++
++ ++str;
++ }
++
++ if (divisor == 0)
++ divisor = 1;
++
++ pixels = points / divisor;
++ *end = str;
++ return pixels;
++}
++
++GuiFont gui_mac_create_related_font(GuiFont font, bool italic, bool bold)
++{
++ CTFontSymbolicTraits traitMask;
++
++ traitMask = italic ? kCTFontItalicTrait : 0;
++ traitMask |= bold ? kCTFontBoldTrait : 0;
++
++ return (GuiFont) CTFontCreateCopyWithSymbolicTraits((CTFontRef) font,
++ 0.0, NULL,
++ traitMask, traitMask);
++}
++
++/* Font Related Utilities 2}}} */
++
++/* Dialog Related Utilities {{{2 */
++
++int gui_mac_select_from_font_panel(char_u *font_name)
++{
++ char fontSizeString[VIM_MAX_FONT_NAME_LEN];
++ NSFontPanel *fontPanel = [NSFontPanel sharedFontPanel];
++
++ if (gui_mac.current_font)
++ [[NSFontManager sharedFontManager] setSelectedFont: gui_mac.current_font
++ isMultiple: NO];;
++
++ [fontPanel setDelegate: gui_mac.app_delegate];
++ [fontPanel orderFront: nil];
++
++ gui_mac.selected_font = nil;
++ [NSApp run];
++ if (! gui_mac.selected_font)
++ return FAIL;
++
++ STRCPY(font_name, [[gui_mac.selected_font fontName] UTF8String]);
++ STRCAT(font_name, ":h");
++ sprintf(fontSizeString, "%d", (int) [gui_mac.selected_font pointSize]);
++ STRCAT(font_name, fontSizeString);
++
++ return OK;
++}
++
++@implementation VIMAlert
++
++- (void) dealloc
++{
++ [textField release];
++ [super dealloc];
++}
++
++- (void) setTextFieldString: (NSString *)textFieldString
++{
++ [textField release];
++ textField = [[NSTextField alloc] init];
++ [textField setStringValue: textFieldString];
++}
++
++- (NSTextField *) textField
++{
++ return textField;
++}
++
++- (void) setInformativeText:(NSString *)text
++{
++ if (textField)
++ {
++ // HACK! Add some space for the text field.
++ [super setInformativeText: [text stringByAppendingString: @"\n\n\n"]];
++ } else
++ {
++ [super setInformativeText: text];
++ }
++}
++
++- (void) beginSheetModalForWindow:(NSWindow *)window
++ modalDelegate:(id)delegate
++ didEndSelector:(SEL)didEndSelector
++ contextInfo:(void *)contextInfo
++{
++ [super beginSheetModalForWindow: window
++ modalDelegate: delegate
++ didEndSelector: didEndSelector
++ contextInfo: contextInfo];
++
++ // HACK! Place the input text field at the bottom of the informative text
++ // (which has been made a bit larger by adding newline characters).
++ NSView *contentView = [[self window] contentView];
++ NSRect rect = [contentView frame];
++ rect.origin.y = rect.size.height;
++
++ NSArray *subviews = [contentView subviews];
++ unsigned i, count = [subviews count];
++ for (i = 0; i < count; ++i)
++ {
++ NSView *view = [subviews objectAtIndex: i];
++
++ if ([view isKindOfClass: [NSTextField class]] &&
++ [view frame].origin.y < rect.origin.y) {
++ // NOTE: The informative text field is the lowest NSTextField in
++ // the alert dialog.
++ rect = [view frame];
++ }
++ }
++
++ rect.size.height = VIMAlertTextFieldHeight;
++ [textField setFrame: rect];
++ [contentView addSubview: textField];
++ [textField becomeFirstResponder];
++}
++
++@end
++
++/* Dialog Related Utilities 2}}} */
++
++/* Scroll Bar Related Utilities {{{2 */
++
++@implementation VIMScroller
++
++- (id)initWithVimScrollbar:(scrollbar_T *)scrollBar
++ orientation:(int)orientation
++{
++ unsigned int mask = 0;
++ NSRect frame = orientation == SBAR_HORIZ ? NSMakeRect(0, 0, 1, 0)
++ : NSMakeRect(0, 0, 0, 1);
++
++ if ((self = [super initWithFrame: frame]))
++ {
++ vimScrollBar = scrollBar;
++
++ [self setEnabled: YES];
++ [self setAction: @selector(scroll:)];
++ [self setTarget: self];
++
++ switch (vimScrollBar->type)
++ {
++ case SBAR_LEFT:
++ mask = NSViewHeightSizable | NSViewMaxXMargin;
++ break;
++
++ case SBAR_RIGHT:
++ mask = NSViewHeightSizable | NSViewMinXMargin;
++ break;
++
++ case SBAR_BOTTOM:
++ mask = NSViewWidthSizable | NSViewMaxYMargin;
++ break;
++ }
++
++ [self setAutoresizingMask: mask];
++ }
++
++ return self;
++}
++
++- (void) scroll:(id)sender
++{
++ scrollbar_T *sb = [sender vimScrollBar];
++ int hitPart = [sender hitPart];
++ float fval = [sender floatValue];
++
++ if (sb == NULL)
++ return;
++
++ scrollbar_T *sb_info = sb->wp ? &sb->wp->w_scrollbars[0] : sb;
++ long value = sb_info->value;
++ long size = sb_info->size;
++ long max = sb_info->max;
++ BOOL isStillDragging = NO;
++ BOOL updateKnob = YES;
++
++ switch (hitPart) {
++ case NSScrollerDecrementPage:
++ value -= (size > 2 ? size - 2 : 1);
++ break;
++ case NSScrollerIncrementPage:
++ value += (size > 2 ? size - 2 : 1);
++ break;
++ case NSScrollerDecrementLine:
++ --value;
++ break;
++ case NSScrollerIncrementLine:
++ ++value;
++ break;
++ case NSScrollerKnob:
++ isStillDragging = YES;
++ // fall through ...
++ case NSScrollerKnobSlot:
++ value = (long)(fval * (max - size + 1));
++ // fall through ...
++ default:
++ updateKnob = NO;
++ break;
++ }
++
++ //gui_mac_msg(MSG_DEBUG, @"value %d -> %d", sb_info->value, value);
++ gui_drag_scrollbar(sb, value, isStillDragging);
++ gui_mac_redraw();
++ if (updateKnob)
++ {
++ // Dragging the knob or option + clicking automatically updates
++ // the knob position (on the actual NSScroller), so we only
++ // need to set the knob position in the other cases.
++ if (sb->wp)
++ {
++ // Update both the left & right vertical scrollbars.
++ VIMScroller *leftScroller = (VIMScroller *) sb->wp->w_scrollbars[SBAR_LEFT].scroller;
++ VIMScroller *rightScroller = (VIMScroller *) sb->wp->w_scrollbars[SBAR_RIGHT].scroller;
++ [leftScroller setThumbValue: value size: size max: max];
++ [rightScroller setThumbValue: value size: size max: max];
++ } else
++ {
++ // Update the horizontal scrollbar.
++ VIMScroller *scroller = (VIMScroller *) sb->scroller;
++ [scroller setThumbValue: value size: size max: max];
++ }
++ }
++}
++
++- (void) setThumbValue:(long)value size:(long)size max:(long)max
++{
++ float fval = max - size + 1 > 0 ? (float) value / (max - size + 1) : 0;
++ float prop = (float) size / (max + 1);
++
++ if (fval < 0) fval = 0;
++ else if (fval > 1.0f) fval = 1.0f;
++ if (prop < 0) prop = 0;
++ else if (prop > 1.0f) prop = 1.0f;
++
++ [self setFloatValue: fval knobProportion: prop];
++}
++
++- (scrollbar_T *) vimScrollBar
++{
++ return vimScrollBar;
++}
++
++@end
++
++void gui_mac_update_scrollbar(scrollbar_T *sb)
++{
++ VIMScroller *scroller = gui_mac_get_scroller(sb);
++
++ /* check if we need to add this scroller onto content view */
++ if (sb->enabled == TRUE && [scroller superview] != [gui_mac.current_window contentView])
++ {
++ [[gui_mac.current_window contentView] addSubview: scroller];
++ // gui_mac_msg(MSG_DEBUG, @"addSubview: %s", scrollbar_desc(sb));
++ }
++
++ if (sb->enabled == FALSE && [scroller superview] == [gui_mac.current_window contentView])
++ {
++ [scroller removeFromSuperview];
++ // gui_mac_msg(MSG_DEBUG, @"removeFromSuperview: %s", scrollbar_desc(sb));
++ }
++}
++
++/* Scroll Bar Related Utilities 2}}} */
++
++/* Private Functions 1}}} */
++
+diff --git a/src/main.c b/src/main.c
+index 9f56e88..8a5aa98 100644
+--- a/src/main.c
++++ b/src/main.c
+@@ -1847,7 +1847,7 @@ command_line_scan(parmp)
+ break;
+
+ case 'p': /* "-p[N]" open N tab pages */
+-#ifdef TARGET_API_MAC_OSX
++#ifdef FEAT_GUI_COCOA
+ /* For some reason on MacOS X, an argument like:
+ -psn_0_10223617 is passed in when invoke from Finder
+ or with the 'open' command */
+diff --git a/src/menu.c b/src/menu.c
+index 7d4839f..79189c7 100644
+--- a/src/menu.c
++++ b/src/menu.c
+@@ -2261,6 +2261,7 @@ ex_emenu(eap)
+ }
+
+ #if defined(FEAT_GUI_MSWIN) \
++ || (defined(FEAT_GUI_COCOA) && defined(FEAT_MENU)) \
+ || (defined(FEAT_GUI_GTK) && defined(FEAT_MENU)) \
+ || defined(FEAT_BEVAL_TIP) || defined(PROTO)
+ /*
+diff --git a/src/option.c b/src/option.c
+index fcac415..d6ef662 100644
+--- a/src/option.c
++++ b/src/option.c
+@@ -481,7 +481,7 @@ static struct vimoption
+ {"antialias", "anti", P_BOOL|P_VI_DEF|P_VIM|P_RCLR,
+ #if defined(FEAT_GUI) && defined(MACOS_X)
+ (char_u *)&p_antialias, PV_NONE,
+- {(char_u *)FALSE, (char_u *)FALSE}
++ {(char_u *)TRUE, (char_u *)TRUE}
+ #else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)FALSE, (char_u *)FALSE}
+@@ -2525,6 +2525,13 @@ static struct vimoption
+ (char_u *)&p_tbis, PV_NONE,
+ {(char_u *)"small", (char_u *)0L}},
+ #endif
++ {"transparency", "transp", P_NUM|P_VIM|P_RCLR,
++#if defined(FEAT_GUI_COCOA)
++ (char_u *)&p_transp, PV_NONE,
++#else
++ (char_u *)NULL, PV_NONE,
++#endif
++ {(char_u *)0L, (char_u *)0L} },
+ {"ttimeout", NULL, P_BOOL|P_VI_DEF|P_VIM,
+ (char_u *)&p_ttimeout, PV_NONE,
+ {(char_u *)FALSE, (char_u *)0L}},
+@@ -7933,6 +7940,20 @@ set_num_option(opt_idx, varp, value, errbuf, errbuflen, opt_flags)
+ }
+ #endif
+
++#if defined(FEAT_GUI_COCOA)
++ /* 'transparency' is a number between 0 and 100 */
++ else if (pp == &p_transp)
++ {
++ if (p_transp < 0 || p_transp > 100)
++ {
++ errmsg = e_invarg;
++ p_transp = old_value;
++ }
++ else if (gui.in_use)
++ gui_mch_new_colors();
++ }
++#endif
++
+ /*
+ * Check the bounds for numeric options here
+ */
+diff --git a/src/option.h b/src/option.h
+index 00374d7..73337d6 100644
+--- a/src/option.h
++++ b/src/option.h
+@@ -775,6 +775,9 @@ EXTERN char_u *p_titlestring; /* 'titlestring' */
+ #ifdef FEAT_INS_EXPAND
+ EXTERN char_u *p_tsr; /* 'thesaurus' */
+ #endif
++#ifdef FEAT_GUI_COCOA
++EXTERN long p_transp; /* 'transparency' */
++#endif
+ EXTERN int p_ttimeout; /* 'ttimeout' */
+ EXTERN long p_ttm; /* 'ttimeoutlen' */
+ EXTERN int p_tbi; /* 'ttybuiltin' */
+diff --git a/src/os_mac.h b/src/os_mac.h
+index 7a54ee5..2e4c627 100644
+--- a/src/os_mac.h
++++ b/src/os_mac.h
+@@ -23,6 +23,7 @@
+ * files have many conflicts).
+ */
+ #ifndef FEAT_X11
++#if 0
+ # include <Quickdraw.h> /* Apple calls it QuickDraw.h... */
+ # include <ToolUtils.h>
+ # include <LowMem.h>
+@@ -36,6 +37,7 @@
+ # include <Script.h>
+ # endif
+ #endif
++#endif
+
+ /*
+ * Unix interface
+diff --git a/src/os_mac_conv.c b/src/os_mac_conv.c
+index 7930189..6a7a6de 100644
+--- a/src/os_mac_conv.c
++++ b/src/os_mac_conv.c
+@@ -22,6 +22,9 @@
+ typedef int UniChar;
+ typedef int *TECObjectRef;
+ typedef int CFStringRef;
++# else
++typedef unsigned short UniChar;
++#include <CoreServices/CoreServices.h>
+ # endif
+
+ static char_u *mac_utf16_to_utf8 __ARGS((UniChar *from, size_t fromLen, size_t *actualLen));
+diff --git a/src/proto.h b/src/proto.h
+index 85f4937..d61171d 100644
+--- a/src/proto.h
++++ b/src/proto.h
+@@ -211,9 +211,12 @@ extern char_u *vimpty_getenv __ARGS((const char_u *string)); /* from pty.c */
+ extern char *vim_SelFile __ARGS((Widget toplevel, char *prompt, char *init_path, int (*show_entry)(), int x, int y, guicolor_T fg, guicolor_T bg, guicolor_T scroll_fg, guicolor_T scroll_bg));
+ # endif
+ # endif
+-# ifdef FEAT_GUI_MAC
++# ifdef FEAT_GUI_CARBON
+ # include "gui_mac.pro"
+ # endif
++# ifdef FEAT_GUI_COCOA
++# include "gui_cocoa.pro"
++# endif
+ # ifdef FEAT_GUI_X11
+ # include "gui_x11.pro"
+ # endif
+diff --git a/src/proto/gui_cocoa.pro b/src/proto/gui_cocoa.pro
+new file mode 100755
+index 0000000..69436af
+--- /dev/null
++++ b/src/proto/gui_cocoa.pro
+@@ -0,0 +1,89 @@
++/* gui_cocoa.pro */
++
++/*
++ * Mac specific prototypes
++ */
++
++void gui_mch_set_blinking __ARGS((long wait, long on, long off));
++void gui_mch_stop_blink __ARGS((void));
++void gui_mch_start_blink __ARGS((void));
++void gui_mch_getmouse __ARGS((int *x, int *y));
++void gui_mch_setmouse __ARGS((int x, int y));
++void gui_mch_prepare __ARGS((int *argc, char **argv));
++int gui_mch_init_check __ARGS((void));
++int gui_mch_init __ARGS((void));
++void gui_mch_new_colors __ARGS((void));
++int gui_mch_open __ARGS((void));
++void gui_mch_exit __ARGS((int));
++void gui_mch_set_winsize __ARGS((int width, int height, int min_width, int min_height, int base_width, int base_height));
++int gui_mch_get_winpos __ARGS((int *x, int *y));
++void gui_mch_set_winpos __ARGS((int x, int y));
++void gui_mch_set_shellsize __ARGS((int width, int height, int min_width, int min_height, int base_width, int base_height, int direction));
++void gui_mch_get_screen_dimensions __ARGS((int *screen_w, int *screen_h));
++void gui_mch_set_text_area_pos __ARGS((int x, int y, int w, int h));
++void gui_mch_enable_scrollbar __ARGS((scrollbar_T *sb, int flag));
++void gui_mch_set_scrollbar_thumb __ARGS((scrollbar_T *sb, long val, long size, long max));
++void gui_mch_set_scrollbar_pos __ARGS((scrollbar_T *sb, int x, int y, int w, int h));
++void gui_mch_create_scrollbar __ARGS((scrollbar_T *sb, int orient));
++void gui_mch_destroy_scrollbar __ARGS((scrollbar_T *sb));
++int gui_mch_adjust_charheight __ARGS((void));
++int gui_mch_init_font __ARGS((char_u *font_name, int fontset));
++GuiFont gui_mch_get_font __ARGS((char_u *name, int giveErrorIfMissing));
++char_u *gui_mch_get_fontname __ARGS((GuiFont font, char_u *name));
++GuiFont gui_mac_find_font __ARGS((char_u *font_name));
++void gui_mch_set_font __ARGS((GuiFont font));
++int gui_mch_same_font __ARGS((GuiFont f1, GuiFont f2));
++void gui_mch_free_font __ARGS((GuiFont font));
++guicolor_T gui_mch_get_color __ARGS((char_u *name));
++void gui_mch_set_fg_color __ARGS((guicolor_T color));
++void gui_mch_set_bg_color __ARGS((guicolor_T color));
++void gui_mch_set_sp_color __ARGS((guicolor_T color));
++void gui_mch_draw_string __ARGS((int row, int col, char_u *s, int len, int flags));
++int gui_mch_haskey __ARGS((char_u *name));
++void gui_mch_beep __ARGS((void));
++void gui_mch_flash __ARGS((int msec));
++void gui_mch_invert_rectangle __ARGS((int r, int c, int nr, int nc));
++void gui_mch_iconify __ARGS((void));
++void gui_mch_settitle __ARGS((char_u *title, char_u *icon));
++void gui_mch_draw_hollow_cursor __ARGS((guicolor_T color));
++void gui_mch_draw_part_cursor __ARGS((int w, int h, guicolor_T color));
++void gui_mch_update __ARGS((void));
++int gui_mch_wait_for_chars __ARGS((int wtime));
++void gui_mch_flush __ARGS((void));
++void gui_mch_clear_block __ARGS((int row1, int col1, int row2, int col2));
++void gui_mch_clear_all __ARGS((void));
++void gui_mch_delete_lines __ARGS((int row, int num_lines));
++void gui_mch_insert_lines __ARGS((int row, int num_lines));
++void gui_mch_enable_menu __ARGS((int flag));
++void gui_mch_set_menu_pos __ARGS((int x, int y, int w, int h));
++void gui_mch_add_menu __ARGS((vimmenu_T *menu, int pos));
++void gui_mch_add_menu_item __ARGS((vimmenu_T *menu, int idx));
++void gui_mch_show_popupmenu __ARGS((vimmenu_T *menu));
++void gui_mch_destroy_menu __ARGS((vimmenu_T *menu));
++void gui_mch_menu_grey __ARGS((vimmenu_T *menu, int grey));
++void gui_mch_menu_hidden __ARGS((vimmenu_T *menu, int hidden));
++void gui_mch_draw_menubar __ARGS((void));
++int gui_mch_get_lightness __ARGS((guicolor_T pixel));
++long_u gui_mch_get_rgb __ARGS((guicolor_T pixel));
++int gui_mch_get_mouse_x __ARGS((void));
++int gui_mch_get_mouse_y __ARGS((void));
++void gui_mch_setmouse __ARGS((int x, int y));
++void gui_mch_show_popupmenu __ARGS((vimmenu_T *menu));
++int gui_mch_dialog __ARGS((int type, char_u *title, char_u *message, char_u *buttons, int dfltbutton, char_u *textfield));
++char_u *gui_mch_browse __ARGS((int saving, char_u *title, char_u *dflt, char_u *ext, char_u *initdir, char_u *filter));
++void gui_mch_set_foreground __ARGS((void));
++void gui_mch_show_tabline __ARGS((int showit));
++int gui_mch_showing_tabline __ARGS((void));
++void gui_mch_update_tabline __ARGS((void));
++void gui_mch_set_curtab __ARGS((int nr));
++
++void gui_mch_lose_selection __ARGS((void));
++int gui_mch_own_selection __ARGS((void));
++void gui_mch_clear_selection __ARGS((void));
++
++void clip_mch_lose_selection __ARGS((VimClipboard *cbd));
++void clip_mch_request_selection __ARGS((VimClipboard *cbd));
++void clip_mch_set_selection __ARGS((VimClipboard *cbd));
++int clip_mch_own_selection __ARGS((VimClipboard *cbd));
++
++/* vim: set ft=c : */
+diff --git a/src/structs.h b/src/structs.h
+index 329676e..18724fb 100644
+--- a/src/structs.h
++++ b/src/structs.h
+@@ -2244,7 +2244,7 @@ struct VimMenu
+ HMENU submenu_id; /* If this is submenu, add children here */
+ HWND tearoff_handle; /* hWnd of tearoff if created */
+ #endif
+-#ifdef FEAT_GUI_MAC
++#ifdef FEAT_GUI_CARBON
+ /* MenuHandle id; */
+ /* short index; */ /* the item index within the father menu */
+ short menu_id; /* the menu id to which this item belong */
+@@ -2253,6 +2253,10 @@ struct VimMenu
+ MenuHandle menu_handle;
+ MenuHandle submenu_handle;
+ #endif
++#ifdef FEAT_GUI_COCOA
++ void *menu_handle; /* NSMenu *, only for menus with submenus */
++ void *item_handle; /* NSMenuItem *, for all menus */
++#endif
+ #ifdef RISCOS
+ int *id; /* Not used, but gui.c needs it */
+ int greyed_out; /* Flag */
+diff --git a/src/version.c b/src/version.c
+index cdd069b..bb2cf9f 100644
+--- a/src/version.c
++++ b/src/version.c
+@@ -1205,10 +1205,10 @@ list_version()
+ # if defined(MSWIN)
+ MSG_PUTS(_("with GUI."));
+ # else
+-# if defined (TARGET_API_MAC_CARBON) && TARGET_API_MAC_CARBON
++# ifdef FEAT_GUI_CARBON
+ MSG_PUTS(_("with Carbon GUI."));
+ # else
+-# if defined (TARGET_API_MAC_OSX) && TARGET_API_MAC_OSX
++# ifdef FEAT_GUI_COCOA
+ MSG_PUTS(_("with Cocoa GUI."));
+ # else
+ # if defined (MACOS)