]> granicus.if.org Git - vim/commitdiff
patch 8.2.0320: no Haiku support v8.2.0320
authorBram Moolenaar <Bram@vim.org>
Wed, 26 Feb 2020 15:16:53 +0000 (16:16 +0100)
committerBram Moolenaar <Bram@vim.org>
Wed, 26 Feb 2020 15:16:53 +0000 (16:16 +0100)
Problem:    No Haiku support.
Solution:   Add support for Haiku. (Emir Sari, closes #5605)

41 files changed:
Filelist
runtime/doc/Makefile
runtime/doc/eval.txt
runtime/doc/gui.txt
runtime/doc/help.txt
runtime/doc/options.txt
runtime/doc/os_haiku.txt [new file with mode: 0644]
runtime/doc/starting.txt
runtime/doc/tags
runtime/gvimrc_example.vim
runtime/vimrc_example.vim
src/INSTALL
src/Makefile
src/auto/configure
src/configure.ac
src/evalfunc.c
src/feature.h
src/fileio.c
src/globals.h
src/gui.c
src/gui.h
src/gui_haiku.cc [new file with mode: 0644]
src/gui_haiku.h [new file with mode: 0644]
src/mbyte.c
src/menu.c
src/misc1.c
src/mouse.c
src/option.h
src/os_haiku.h [new file with mode: 0644]
src/os_haiku.rdef [new file with mode: 0644]
src/os_unix.c
src/os_unix.h
src/osdef1.h.in
src/proto.h
src/proto/gui_haiku.pro [new file with mode: 0644]
src/pty.c
src/screen.c
src/structs.h
src/term.c
src/version.c
src/vim.h

index f5328a5d530eb57a7b7160482c04e63e8c9a3775..8407e1cfc69d96dacf7e59ee40307225dd514705 100644 (file)
--- a/Filelist
+++ b/Filelist
@@ -599,6 +599,14 @@ SRC_AMI =  \
                src/testdir/amiga.vim \
                src/xxd/Make_amiga.mak \
 
+# source files for Haiku (also in the extra archive)
+SRC_HAIKU =    \
+               src/os_haiku.h \
+               src/os_haiku.rdef \
+               src/gui_haiku.cc \
+               src/gui_haiku.h \
+               src/proto/gui_haiku.pro \
+
 # source files for the Mac (also in the extra archive)
 SRC_MAC =      \
                src/INSTALLmac.txt \
@@ -634,13 +642,13 @@ SRC_QNX = \
                src/proto/gui_photon.pro \
                src/proto/os_qnx.pro \
 
-
 # source files for the extra archive (all sources that are not for Unix)
 SRC_EXTRA =    \
                $(SRC_AMI) \
                $(SRC_AMI_DOS) \
                $(SRC_DOS) \
                $(SRC_DOS_BIN) \
+               $(SRC_HAIKU) \
                $(SRC_MAC) \
                $(SRC_QNX) \
                $(SRC_VMS) \
index 65dc8436c6ae8b208d76c4067e101d5feb70dd85..b1b4c8ec724d3d1a1a557441ae1cd0516fdc3889 100644 (file)
@@ -64,6 +64,7 @@ DOCS = \
        os_amiga.txt \
        os_beos.txt \
        os_dos.txt \
+       os_haiku.txt \
        os_mac.txt \
        os_mint.txt \
        os_msdos.txt \
@@ -204,6 +205,7 @@ HTMLS = \
        os_amiga.html \
        os_beos.html \
        os_dos.html \
+       os_haiku.html \
        os_mac.html \
        os_mint.html \
        os_msdos.html \
@@ -422,6 +424,9 @@ os_beos.txt:
 os_dos.txt:
        touch os_dos.txt
 
+os_haiku.txt:
+       touch os_haiku.txt
+
 os_mac.txt:
        touch os_mac.txt
 
index 508c59a150e54dec4c7e0721f0057ca9aff79f4e..fb4db5d40760741a05ea394c4d3d954514b4a40d 100644 (file)
@@ -10766,12 +10766,14 @@ gui_gnome             Compiled with Gnome support (gui_gtk is also defined).
 gui_gtk                        Compiled with GTK+ GUI (any version).
 gui_gtk2               Compiled with GTK+ 2 GUI (gui_gtk is also defined).
 gui_gtk3               Compiled with GTK+ 3 GUI (gui_gtk is also defined).
+gui_haiku              Compiled with Haiku GUI.
 gui_mac                        Compiled with Macintosh GUI.
 gui_motif              Compiled with Motif GUI.
 gui_photon             Compiled with Photon GUI.
 gui_running            Vim is running in the GUI, or it will start soon.
 gui_win32              Compiled with MS Windows Win32 GUI.
 gui_win32s             idem, and Win32s system being used (Windows 3.1)
+haiku                  Haiku version of Vim.
 hangul_input           Compiled with Hangul input support. |hangul|
 hpux                   HP-UX version of Vim.
 iconv                  Can use iconv() for conversion.
index 93e01ef6c5134a2f72233ec7fe02d2c843a05b37..1a38496040335dd6126916f45fe3561ecb842919 100644 (file)
@@ -99,6 +99,7 @@ Recommended place for your personal GUI initializations:
                            or $VIM/_gvimrc
        Amiga               s:.gvimrc, home:.gvimrc, home:vimfiles:gvimrc
                            or $VIM/.gvimrc
+       Haiku               $HOME/config/settings/vim/gvimrc
 
 The personal initialization files are searched in the order specified above
 and only the first one that is found is read.
index 8f67ef5c98912fed541b346e0e1606ba1c8d1246..f2b78466eee543ce777c505b97c00db251da7349 100644 (file)
@@ -204,6 +204,7 @@ Remarks about specific systems ~
 |os_os2.txt|   OS/2
 |os_qnx.txt|   QNX
 |os_risc.txt|  RISC-OS
+|os_haiku.txt| Haiku
 |os_unix.txt|  Unix
 |os_vms.txt|   VMS
 |os_win32.txt| MS-Windows
index a48e9ea4a5807584cb23d5570ead6ab09eb399ad..df8aba2a556ffae076cd5fdf2d5482198dde4747 100644 (file)
@@ -3769,7 +3769,7 @@ A jump table for the options with a short description can be found at |Q_op|.
                'guitablabel' can be used to change the text in the labels.
                When 'e' is missing a non-GUI tab pages line may be used.
                The GUI tabs are only supported on some systems, currently
-               GTK, Motif, Mac OS/X and MS-Windows.
+               GTK, Motif, Mac OS/X, Haiku, and MS-Windows.
                                                                *'go-f'*
          'f'   Foreground: Don't use fork() to detach the GUI from the shell
                where it was started.  Use this for programs that wait for the
@@ -6207,6 +6207,11 @@ A jump table for the options with a short description can be found at |Q_op|.
                                        Macintosh: "$VIM:vimfiles,
                                                $VIMRUNTIME,
                                                $VIM:vimfiles:after"
+                                       Haiku: "$BE_USER_SETTINGS/vim,
+                                               $VIM/vimfiles,
+                                               $VIMRUNTIME,
+                                               $VIM/vimfiles/after,
+                                               $BE_USER_SETTINGS/vim/after")
                                        VMS: "sys$login:vimfiles,
                                                $VIM/vimfiles,
                                                $VIMRUNTIME,
@@ -7665,6 +7670,7 @@ A jump table for the options with a short description can be found at |Q_op|.
                                      in the GUI: "builtin_gui"
                                        on Amiga: "amiga"
                                         on BeOS: "beos-ansi"
+                                       on Haiku: "xterm"
                                          on Mac: "mac-ansi"
                                         on MiNT: "vt52"
                                         on Unix: "ansi"
diff --git a/runtime/doc/os_haiku.txt b/runtime/doc/os_haiku.txt
new file mode 100644 (file)
index 0000000..1154ea7
--- /dev/null
@@ -0,0 +1,228 @@
+*os_haiku.txt* For Vim version 8.2.  Last change: 2020 Feb 26
+
+
+                 VIM REFERENCE MANUAL    by Bram Moolenaar
+
+
+                                                       *Haiku*
+This file contains the particularities for the Haiku version of Vim.  For
+matters not discussed in this file, Vim behaves very much like the Unix
+|os_unix.txt| version.
+
+Haiku is an open-source operating system inspired by BeOS, that specifically
+targets personal computing.
+
+ 1. General                    |haiku-general|
+ 2. Compiling Vim              |haiku-compiling|
+ 3. The Haiku GUI              |haiku-gui|
+ 4. The $VIM directory         |haiku-vimdir|
+ 5. The $BE_USER_SETTINGS
+    directory                  |haiku-user-settings-dir|
+ 6. Drag & Drop                        |haiku-dragndrop|
+ 7. Single Launch vs. Multiple
+    Launch                     |haiku-launch|
+ 8. Fonts                      |haiku-fonts|
+ 9. The meta key modifier      |haiku-meta|
+10. Mouse key mappings         |haiku-mouse|
+11. Color names                        |haiku-colors|
+12. Credits                    |haiku-support-credits|
+13. Bugs & things To Do                |haiku-bugs|
+
+
+1. General                                             *haiku-general*
+
+The default syntax highlighting mostly works with different foreground colors
+to highlight items.  This works best if you set your Terminal window to a
+darkish background and light letters.  Some middle-grey background (for
+instance (r,g,b)=(168,168,168)) with black letters also works nicely.
+
+
+2. Compiling Vim                                       *haiku-compiling*
+
+Vim can be compiled using the standard configure/make approach. Running
+./configure without any arguments or passing --enable-gui=haiku, will compile
+vim with the Haiku GUI support.  Run ./configure --help , to find out other
+features you can enable/disable.
+
+Now you should use "make" to compile Vim, then "make install" to install it.
+For seamless integration into the Haiku the GUI-less vim binary should be
+additionally installed over the GUI version. Typical build commands are: >
+
+  ./configure --prefix=`finddir B_SYSTEM_NONPACKAGED_DIRECTORY` \
+    --datarootdir=`finddir B_SYSTEM_NONPACKAGED_DATA_DIRECTORY` \
+    --mandir=`finddir B_SYSTEM_NONPACKAGED_DIRECTORY`/documentation/man \
+  make clean
+  make install
+
+  ./configure --prefix=`finddir B_SYSTEM_NONPACKAGED_DIRECTORY`  \
+    --datarootdir=`finddir B_SYSTEM_NONPACKAGED_DATA_DIRECTORY` \
+    --mandir=`finddir B_SYSTEM_NONPACKAGED_DIRECTORY`/documentation/man \
+    --disable-gui
+  make clean
+  make install
+
+
+3. The Haiku GUI                                       *haiku-gui*
+
+Normally Vim starts with the GUI if you start it as gvim or vim -g.  The vim
+version with GUI tries to determine if it was started from the Tracker instead
+of the Terminal, and if so, uses the GUI anyway. However, the current detection
+scheme is fooled if you use the command "vim - </dev/null".
+
+Stuff that does not work yet:
+
+- Mouse up events are not generated when outside the window. This may be a bug in
+  Haiku. You can notice this when selecting text and moving the cursor outside
+  the window, then letting go of the mouse button.  Another way is when you
+  drag the scrollbar and do the same thing.  Because Vim still thinks you are
+  still playing with the scrollbar it won't change it itself. I provided a
+  workaround which kicks in when the window is activated or deactivated (so it
+  works best with focus- follows-mouse turned on).
+- The cursor does not flash (very low priority; I'm not sure I even like it
+  when it flashes)
+
+
+4. The $VIM directory                                  *haiku-vimdir*
+
+$VIM is the symbolic name for the place where Vims support files are stored.
+The default value for $VIM is set at compile time and can be determined with >
+
+  :version
+
+The normal value is /boot/common/data/vim.  If you don't like it you can
+set the VIM environment variable to override this, or set 'helpfile' in your
+.vimrc: >
+
+  :if version >= 500
+  :    set helpfile=~/vim/runtime/doc/help.txt
+  :    syntax on
+  :endif
+
+
+5. The $USER_SETTINGS_DIR directory            *haiku-user-settings-dir*
+
+$USER_SETTINGS_DIR is the symbolic name for the place where Haiku
+configuration and settings files are stored.
+
+The normal value is /boot/home/config/settings.
+
+
+6. Drag & Drop                                         *haiku-dragndrop*
+
+You can drop files and directories on either the Vim icon (starts a new Vim
+session, unless you use the File Types application to set Vim to be "Single
+Launch") or on the Vim window (starts editing the files).  Dropping a folder
+sets Vim's current working directory. |:cd| |:pwd| If you drop files or
+folders with either SHIFT key pressed, Vim changes directory to the folder
+that contains the first item dropped.  When starting Vim, there is no need to
+press shift: Vim behaves as if you do.
+
+Files dropped set the current argument list. |argument-list|
+
+
+7. Single Launch vs. Multiple Launch                   *haiku-launch*
+
+As distributed Vim's Application Flags (as seen in the FileTypes preference)
+are set to Multiple Launch.  If you prefer, you can set them to Single Launch
+instead.  Attempts to start a second copy of Vim will cause the first Vim to
+open the files instead.  This works from the Tracker but also from the command
+line.  In the latter case, non-file (option) arguments are not supported.
+Another drawback of the Single Launch is silent ignore of "Open With ..."
+requests by vim instance that running as non-GUI application even GUI support
+was compiled in. Vim instance running with GUI has no such problems.
+
+NB: Only the GUI version has a BApplication (and hence Application Flags).
+This section does not apply to the GUI-less version, should you compile one.
+
+
+8. Fonts                                               *haiku-fonts*
+
+Set fonts with >
+
+  :set guifont=DejaVu_Sans_Mono/Book/12
+
+where the first part is the font family, the second part the style, and the
+third part the size.  You can use underscores instead of spaces in family and
+style.
+
+Best results are obtained with monospaced fonts.  Vim attempts to use all
+fonts in B_FIXED_SPACING mode but apparently this does not work for
+proportional fonts (despite what the BeBook says).
+
+To verify which encodings are supported by the current font give the >
+
+  :digraphs
+
+command, which lists a bunch of characters with their ISO Latin 1 encoding.
+If, for instance, there are "box" characters among them, or the last character
+isn't a dotted-y, then for this font the encoding does not work.
+
+If the font you specify is unavailable, you get the system fixed font.
+
+GUI Font Selection Dialog is available at giving the >
+
+  :set guifont=*
+
+command.
+
+
+9. The meta key modifier                               *haiku-meta*
+
+The META key modifier is obtained by the left or right OPTION keys.  This is
+because the ALT (aka COMMAND) keys are not passed to applications.
+
+
+10. Mouse key mappings                                 *haiku-mouse*
+
+Vim calls the various mouse buttons LeftMouse, MiddleMouse and RightMouse.  If
+you use the default Mouse preference settings these names indeed correspond to
+reality.  Vim uses this mapping:
+
+    Button 1 -> LeftMouse,
+    Button 2 -> RightMouse,
+    Button 3 -> MiddleMouse.
+
+If your mouse has fewer than 3 buttons you can provide your own mapping from
+mouse clicks with modifier(s) to other mouse buttons.  See the file
+$VIM/macros/swapmous.vim for an example.               |gui-mouse-mapping|
+
+
+11. Color names                                                *haiku-colors*
+
+Vim has a number of color names built-in.  Additional names are read from the
+file $VIMRUNTIME/rgb.txt, if present.  This file is basically the color
+database from X.  Names used from this file are cached for efficiency.
+
+
+12. GUI Toolbar Images                                 *haiku-toolbar-images*
+
+Alternative set of toolbar images should be the PNG image of any height you
+like. Image width is calculated to contain at least 32 buttons in one-row
+cells.
+The image should be stored under the name $VIRUNTIME/bitmaps/builtin-tools.png
+More info about the buttons assignment are at |builtin-tools|.
+
+
+13. Credits                                            *haiku-support-credits*
+
+Haiku port is based on work done for BeOS version by many people
+ - BeBox GUI support Copyright 1998 by Olaf Seibert;
+ - Ported to R4 by Richard Offer <richard@whitequeen.com> Jul 99;
+ - Those who contributed, not listed above but not forgotten;
+ - Haiku support by Siarzhuk Zharski <imker@gmx.li> Apr-Mai 2009.
+
+All the changes and patches released under vim-license.
+
+Thank you, all!
+
+
+13. Bugs & things To Do                                        *haiku-bugs*
+
+The port is under development now and far away from the perfect state. Bug
+reports, patches and wishes are welcome.
+
+
+ -Siarzhuk Zharski <imker@gmx.li>
+
+
+ vim:tw=78:ts=8:ft=help:norl:
index b9a23707116893e0ce9dd988bbc60b9d516d5da0..f437c0e0346727d565a453d9beff50cb70a751c3 100644 (file)
@@ -790,6 +790,7 @@ accordingly.  Vim proceeds in this order:
                                or $VIM/_vimrc
                Amiga           s:.vimrc, home:.vimrc, home:vimfiles:vimrc
                                or $VIM/.vimrc
+               Haiku           $HOME/config/settings/vim/vimrc
 
        The files are searched in the order specified above and only the first
        one that is found is read.
@@ -835,6 +836,8 @@ accordingly.  Vim proceeds in this order:
                    "$HOME/_vimrc"         (for Win32) (*)
                    "$HOME/vimfiles/vimrc" (for Win32) (*)
                    "$VIM/_vimrc"          (for Win32) (*)
+                   "$HOME/config/settings/vim/vimrc"   (for Haiku) (*)
+
                Note: For Unix and Amiga, when ".vimrc" does not exist,
                "_vimrc" is also tried, in case an MS-DOS compatible file
                system is used.  For MS-Windows ".vimrc" is checked after
@@ -950,6 +953,8 @@ sessions.  Put it in a place so that it will be found by 3b:
        ~/.vimrc        (Unix)
        s:.vimrc        (Amiga)
        $VIM\_vimrc     (Win32)
+       ~/config/settings/vim/vimrc (Haiku)
+
 Note that creating a vimrc file will cause the 'compatible' option to be off
 by default.  See |compatible-default|.
 
index 735fb2d0c76bc4a188325f5d6c910fdb2259d717..fdba199a0408538f4ce3669a6ddb9bc26c95f860 100644 (file)
@@ -4871,6 +4871,7 @@ GetLatestVimScripts-copyright     pi_getscript.txt        /*GetLatestVimScripts-copyright*
 GetLatestVimScripts_dat        pi_getscript.txt        /*GetLatestVimScripts_dat*
 Gnome  gui_x11.txt     /*Gnome*
 H      motion.txt      /*H*
+Haiku  os_haiku.txt    /*Haiku*
 I      insert.txt      /*I*
 ICCF   uganda.txt      /*ICCF*
 IM-server      mbyte.txt       /*IM-server*
@@ -7053,6 +7054,20 @@ g~       change.txt      /*g~*
 g~g~   change.txt      /*g~g~*
 g~~    change.txt      /*g~~*
 h      motion.txt      /*h*
+haiku-bugs     os_haiku.txt    /*haiku-bugs*
+haiku-colors   os_haiku.txt    /*haiku-colors*
+haiku-compiling        os_haiku.txt    /*haiku-compiling*
+haiku-dragndrop        os_haiku.txt    /*haiku-dragndrop*
+haiku-fonts    os_haiku.txt    /*haiku-fonts*
+haiku-general  os_haiku.txt    /*haiku-general*
+haiku-gui      os_haiku.txt    /*haiku-gui*
+haiku-launch   os_haiku.txt    /*haiku-launch*
+haiku-meta     os_haiku.txt    /*haiku-meta*
+haiku-mouse    os_haiku.txt    /*haiku-mouse*
+haiku-support-credits  os_haiku.txt    /*haiku-support-credits*
+haiku-toolbar-images   os_haiku.txt    /*haiku-toolbar-images*
+haiku-user-settings-dir        os_haiku.txt    /*haiku-user-settings-dir*
+haiku-vimdir   os_haiku.txt    /*haiku-vimdir*
 hangul hangulin.txt    /*hangul*
 hangulin.txt   hangulin.txt    /*hangulin.txt*
 has()  eval.txt        /*has()*
@@ -8211,6 +8226,7 @@ os_390.txt        os_390.txt      /*os_390.txt*
 os_amiga.txt   os_amiga.txt    /*os_amiga.txt*
 os_beos.txt    os_beos.txt     /*os_beos.txt*
 os_dos.txt     os_dos.txt      /*os_dos.txt*
+os_haiku.txt   os_haiku.txt    /*os_haiku.txt*
 os_mac.txt     os_mac.txt      /*os_mac.txt*
 os_mint.txt    os_mint.txt     /*os_mint.txt*
 os_msdos.txt   os_msdos.txt    /*os_msdos.txt*
index cc3e791e877855aaf808f64671f2a8924d53f36a..083dacee905b98bce55de4db665f144adfd288d6 100644 (file)
@@ -6,10 +6,11 @@
 " Last change: 2016 Apr 05
 "
 " To use it, copy it to
-"             for Unix:  ~/.gvimrc
-"            for Amiga:  s:.gvimrc
-"  for MS-DOS and Win32:  $VIM\_gvimrc
-"          for OpenVMS:  sys$login:.gvimrc
+"         for Unix:  ~/.gvimrc
+"        for Amiga:  s:.gvimrc
+"   for MS-Windows:  $VIM\_gvimrc
+"        for Haiku:  ~/config/settings/vim/gvimrc
+"      for OpenVMS:  sys$login:.gvimrc
 
 " Make external commands work through a pipe instead of a pseudo-tty
 "set noguipty
index 3017a6cf935d2e90e709eaafaeb473381c8a82d7..e11e4cff555962c753b8536aa2cbec29360af053 100644 (file)
@@ -7,6 +7,7 @@
 "             for Unix:  ~/.vimrc
 "            for Amiga:  s:.vimrc
 "       for MS-Windows:  $VIM\_vimrc
+"            for Haiku:  ~/config/settings/vim/vimrc
 "          for OpenVMS:  sys$login:.vimrc
 
 " When started as "evim", evim.vim will already have done these settings, bail
index 3da9141d222ccf0a1a6a1c8dc919e1553be06772..a404833c8dab57d56f93cfab23f65b1adc3b0fe4 100644 (file)
@@ -16,7 +16,7 @@ See INSTALLvms.txt              for VMS
 See INSTALLx.txt               for cross-compiling on Unix
 See ../READMEdir/README_390.txt for z/OS and OS/390 Unix
 See ../runtime/doc/os_beos.txt  for BeBox
-
+See ../runtime/doc/os_haiku.txt        for Haiku
 
 1. Generic
 ==========
index e284530164e1331a7cae955527c363a6360dddf1..d66b2704830b88482261c559aff6d509c2dd5c2f 100644 (file)
@@ -1385,6 +1385,20 @@ CARBONGUI_BUNDLE = gui_bundle
 APPDIR = $(VIMNAME).app
 CARBONGUI_TESTARG = VIMPROG=../$(APPDIR)/Contents/MacOS/$(VIMTARGET)
 
+### Haiku GUI
+HAIKUGUI_SRC   = gui.c gui_haiku.cc
+HAIKUGUI_OBJ   = objects/gui.o objects/gui_haiku.o
+HAIKUGUI_DEFS  = -DFEAT_GUI_HAIKU
+HAIKUGUI_IPATH =
+HAIKUGUI_LIBS_DIR =
+HAIKUGUI_LIBS1 = -lbe -lroot -ltracker -ltranslation -lsupc++ -lstdc++
+HAIKUGUI_LIBS2 =
+HAIKUGUI_INSTALL = install_normal install_haiku_extra
+HAIKUGUI_TARGETS       = installglinks_haiku
+HAIKUGUI_MAN_TARGETS =
+HAIKUGUI_TESTTARGET = gui
+HAIKUGUI_BUNDLE =
+
 # 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
 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_w32.pro gui_photon.pro
@@ -3217,6 +3231,9 @@ objects/gui_gtk_gresources.o: auto/gui_gtk_gresources.c
 objects/gui_gtk_x11.o: gui_gtk_x11.c
        $(CCC) -o $@ gui_gtk_x11.c
 
+objects/gui_haiku.o: gui_haiku.cc
+       $(CCC) -o $@ gui_haiku.cc
+
 objects/gui_motif.o: gui_motif.c
        $(CCC) -o $@ gui_motif.c
 
@@ -3349,6 +3366,9 @@ objects/os_beos.o: os_beos.c
 objects/os_qnx.o: os_qnx.c
        $(CCC) -o $@ os_qnx.c
 
+objects/os_haiku.rsrc: os_haiku.rdef
+       cat $< | $(CCC) -E - | grep -v '^#' | rc -o "$@" -
+
 objects/os_macosx.o: os_macosx.m
        $(CCC) -o $@ os_macosx.m
 
@@ -3616,6 +3636,61 @@ $(APPDIR)/Contents:
 # Dependencies that "make depend" doesn't find
 objects/gui_gtk_x11.o: version.h
 
+###############################################################################
+#
+# Haiku installation
+#
+# This rule:
+#              - add resources to already installed vim binary to avoid
+#                stripping them during install;
+#              - copy rgb.txt to runtime directory;
+#              - update system MIME database with info about vim application.
+#
+install_haiku_extra: $(DEST_BIN)/$(VIMTARGET) objects/os_haiku.rsrc
+       xres -o $(DEST_BIN)/$(VIMTARGET) objects/os_haiku.rsrc
+       $(INSTALL_DATA) $(SCRIPTSOURCE)/rgb.txt $(DEST_RT)
+       mimeset $(DEST_BIN)/$(VIMTARGET)
+
+# List of g*-links that should be replaced with shell script equivalents.
+# This solves the problem of them from Tracker.
+#
+HAIKU_GLINKS =         $(DEST_BIN)/$(GVIMTARGET) \
+                               $(DEST_BIN)/$(GVIEWTARGET) \
+                               $(DEST_BIN)/$(GVIMDIFFTARGET) \
+                               $(DEST_BIN)/$(RGVIMTARGET) \
+                               $(DEST_BIN)/$(RGVIEWTARGET)
+
+# This rule:
+#              - Replace gvim link with copy of vim binary.
+#              - Replace g*-links with shell script equivalents to solve the
+#                problem of calling them from Tracker,
+#              - Add icon resources to mentioned g*-link shell scripts
+#              - in case gui-less vim.con executable available use it.
+#
+installglinks_haiku: $(HAIKU_GLINKS) install_haiku_extra
+       @catattr -r "BEOS:ICON" $(DEST_BIN)/$(GVIMTARGET) > ~icon.attr
+       for i in $(HAIKU_GLINKS); do \
+               rm $$i ; \
+               echo "#!/bin/sh" > $$i ; \
+               case $$i in \
+                       $(DEST_BIN)/$(GVIMTARGET)) \
+                               cp $(DEST_BIN)/$(VIMTARGET) $$i ; \
+                               if [ -f $(VIMTARGET).con ] ; then \
+                                       $(STRIP) $(VIMTARGET).con ; \
+                                       mv $(VIMTARGET).con $(DEST_BIN)/$(VIMTARGET) ; \
+                               fi ;; \
+                       $(DEST_BIN)/$(GVIEWTARGET))    printf "%s -R %c%c" $(GVIMTARGET) '$$' '*' >> $$i;; \
+                       $(DEST_BIN)/$(GVIMDIFFTARGET)) printf "%s -d %c%c" $(GVIMTARGET) '$$' '*' >> $$i;; \
+                       $(DEST_BIN)/$(RGVIMTARGET))    printf "%s -Z %c%c" $(GVIMTARGET) '$$' '*' >> $$i;; \
+                       $(DEST_BIN)/$(RGVIEWTARGET))   printf "%s -Z -R %c%c" $(GVIMTARGET) '$$' '*' >> $$i;; \
+                       *) printf "%s %c%c" $(GVIMTARGET) '$$' '*' >> $$i;; \
+               esac ; \
+               chmod $(BINMOD) $$i ; \
+               addattr -f ~icon.attr  -t \'VICN\' BEOS:ICON $$i ; \
+       done
+       addattr -f ~icon.attr  -t \'VICN\' BEOS:ICON $(DEST_BIN)/$(VIMNAME)tutor
+       @rm ~icon.attr
+
 ###############################################################################
 ### (automatically generated by 'make depend')
 ### Dependencies:
index ff2739c86f85b2680efefa0ab82aa3fbcf4427aa..0a140eed8be445320f81c2bdb981e3fdf83205c8 100755 (executable)
@@ -1501,7 +1501,7 @@ Optional Features:
   --disable-farsi         Deprecated.
   --enable-xim            Include XIM input support.
   --enable-fontset        Include X fontset output support.
-  --enable-gui=OPTS       X11 GUI. default=auto OPTS=auto/no/gtk2/gnome2/gtk3/motif/athena/neXtaw/photon/carbon
+  --enable-gui=OPTS       X11 GUI. default=auto OPTS=auto/no/gtk2/gnome2/gtk3/motif/athena/neXtaw/haiku/photon/carbon
   --enable-gtk2-check     If auto-select GUI, check for GTK+ 2 default=yes
   --enable-gnome-check    If GTK GUI, check for GNOME default=no
   --enable-gtk3-check     If auto-select GUI, check for GTK+ 3 default=yes
@@ -4543,6 +4543,15 @@ $as_echo "yes" >&6; };;
 $as_echo "no" >&6; };;
 esac
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Haiku" >&5
+$as_echo_n "checking for Haiku... " >&6; }
+case `uname` in
+    Haiku) HAIKU=yes; { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; };;
+    *)     HAIKU=no; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; };;
+esac
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for QNX" >&5
 $as_echo_n "checking for QNX... " >&6; }
 case `uname` in
@@ -7714,7 +7723,55 @@ $as_echo "yes" >&6; }
 fi
 
 if test "$enable_channel" = "yes"; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5
+
+  if test "x$HAIKU" = "xyes"; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lnetwork" >&5
+$as_echo_n "checking for socket in -lnetwork... " >&6; }
+if ${ac_cv_lib_network_socket+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnetwork  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char socket ();
+int
+main ()
+{
+return socket ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_network_socket=yes
+else
+  ac_cv_lib_network_socket=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_network_socket" >&5
+$as_echo "$ac_cv_lib_network_socket" >&6; }
+if test "x$ac_cv_lib_network_socket" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBNETWORK 1
+_ACEOF
+
+  LIBS="-lnetwork $LIBS"
+
+fi
+
+  else
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5
 $as_echo_n "checking for socket in -lsocket... " >&6; }
 if ${ac_cv_lib_socket_socket+:} false; then :
   $as_echo_n "(cached) " >&6
@@ -7759,6 +7816,8 @@ _ACEOF
 
 fi
 
+  fi
+
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5
 $as_echo_n "checking for gethostbyname in -lnsl... " >&6; }
 if ${ac_cv_lib_nsl_gethostbyname+:} false; then :
@@ -9034,7 +9093,7 @@ if test "x$with_x" = xno -a "x$with_x_arg" = xyes; then
     as_fn_error $? "could not configure X" "$LINENO" 5
 fi
 
-test "x$with_x" = xno -a "x$MACOS_X" != "xyes" -a "x$QNX" != "xyes" && enable_gui=no
+test "x$with_x" = xno -a "x$HAIKU" != "xyes" -a "x$MACOS_X" != "xyes" -a "x$QNX" != "xyes" && enable_gui=no
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-gui argument" >&5
 $as_echo_n "checking --enable-gui argument... " >&6; }
@@ -9056,10 +9115,27 @@ SKIP_MOTIF=YES
 SKIP_ATHENA=YES
 SKIP_NEXTAW=YES
 SKIP_PHOTON=YES
+SKIP_HAIKU=YES
 SKIP_CARBON=YES
 GUITYPE=NONE
 
-if test "x$QNX" = "xyes" -a "x$with_x" = "xno" ; then
+if test "x$HAIKU" = "xyes"; then
+  SKIP_HAIKU=
+  case "$enable_gui_canon" in
+    no)     { $as_echo "$as_me:${as_lineno-$LINENO}: result: no GUI support" >&5
+$as_echo "no GUI support" >&6; }
+            SKIP_HAIKU=YES ;;
+    yes|"") { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes - automatic GUI support" >&5
+$as_echo "yes - automatic GUI support" >&6; } ;;
+    auto)   { $as_echo "$as_me:${as_lineno-$LINENO}: result: auto - automatic GUI support" >&5
+$as_echo "auto - automatic GUI support" >&6; } ;;
+    haiku)  { $as_echo "$as_me:${as_lineno-$LINENO}: result: Haiku GUI support" >&5
+$as_echo "Haiku GUI support" >&6; } ;;
+    *)      { $as_echo "$as_me:${as_lineno-$LINENO}: result: Sorry, $enable_gui GUI is not supported" >&5
+$as_echo "Sorry, $enable_gui GUI is not supported" >&6; }
+            SKIP_HAIKU=YES ;;
+    esac
+elif test "x$QNX" = "xyes" -a "x$with_x" = "xno" ; then
   SKIP_PHOTON=
   case "$enable_gui_canon" in
     no)                { $as_echo "$as_me:${as_lineno-$LINENO}: result: no GUI support" >&5
@@ -9283,6 +9359,7 @@ $as_echo "yes" >&6; };
   SKIP_ATHENA=YES;
   SKIP_NEXTAW=YES;
   SKIP_PHOTON=YES;
+  SKIP_HAIKU=YES;
   SKIP_CARBON=YES
 fi
 
@@ -10589,6 +10666,10 @@ $as_echo "GTK+ 2 GUI selected; fontset has been disabled" >&6; }
   enable_fontset="no"
 fi
 
+if test -z "$SKIP_HAIKU"; then
+  GUITYPE=HAIKUGUI
+fi
+
 if test -z "$SKIP_PHOTON"; then
   GUITYPE=PHOTONGUI
 fi
index fe2022802b058bcce623c871c180020f261abe86..89ae06f739fff9176b5f2f9246661903c5121bea 100644 (file)
@@ -154,6 +154,12 @@ case `uname` in
     *)         BEOS=no; AC_MSG_RESULT(no);;
 esac
 
+AC_MSG_CHECKING(for Haiku)
+case `uname` in
+    Haiku) HAIKU=yes; AC_MSG_RESULT(yes);;
+    *)     HAIKU=no; AC_MSG_RESULT(no);;
+esac
+
 dnl If QNX is found, assume we don't want to use Xphoton
 dnl unless it was specifically asked for (--with-x)
 AC_MSG_CHECKING(for QNX)
@@ -2033,7 +2039,13 @@ fi
 
 if test "$enable_channel" = "yes"; then
   dnl On Solaris we need the socket and nsl library.
-  AC_CHECK_LIB(socket, socket)
+
+  if test "x$HAIKU" = "xyes"; then
+       AC_CHECK_LIB(network, socket)
+  else
+       AC_CHECK_LIB(socket, socket)
+  fi
+
   AC_CHECK_LIB(nsl, gethostbyname)
   AC_MSG_CHECKING(whether compiling with process communication is possible)
   AC_TRY_LINK([
@@ -2311,11 +2323,11 @@ if test "x$with_x" = xno -a "x$with_x_arg" = xyes; then
     AC_MSG_ERROR([could not configure X])
 fi
 
-test "x$with_x" = xno -a "x$MACOS_X" != "xyes" -a "x$QNX" != "xyes" && enable_gui=no
+test "x$with_x" = xno -a "x$HAIKU" != "xyes" -a "x$MACOS_X" != "xyes" -a "x$QNX" != "xyes" && enable_gui=no
 
 AC_MSG_CHECKING(--enable-gui argument)
 AC_ARG_ENABLE(gui,
- [  --enable-gui[=OPTS]       X11 GUI. [default=auto] [OPTS=auto/no/gtk2/gnome2/gtk3/motif/athena/neXtaw/photon/carbon]], , enable_gui="auto")
+ [  --enable-gui[=OPTS]       X11 GUI. [default=auto] [OPTS=auto/no/gtk2/gnome2/gtk3/motif/athena/neXtaw/haiku/photon/carbon]], , 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.
@@ -2330,10 +2342,22 @@ SKIP_MOTIF=YES
 SKIP_ATHENA=YES
 SKIP_NEXTAW=YES
 SKIP_PHOTON=YES
+SKIP_HAIKU=YES
 SKIP_CARBON=YES
 GUITYPE=NONE
 
-if test "x$QNX" = "xyes" -a "x$with_x" = "xno" ; then
+if test "x$HAIKU" = "xyes"; then
+  SKIP_HAIKU=
+  case "$enable_gui_canon" in
+    no)     AC_MSG_RESULT(no GUI support)
+            SKIP_HAIKU=YES ;;
+    yes|"") AC_MSG_RESULT(yes - automatic GUI support) ;;
+    auto)   AC_MSG_RESULT(auto - automatic GUI support) ;;
+    haiku)  AC_MSG_RESULT(Haiku GUI support) ;;
+    *)      AC_MSG_RESULT([Sorry, $enable_gui GUI is not supported])
+            SKIP_HAIKU=YES ;;
+    esac
+elif test "x$QNX" = "xyes" -a "x$with_x" = "xno" ; then
   SKIP_PHOTON=
   case "$enable_gui_canon" in
     no)                AC_MSG_RESULT(no GUI support)
@@ -2499,6 +2523,7 @@ if test "x$MACOS_X" = "xyes" -a -z "$SKIP_CARBON" -a "x$CARBON" = "xyes"; then
   SKIP_ATHENA=YES;
   SKIP_NEXTAW=YES;
   SKIP_PHOTON=YES;
+  SKIP_HAIKU=YES;
   SKIP_CARBON=YES
 fi
 
@@ -3112,6 +3137,11 @@ if test "x$GUITYPE:$enable_fontset" = "xGTK:yes"; then
   enable_fontset="no"
 fi
 
+dnl There is no test for the Haiku GUI, if it's selected it's used
+if test -z "$SKIP_HAIKU"; then
+  GUITYPE=HAIKUGUI
+fi
+
 if test -z "$SKIP_PHOTON"; then
   GUITYPE=PHOTONGUI
 fi
index cad7a969f9706f652bca19b39becb14694cb9533..ff891eaa940b0be39a6bafc9550762d74e5e742d 100644 (file)
@@ -3264,6 +3264,9 @@ f_has(typval_T *argvars, typval_T *rettv)
 #ifdef __BEOS__
        "beos",
 #endif
+#ifdef __HAIKU__
+       "haiku",
+#endif
 #if defined(BSD) && !defined(MACOS_X)
        "bsd",
 #endif
@@ -3450,6 +3453,9 @@ f_has(typval_T *argvars, typval_T *rettv)
 #ifdef FEAT_GUI_GNOME
        "gui_gnome",
 #endif
+#ifdef FEAT_GUI_HAIKU
+       "gui_haiku",
+#endif
 #ifdef FEAT_GUI_MAC
        "gui_mac",
 #endif
index b25837e1f6b3a6c296331342da84c403212115c6..49175272f89d95126bc52bbf1a868cd972588a12 100644 (file)
  */
 #if defined(FEAT_GUI_MSWIN) && !defined(FEAT_MBYTE_IME)
 // #define FEAT_MBYTE_IME
-# endif
+#endif
+
+#if defined(FEAT_BIG) && defined(FEAT_GUI_HAIKU) && !defined(FEAT_MBYTE_IME)
+# define FEAT_MBYTE_IME
+#endif
 
 // Use iconv() when it's available.
 #if (defined(HAVE_ICONV_H) && defined(HAVE_ICONV)) || defined(DYNAMIC_ICONV)
                || defined(FEAT_GUI_MSWIN) \
                || ((defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)) \
                        && defined(HAVE_XPM)) \
-               || defined(FEAT_GUI_PHOTON))
+               || defined(FEAT_GUI_PHOTON) \
+               || defined(FEAT_GUI_HAIKU))
+
 # define FEAT_TOOLBAR
 #endif
 
     && (defined(FEAT_GUI_GTK) \
        || (defined(FEAT_GUI_MOTIF) && defined(HAVE_XM_NOTEBOOK_H)) \
        || defined(FEAT_GUI_MAC) \
+       || defined(FEAT_GUI_HAIKU) \
        || (defined(FEAT_GUI_MSWIN) \
            && (!defined(_MSC_VER) || _MSC_VER > 1020)))
 # define FEAT_GUI_TABLINE
  */
 #if defined(FEAT_NORMAL)
 # define FEAT_BROWSE_CMD
-# if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
+# if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA) \
+       || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_HAIKU) || defined(FEAT_GUI_PHOTON) \
+       || defined(FEAT_GUI_MAC)
 #  define FEAT_BROWSE
 # endif
 #endif
                && defined(HAVE_X11_XPM_H)) \
        || defined(FEAT_GUI_GTK) \
        || defined(FEAT_GUI_PHOTON) \
+       || defined(FEAT_GUI_HAIKU) \
        || defined(FEAT_GUI_MSWIN) \
        || defined(FEAT_GUI_MAC)
 #  define FEAT_CON_DIALOG
 #if defined(FEAT_GUI_DIALOG) && \
        (defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA) \
         || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_MSWIN) \
-        || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC))
+        || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) \
+        || defined(FEAT_GUI_HAIKU))
 # define FEAT_GUI_TEXTDIALOG
 # ifndef ALWAYS_USE_GUI
 #  define FEAT_CON_DIALOG
index e80009fbe1ef7dba19501edb9503745486ce1d9f..6e66a3e862cdf0d9fa322774f4c80a81e391a3df 100644 (file)
@@ -3367,6 +3367,7 @@ shorten_fnames(int force)
 #if (defined(FEAT_DND) && defined(FEAT_GUI_GTK)) \
        || defined(FEAT_GUI_MSWIN) \
        || defined(FEAT_GUI_MAC) \
+       || defined(FEAT_GUI_HAIKU) \
        || defined(PROTO)
 /*
  * Shorten all filenames in "fnames[count]" by current directory.
@@ -4422,130 +4423,133 @@ readdir_core(
     void       *context,
     int                (*checkitem)(void *context, char_u *name))
 {
-    int                        failed = FALSE;
-# ifdef MSWIN
-    char_u             *buf, *p;
-    int                        ok;
-    HANDLE             hFind = INVALID_HANDLE_VALUE;
-    WIN32_FIND_DATAW    wfb;
-    WCHAR              *wn = NULL;     // UTF-16 name, NULL when not used.
-# endif
+    int                failed = FALSE;
+    char_u     *p;
 
     ga_init2(gap, (int)sizeof(char *), 20);
 
 # ifdef MSWIN
-    buf = alloc(MAXPATHL);
-    if (buf == NULL)
-       return FAIL;
-    STRNCPY(buf, path, MAXPATHL-5);
-    p = buf + STRLEN(buf);
-    MB_PTR_BACK(buf, p);
-    if (*p == '\\' || *p == '/')
-       *p = NUL;
-    STRCAT(buf, "\\*");
-
-    wn = enc_to_utf16(buf, NULL);
-    if (wn != NULL)
-       hFind = FindFirstFileW(wn, &wfb);
-    ok = (hFind != INVALID_HANDLE_VALUE);
-    if (!ok)
     {
-       failed = TRUE;
-       smsg(_(e_notopen), path);
-    }
-    else
-    {
-       while (ok)
+       char_u          *buf;
+       int             ok;
+       HANDLE          hFind = INVALID_HANDLE_VALUE;
+       WIN32_FIND_DATAW    wfb;
+       WCHAR           *wn = NULL;     // UTF-16 name, NULL when not used.
+
+       buf = alloc(MAXPATHL);
+       if (buf == NULL)
+           return FAIL;
+       STRNCPY(buf, path, MAXPATHL-5);
+       p = buf + STRLEN(buf);
+       MB_PTR_BACK(buf, p);
+       if (*p == '\\' || *p == '/')
+           *p = NUL;
+       STRCAT(buf, "\\*");
+
+       wn = enc_to_utf16(buf, NULL);
+       if (wn != NULL)
+           hFind = FindFirstFileW(wn, &wfb);
+       ok = (hFind != INVALID_HANDLE_VALUE);
+       if (!ok)
        {
-           int ignore;
-
-           p = utf16_to_enc(wfb.cFileName, NULL);   // p is allocated here
-           if (p == NULL)
-               break;  // out of memory
-
-           ignore = p[0] == '.' && (p[1] == NUL
-                                             || (p[1] == '.' && p[2] == NUL));
-           if (!ignore && checkitem != NULL)
+           failed = TRUE;
+           smsg(_(e_notopen), path);
+       }
+       else
+       {
+           while (ok)
            {
-               int r = checkitem(context, p);
+               int     ignore;
+
+               p = utf16_to_enc(wfb.cFileName, NULL);   // p is allocated here
+               if (p == NULL)
+                   break;  // out of memory
 
-               if (r < 0)
+               ignore = p[0] == '.' && (p[1] == NUL
+                                                 || (p[1] == '.' && p[2] == NUL));
+               if (!ignore && checkitem != NULL)
                {
-                   vim_free(p);
-                   break;
+                   int r = checkitem(context, p);
+
+                   if (r < 0)
+                   {
+                       vim_free(p);
+                       break;
+                   }
+                   if (r == 0)
+                       ignore = TRUE;
                }
-               if (r == 0)
-                   ignore = TRUE;
-           }
 
-           if (!ignore)
-           {
-               if (ga_grow(gap, 1) == OK)
-                   ((char_u**)gap->ga_data)[gap->ga_len++] = vim_strsave(p);
-               else
+               if (!ignore)
                {
-                   failed = TRUE;
-                   vim_free(p);
-                   break;
+                   if (ga_grow(gap, 1) == OK)
+                       ((char_u**)gap->ga_data)[gap->ga_len++] = vim_strsave(p);
+                   else
+                   {
+                       failed = TRUE;
+                       vim_free(p);
+                       break;
+                   }
                }
-           }
 
-           vim_free(p);
-           ok = FindNextFileW(hFind, &wfb);
+               vim_free(p);
+               ok = FindNextFileW(hFind, &wfb);
+           }
+           FindClose(hFind);
        }
-       FindClose(hFind);
-    }
-
-    vim_free(buf);
-    vim_free(wn);
-# else
-    DIR                *dirp;
-    struct dirent *dp;
-    char_u     *p;
 
-    dirp = opendir((char *)path);
-    if (dirp == NULL)
-    {
-       failed = TRUE;
-       smsg(_(e_notopen), path);
+       vim_free(buf);
+       vim_free(wn);
     }
-    else
+# else
     {
-       for (;;)
-       {
-           int ignore;
-
-           dp = readdir(dirp);
-           if (dp == NULL)
-               break;
-           p = (char_u *)dp->d_name;
+       DIR                     *dirp;
+       struct dirent   *dp;
 
-           ignore = p[0] == '.' &&
-                   (p[1] == NUL ||
-                    (p[1] == '.' && p[2] == NUL));
-           if (!ignore && checkitem != NULL)
+       dirp = opendir((char *)path);
+       if (dirp == NULL)
+       {
+           failed = TRUE;
+           smsg(_(e_notopen), path);
+       }
+       else
+       {
+           for (;;)
            {
-               int r = checkitem(context, p);
+               int     ignore;
 
-               if (r < 0)
+               dp = readdir(dirp);
+               if (dp == NULL)
                    break;
-               if (r == 0)
-                   ignore = TRUE;
-           }
+               p = (char_u *)dp->d_name;
 
-           if (!ignore)
-           {
-               if (ga_grow(gap, 1) == OK)
-                   ((char_u**)gap->ga_data)[gap->ga_len++] = vim_strsave(p);
-               else
+               ignore = p[0] == '.' &&
+                       (p[1] == NUL ||
+                        (p[1] == '.' && p[2] == NUL));
+               if (!ignore && checkitem != NULL)
                {
-                   failed = TRUE;
-                   break;
+                   int r = checkitem(context, p);
+
+                   if (r < 0)
+                       break;
+                   if (r == 0)
+                       ignore = TRUE;
+               }
+
+               if (!ignore)
+               {
+                   if (ga_grow(gap, 1) == OK)
+                       ((char_u**)gap->ga_data)[gap->ga_len++] = vim_strsave(p);
+                   else
+                   {
+                       failed = TRUE;
+                       break;
+                   }
                }
            }
-       }
 
-       closedir(dirp);
+           closedir(dirp);
+       }
     }
 # endif
 
index 6f257484d34034f92a85d10b74a8ecdd9fa64c80..6d3fa1670a5eb5f928970717f3c785c5c5e72b5f 100644 (file)
@@ -1524,7 +1524,7 @@ EXTERN char e_failed[]    INIT(= N_("E472: Command failed"));
 EXTERN char e_fontset[]        INIT(= N_("E234: Unknown fontset: %s"));
 #endif
 #if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_MAC) \
-       || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MSWIN)
+       || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_HAIKU)
 EXTERN char e_font[]           INIT(= N_("E235: Unknown font: %s"));
 #endif
 #if defined(FEAT_GUI_X11) && !defined(FEAT_GUI_GTK)
index 3f2a84ccbf26cb27a08a5a7c144a03454062ec19..4733bad6e412b6d5b6d71c5ea3529a9c31f1a1d2 100644 (file)
--- a/src/gui.c
+++ b/src/gui.c
@@ -446,7 +446,8 @@ gui_init_check(void)
     gui.menu_width = 0;
 # endif
 #endif
-#if defined(FEAT_TOOLBAR) && (defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA))
+#if defined(FEAT_TOOLBAR) && (defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA) \
+       || defined(FEAT_GUI_HAIKU))
     gui.toolbar_height = 0;
 #endif
 #if defined(FEAT_FOOTER) && defined(FEAT_GUI_MOTIF)
@@ -1371,10 +1372,11 @@ gui_position_components(int total_width UNUSED)
        text_area_y += gui.tabline_height;
 #endif
 
-#if defined(FEAT_TOOLBAR) && (defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA))
+#if defined(FEAT_TOOLBAR) && (defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA) \
+       || defined(FEAT_GUI_HAIKU))
     if (vim_strchr(p_go, GO_TOOLBAR) != NULL)
     {
-# ifdef FEAT_GUI_ATHENA
+# if defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_HAIKU)
        gui_mch_set_toolbar_pos(0, text_area_y,
                                gui.menu_width, gui.toolbar_height);
 # endif
@@ -1382,6 +1384,13 @@ gui_position_components(int total_width UNUSED)
     }
 #endif
 
+# if defined(FEAT_GUI_TABLINE) && defined(FEAT_GUI_HAIKU)
+    gui_mch_set_tabline_pos(0, text_area_y,
+    gui.menu_width, gui.tabline_height);
+    if (gui_has_tabline())
+       text_area_y += gui.tabline_height;
+#endif
+
     text_area_width = gui.num_cols * gui.char_width + gui.border_offset * 2;
     text_area_height = gui.num_rows * gui.char_height + gui.border_offset * 2;
 
@@ -1453,7 +1462,7 @@ gui_get_base_height(void)
 #  endif
 # endif
 # if defined(FEAT_GUI_TABLINE) && (defined(FEAT_GUI_MSWIN) \
-       || defined(FEAT_GUI_MOTIF))
+       || defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_HAIKU))
     if (gui_has_tabline())
        base_height += gui.tabline_height;
 # endif
@@ -1496,6 +1505,10 @@ again:
     new_pixel_height = 0;
     busy = TRUE;
 
+#ifdef FEAT_GUI_HAIKU
+    vim_lock_screen();
+#endif
+
     // Flush pending output before redrawing
     out_flush();
 
@@ -1518,6 +1531,10 @@ again:
            || gui.num_rows != Rows || gui.num_cols != Columns)
        shell_resized();
 
+#ifdef FEAT_GUI_HAIKU
+    vim_unlock_screen();
+#endif
+
     gui_update_scrollbars(TRUE);
     gui_update_cursor(FALSE, TRUE);
 #if defined(FEAT_XIM) && !defined(FEAT_GUI_GTK)
@@ -4254,9 +4271,10 @@ gui_update_scrollbars(
                y += gui.menu_height;
 #endif
 
-#if defined(FEAT_TOOLBAR) && (defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_ATHENA))
+#if defined(FEAT_TOOLBAR) && (defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_ATHENA) \
+       || defined(FEAT_GUI_HAIKU))
            if (vim_strchr(p_go, GO_TOOLBAR) != NULL)
-# ifdef FEAT_GUI_ATHENA
+# if defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_HAIKU)
                y += gui.toolbar_height;
 # else
 #  ifdef FEAT_GUI_MSWIN
@@ -4265,7 +4283,7 @@ gui_update_scrollbars(
 # endif
 #endif
 
-#if defined(FEAT_GUI_TABLINE) && defined(FEAT_GUI_MSWIN)
+#if defined(FEAT_GUI_TABLINE) && defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_HAIKU)
            if (gui_has_tabline())
                y += gui.tabline_height;
 #endif
@@ -5035,10 +5053,11 @@ ex_gui(exarg_T *eap)
 }
 
 #if ((defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK) \
-           || defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_PHOTON)) \
+           || defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_PHOTON) \
+           || defined(FEAT_GUI_HAIKU)) \
            && defined(FEAT_TOOLBAR)) || defined(PROTO)
 /*
- * This is shared between Athena, Motif and GTK.
+ * This is shared between Athena, Haiku, Motif, and GTK.
  */
 
 /*
index c107ec88be656533281037e1a306d51b0890c129..cfc4448168ac859a43cbd091de5f1f411151e8ba 100644 (file)
--- a/src/gui.h
+++ b/src/gui.h
 # include <gtk/gtk.h>
 #endif
 
+#ifdef FEAT_GUI_HAIKU
+# include "gui_haiku.h"
+#endif
+
 // Needed when generating prototypes, since FEAT_GUI is always defined then.
 #if defined(FEAT_XCLIPBOARD) && !defined(FEAT_GUI_MOTIF) \
        && !defined(FEAT_GUI_ATHENA) && !defined(FEAT_GUI_GTK)
@@ -73,7 +77,8 @@
  */
 #if (defined(FEAT_DND) && defined(FEAT_GUI_GTK)) \
        || defined(FEAT_GUI_MSWIN) \
-       || defined(FEAT_GUI_MAC)
+       || defined(FEAT_GUI_MAC) \
+       || defined(FEAT_GUI_HAIKU)
 # define HAVE_DROP_FILE
 #endif
 
@@ -200,6 +205,10 @@ typedef struct GuiScrollbar
                                // scroll_shift is set to the number of shifts
                                // to reduce the count.
 #endif
+
+#if FEAT_GUI_HAIKU
+    VimScrollBar *id;          // Pointer to real scroll bar
+#endif
 #ifdef FEAT_GUI_MAC
     ControlHandle id;          // A handle to the scrollbar
 #endif
@@ -426,7 +435,7 @@ typedef struct Gui
 
 #if defined(FEAT_GUI_TABLINE) \
        && (defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_MOTIF) \
-               || defined(FEAT_GUI_MAC))
+               || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_HAIKU))
     int                tabline_height;
 #endif
 
@@ -435,7 +444,7 @@ typedef struct Gui
 #endif
 
 #if defined(FEAT_TOOLBAR) \
-       && (defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MOTIF))
+       && (defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_HAIKU))
     int                toolbar_height;     // height of the toolbar
 #endif
 
@@ -456,6 +465,14 @@ typedef struct Gui
     guicolor_T currSpColor;        // Current special text color
 #endif
 
+#ifdef FEAT_GUI_HAIKU
+    VimApp     *vimApp;
+    VimWindow  *vimWindow;
+    VimFormView *vimForm;
+    VimTextAreaView *vimTextArea;
+    int        vdcmp;                      // Vim Direct Communication Message Port
+#endif
+
 #ifdef FEAT_GUI_MAC
     WindowPtr  VimWindow;
     MenuHandle MacOSHelpMenu;      // Help menu provided by the MacOS
diff --git a/src/gui_haiku.cc b/src/gui_haiku.cc
new file mode 100644 (file)
index 0000000..b7ecf64
--- /dev/null
@@ -0,0 +1,5242 @@
+/* vi:set ts=8 sts=4 sw=4:
+ *
+ * VIM - Vi IMproved   by Bram Moolenaar
+ *    BeBox GUI support Copyright 1998 by Olaf Seibert.
+ *                  All Rights Reserved.
+ *
+ * Do ":help uganda"  in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ *
+ * Based on "GUI support for the Buzzword Enhanced Operating System."
+ *
+ * Ported to R4 by Richard Offer <richard@whitequeen.com> Jul 99
+ *
+ * Haiku support by Siarzhuk Zharski <imker@gmx.li> Apr-Mai 2009
+ *
+ */
+
+/*
+ * Structure of the Haiku GUI code:
+ *
+ * There are 3 threads.
+ * 1. The initial thread. In gui_mch_prepare() this gets to run the
+ *    BApplication message loop. But before it starts doing that,
+ *    it creates thread 2
+ * 2. The main() thread. This thread is created in gui_mch_prepare()
+ *    and its purpose in life is to call main(argc, argv) again.
+ *    This thread is doing the bulk of the work.
+ * 3. Sooner or later, a window is opened by the main() thread. This
+ *    causes a second message loop to be created: the window thread.
+ *
+ * == alternatively ===
+ *
+ * #if RUN_BAPPLICATION_IN_NEW_THREAD...
+ *
+ * 1. The initial thread. In gui_mch_prepare() this gets to spawn
+ *    thread 2. After doing that, it returns to main() to do the
+ *    bulk of the work, being the main() thread.
+ * 2. Runs the BApplication.
+ * 3. The window thread, just like in the first case.
+ *
+ * This second alternative is cleaner from Vim's viewpoint. However,
+ * the BeBook seems to assume everywhere that the BApplication *must*
+ * run in the initial thread. So perhaps doing otherwise is very wrong.
+ *
+ * However, from a B_SINGLE_LAUNCH viewpoint, the first is better.
+ * If Vim is marked "Single Launch" in its application resources,
+ * and a file is dropped on the Vim icon, and another Vim is already
+ * running, the file is passed on to the earlier Vim. This happens
+ * in BApplication::Run(). So we want Vim to terminate if
+ * BApplication::Run() terminates. (See the BeBook, on BApplication.
+ * However, it seems that the second copy of Vim isn't even started
+ * in this case... which is for the better since I wouldn't know how
+ * to detect this case.)
+ *
+ * Communication between these threads occurs mostly by translating
+ * BMessages that come in and posting an appropriate translation on
+ * the VDCMP (Vim Direct Communication Message Port). Therefore the
+ * actions required for keypresses and window resizes, etc, are mostly
+ * performed in the main() thread.
+ *
+ * A notable exception to this is the Draw() event. The redrawing of
+ * the window contents is performed asynchronously from the window
+ * thread. To make this work correctly, a locking protocol is used when
+ * any thread is accessing the essential variables that are used by
+ * the window thread.
+ *
+ * This locking protocol consists of locking Vim's window. This is both
+ * convenient and necessary.
+ */
+
+extern "C" {
+
+#include <assert.h>
+#include <float.h>
+#include <syslog.h>
+
+#include "vim.h"
+#include "globals.h"
+#include "proto.h"
+#include "version.h"
+
+}      // extern "C"
+
+// ---------------- start of header part ----------------
+
+//#include <Alert.h>
+#include <Application.h>
+#include <Beep.h>
+#include <Bitmap.h>
+#include <Box.h>
+#include <Button.h>
+#include <Clipboard.h>
+#include <Debug.h>
+//#include <Directory.h>
+//#include <Entry.h>
+#include <File.h>
+#include <FilePanel.h>
+#include <FindDirectory.h>
+//#include <Font.h>
+#include <IconUtils.h>
+#include <Input.h>
+#include <ListView.h>
+#include <MenuBar.h>
+#include <MenuItem.h>
+//#include <MessageQueue.h>
+//#include <OS.h>
+#include <Path.h>
+#include <PictureButton.h>
+#include <PopUpMenu.h>
+//#include <Region.h>
+#include <Resources.h>
+//#include <Roster.h>
+#include <Screen.h>
+#include <ScrollBar.h>
+#include <ScrollView.h>
+#include <String.h>
+#include <StringView.h>
+//#include <SupportDefs.h>
+#include <TabView.h>
+#include <TextControl.h>
+#include <TextView.h>
+#include <TranslationUtils.h>
+#include <TranslatorFormats.h>
+#include <View.h>
+#include <Window.h>
+
+class VimApp;
+class VimFormView;
+class VimTextAreaView;
+class VimWindow;
+class VimToolbar;
+class VimTabLine;
+
+extern key_map *keyMap;
+extern char *keyMapChars;
+
+extern int main(int argc, char **argv);
+
+#ifndef B_MAX_PORT_COUNT
+#define B_MAX_PORT_COUNT    255
+#endif
+
+// VimApp seems comparable to the X "vimShell"
+class VimApp: public BApplication
+{
+       typedef BApplication Inherited;
+       public:
+       VimApp(const char *appsig);
+       ~VimApp();
+
+       // callbacks:
+#if 0
+       virtual void DispatchMessage(BMessage *m, BHandler *h)
+       {
+               m->PrintToStream();
+               Inherited::DispatchMessage(m, h);
+       }
+#endif
+       virtual void ReadyToRun();
+       virtual void ArgvReceived(int32 argc, char **argv);
+       virtual void RefsReceived(BMessage *m);
+       virtual bool QuitRequested();
+       virtual void MessageReceived(BMessage *m);
+
+       static void SendRefs(BMessage *m, bool changedir);
+
+       sem_id          fFilePanelSem;
+       BFilePanel*     fFilePanel;
+       BPath           fBrowsedPath;
+       private:
+};
+
+class VimWindow: public BWindow
+{
+       typedef BWindow Inherited;
+       public:
+       VimWindow();
+       ~VimWindow();
+
+       //    virtual void DispatchMessage(BMessage *m, BHandler *h);
+       virtual void WindowActivated(bool active);
+       virtual bool QuitRequested();
+
+       VimFormView             *formView;
+
+       private:
+       void init();
+
+};
+
+class VimFormView: public BView
+{
+       typedef BView Inherited;
+       public:
+       VimFormView(BRect frame);
+       ~VimFormView();
+
+       // callbacks:
+       virtual void AllAttached();
+       virtual void FrameResized(float new_width, float new_height);
+
+#define MENUBAR_MARGIN 1
+       float MenuHeight() const
+       { return menuBar ? menuBar->Frame().Height() + MENUBAR_MARGIN: 0; }
+       BMenuBar *MenuBar() const
+       { return menuBar; }
+
+       private:
+       void init(BRect);
+
+       BMenuBar                *menuBar;
+       VimTextAreaView *textArea;
+
+#ifdef FEAT_TOOLBAR
+       public:
+       float ToolbarHeight() const;
+       VimToolbar *ToolBar() const
+       { return toolBar; }
+       private:
+       VimToolbar              *toolBar;
+#endif
+
+#ifdef FEAT_GUI_TABLINE
+       public:
+       VimTabLine *TabLine() const     { return tabLine; }
+       bool IsShowingTabLine() const { return showingTabLine; }
+       void SetShowingTabLine(bool showing) { showingTabLine = showing;        }
+       float TablineHeight() const;
+       private:
+       VimTabLine      *tabLine;
+       int     showingTabLine;
+#endif
+};
+
+class VimTextAreaView: public BView
+{
+       typedef BView Inherited;
+       public:
+       VimTextAreaView(BRect frame);
+       ~VimTextAreaView();
+
+       // callbacks:
+       virtual void Draw(BRect updateRect);
+       virtual void KeyDown(const char *bytes, int32 numBytes);
+       virtual void MouseDown(BPoint point);
+       virtual void MouseUp(BPoint point);
+       virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *message);
+       virtual void MessageReceived(BMessage *m);
+
+       // own functions:
+       int mchInitFont(char_u *name);
+       void mchDrawString(int row, int col, char_u *s, int len, int flags);
+       void mchClearBlock(int row1, int col1, int row2, int col2);
+       void mchClearAll();
+       void mchDeleteLines(int row, int num_lines);
+       void mchInsertLines(int row, int num_lines);
+
+       static void guiSendMouseEvent(int button, int x, int y, int repeated_click, int_u modifiers);
+       static void guiMouseMoved(int x, int y);
+       static void guiBlankMouse(bool should_hide);
+       static int_u mouseModifiersToVim(int32 beModifiers);
+
+       int32 mouseDragEventCount;
+
+#ifdef FEAT_MBYTE_IME
+       void DrawIMString(void);
+#endif
+
+       private:
+       void init(BRect);
+
+       int_u       vimMouseButton;
+       int_u       vimMouseModifiers;
+
+#ifdef FEAT_MBYTE_IME
+       struct {
+               BMessenger* messenger;
+               BMessage* message;
+               BPoint location;
+               int row;
+               int col;
+               int count;
+       } IMData;
+#endif
+};
+
+class VimScrollBar: public BScrollBar
+{
+       typedef BScrollBar Inherited;
+       public:
+       VimScrollBar(scrollbar_T *gsb, orientation posture);
+       ~VimScrollBar();
+
+       virtual void ValueChanged(float newValue);
+       virtual void MouseUp(BPoint where);
+       void SetValue(float newval);
+       scrollbar_T *getGsb()
+       { return gsb; }
+
+       int32       scrollEventCount;
+
+       private:
+       scrollbar_T *gsb;
+       float   ignoreValue;
+};
+
+
+#ifdef FEAT_TOOLBAR
+
+class VimToolbar : public BBox
+{
+       static BBitmap *normalButtonsBitmap;
+       static BBitmap *grayedButtonsBitmap;
+
+       BBitmap *LoadVimBitmap(const char* fileName);
+       bool GetPictureFromBitmap(BPicture *pictureTo, int32 index, BBitmap *bitmapFrom, bool pressed);
+       bool ModifyBitmapToGrayed(BBitmap *bitmap);
+
+       BList fButtonsList;
+       void InvalidateLayout();
+
+       public:
+       VimToolbar(BRect frame, const char * name);
+       ~VimToolbar();
+
+       bool PrepareButtonBitmaps();
+
+       bool AddButton(int32 index, vimmenu_T *menu);
+       bool RemoveButton(vimmenu_T *menu);
+       bool GrayButton(vimmenu_T *menu, int grey);
+
+       float ToolbarHeight() const;
+       virtual void AttachedToWindow();
+};
+
+BBitmap *VimToolbar::normalButtonsBitmap  = NULL;
+BBitmap *VimToolbar::grayedButtonsBitmap  = NULL;
+
+const float ToolbarMargin = 3.;
+const float ButtonMargin  = 3.;
+
+#endif //FEAT_TOOLBAR
+
+#ifdef FEAT_GUI_TABLINE
+
+class VimTabLine : public BTabView
+{
+       public:
+               class VimTab : public BTab {
+                       public:
+                               VimTab() : BTab(new BView(BRect(), "-Empty-", 0, 0)) {}
+
+                       virtual void Select(BView* owner);
+               };
+
+               VimTabLine(BRect r) : BTabView(r, "vimTabLine", B_WIDTH_FROM_LABEL,
+                          B_FOLLOW_LEFT | B_FOLLOW_TOP | B_FOLLOW_RIGHT, B_WILL_DRAW | B_FRAME_EVENTS) {}
+
+       float TablineHeight() const;
+       virtual void MouseDown(BPoint point);
+};
+
+#endif //FEAT_GUI_TABLINE
+
+
+// For caching the fonts that are used;
+// Vim seems rather sloppy in this regard.
+class VimFont: public BFont
+{
+       typedef BFont Inherited;
+       public:
+       VimFont();
+       VimFont(const VimFont *rhs);
+       VimFont(const BFont *rhs);
+       VimFont(const VimFont &rhs);
+       ~VimFont();
+
+       VimFont *next;
+       int refcount;
+       char_u *name;
+
+       private:
+       void init();
+};
+
+#if defined(FEAT_GUI_DIALOG)
+
+class VimDialog : public BWindow
+{
+       typedef BWindow Inherited;
+
+       BButton* _CreateButton(int32 which, const char* label);
+
+       public:
+
+       class View : public BView {
+               typedef BView Inherited;
+
+               public:
+               View(BRect frame);
+               ~View();
+
+               virtual void Draw(BRect updateRect);
+               void InitIcon(int32 type);
+
+               private:
+               BBitmap*        fIconBitmap;
+       };
+
+       VimDialog(int type, const char *title, const char *message,
+                       const char *buttons, int dfltbutton, const char *textfield,
+                       int ex_cmd);
+       ~VimDialog();
+
+       int Go();
+
+       virtual void MessageReceived(BMessage *msg);
+
+       private:
+       sem_id                  fDialogSem;
+       int                             fDialogValue;
+       BList                   fButtonsList;
+       BTextView*              fMessageView;
+       BTextControl*   fInputControl;
+       const char*             fInputValue;
+};
+
+class VimSelectFontDialog : public BWindow
+{
+       typedef BWindow Inherited;
+
+       void _CleanList(BListView* list);
+       void _UpdateFontStyles();
+       void _UpdateSizeInputPreview();
+       void _UpdateFontPreview();
+       bool _UpdateFromListItem(BListView* list, char* text, int textSize);
+       public:
+
+       VimSelectFontDialog(font_family* family, font_style* style, float* size);
+       ~VimSelectFontDialog();
+
+       bool Go();
+
+       virtual void MessageReceived(BMessage *msg);
+
+       private:
+       status_t                fStatus;
+       sem_id                  fDialogSem;
+       bool                    fDialogValue;
+       font_family*    fFamily;
+       font_style*             fStyle;
+       float*                  fSize;
+       font_family             fFontFamily;
+       font_style              fFontStyle;
+       float                   fFontSize;
+       BStringView*    fPreview;
+       BListView*              fFamiliesList;
+       BListView*              fStylesList;
+       BListView*              fSizesList;
+       BTextControl*   fSizesInput;
+};
+
+#endif // FEAT_GUI_DIALOG
+
+// ---------------- end of GUI classes ----------------
+
+struct MainArgs {
+       int              argc;
+       char    **argv;
+};
+
+// These messages are copied through the VDCMP.
+// Therefore they ought not to have anything fancy.
+// They must be of POD type (Plain Old Data)
+// as the C++ standard calls them.
+
+#define        KEY_MSG_BUFSIZ  7
+#if KEY_MSG_BUFSIZ < MAX_KEY_CODE_LEN
+#error Increase KEY_MSG_BUFSIZ!
+#endif
+
+struct VimKeyMsg {
+       char_u  length;
+       char_u  chars[KEY_MSG_BUFSIZ];  // contains Vim encoding
+       bool    csi_escape;
+};
+
+struct VimResizeMsg {
+       int             width;
+       int             height;
+};
+
+struct VimScrollBarMsg {
+       VimScrollBar *sb;
+       long    value;
+       int             stillDragging;
+};
+
+struct VimMenuMsg {
+       vimmenu_T       *guiMenu;
+};
+
+struct VimMouseMsg {
+       int             button;
+       int             x;
+       int             y;
+       int             repeated_click;
+       int_u   modifiers;
+};
+
+struct VimMouseMovedMsg {
+       int             x;
+       int             y;
+};
+
+struct VimFocusMsg {
+       bool    active;
+};
+
+struct VimRefsMsg {
+       BMessage   *message;
+       bool    changedir;
+};
+
+struct VimTablineMsg {
+       int             index;
+};
+
+struct VimTablineMenuMsg {
+       int             index;
+       int             event;
+};
+
+struct VimMsg {
+       enum VimMsgType {
+               Key, Resize, ScrollBar, Menu, Mouse, MouseMoved, Focus, Refs, Tabline, TablineMenu
+       };
+
+       union {
+               struct VimKeyMsg        Key;
+               struct VimResizeMsg     NewSize;
+               struct VimScrollBarMsg  Scroll;
+               struct VimMenuMsg       Menu;
+               struct VimMouseMsg      Mouse;
+               struct VimMouseMovedMsg MouseMoved;
+               struct VimFocusMsg      Focus;
+               struct VimRefsMsg       Refs;
+               struct VimTablineMsg    Tabline;
+               struct VimTablineMenuMsg        TablineMenu;
+       } u;
+};
+
+#define RGB(r, g, b)   ((char_u)(r) << 16 | (char_u)(g) << 8 | (char_u)(b) << 0)
+#define GUI_TO_RGB(g)  { (g) >> 16, (g) >> 8, (g) >> 0, 255 }
+
+// ---------------- end of header part ----------------
+
+static struct specialkey
+{
+       uint16  BeKeys;
+#define KEY(a,b)       ((a)<<8|(b))
+#define K(a)           KEY(0,a)                    // for ASCII codes
+#define F(b)           KEY(1,b)                    // for scancodes
+       char_u  vim_code0;
+       char_u  vim_code1;
+} special_keys[] =
+{
+       {K(B_UP_ARROW),     'k', 'u'},
+       {K(B_DOWN_ARROW),           'k', 'd'},
+       {K(B_LEFT_ARROW),           'k', 'l'},
+       {K(B_RIGHT_ARROW),          'k', 'r'},
+       {K(B_BACKSPACE),            'k', 'b'},
+       {K(B_INSERT),       'k', 'I'},
+       {K(B_DELETE),       'k', 'D'},
+       {K(B_HOME),                 'k', 'h'},
+       {K(B_END),                  '@', '7'},
+       {K(B_PAGE_UP),      'k', 'P'},      // XK_Prior
+       {K(B_PAGE_DOWN),            'k', 'N'},      // XK_Next,
+
+#define FIRST_FUNCTION_KEY  11
+       {F(B_F1_KEY),       'k', '1'},
+       {F(B_F2_KEY),       'k', '2'},
+       {F(B_F3_KEY),       'k', '3'},
+       {F(B_F4_KEY),       'k', '4'},
+       {F(B_F5_KEY),       'k', '5'},
+       {F(B_F6_KEY),       'k', '6'},
+       {F(B_F7_KEY),       'k', '7'},
+       {F(B_F8_KEY),       'k', '8'},
+       {F(B_F9_KEY),       'k', '9'},
+       {F(B_F10_KEY),      'k', ';'},
+
+       {F(B_F11_KEY),      'F', '1'},
+       {F(B_F12_KEY),      'F', '2'},
+       //  {XK_F13,                'F', '3'},  // would be print screen
+       // sysreq
+       {F(0x0F),                   'F', '4'},          // scroll lock
+       {F(0x10),                   'F', '5'},          // pause/break
+       //  {XK_F16,        'F', '6'},
+       //  {XK_F17,        'F', '7'},
+       //  {XK_F18,        'F', '8'},
+       //  {XK_F19,        'F', '9'},
+       //   {XK_F20,       'F', 'A'},
+       //  {XK_F21,        'F', 'B'},
+       //  {XK_F22,        'F', 'C'},
+       //  {XK_F23,        'F', 'D'},
+       //  {XK_F24,        'F', 'E'},
+       //  {XK_F25,        'F', 'F'},
+       //  {XK_F26,        'F', 'G'},
+       //  {XK_F27,        'F', 'H'},
+       //  {XK_F28,        'F', 'I'},
+       //  {XK_F29,        'F', 'J'},
+       //  {XK_F30,        'F', 'K'},
+       //  {XK_F31,        'F', 'L'},
+       //  {XK_F32,        'F', 'M'},
+       //  {XK_F33,        'F', 'N'},
+       //  {XK_F34,        'F', 'O'},
+       //  {XK_F35,        'F', 'P'},      // keysymdef.h defines up to F35
+
+       //  {XK_Help,       '%', '1'},      // XK_Help
+       {F(B_PRINT_KEY),            '%', '9'},
+
+#if 0
+       // Keypad keys:
+       {F(0x48),           'k', 'l'},      // XK_KP_Left
+       {F(0x4A),           'k', 'r'},      // XK_KP_Right
+       {F(0x38),           'k', 'u'},      // XK_KP_Up
+       {F(0x59),           'k', 'd'},      // XK_KP_Down
+       {F(0x64),           'k', 'I'},      // XK_KP_Insert
+       {F(0x65),           'k', 'D'},      // XK_KP_Delete
+       {F(0x37),           'k', 'h'},      // XK_KP_Home
+       {F(0x58),           '@', '7'},      // XK_KP_End
+       {F(0x39),           'k', 'P'},      // XK_KP_Prior
+       {F(0x60),           'k', 'N'},      // XK_KP_Next
+       {F(0x49),           '&', '8'},      // XK_Undo, keypad 5
+#endif
+
+       // End of list marker:
+       {0,                         0, 0}
+};
+
+#define NUM_SPECIAL_KEYS    (sizeof(special_keys)/sizeof(special_keys[0]))
+
+// ---------------- VimApp ----------------
+
+       static void
+docd(BPath &path)
+{
+       mch_chdir((char *)path.Path());
+       // Do this to get the side effects of a :cd command
+       do_cmdline_cmd((char_u *)"cd .");
+}
+
+        static void
+drop_callback(void *cookie)
+{
+    // TODO here we could handle going to a specific position in the dropped
+    // file (see src/gui_mac.c)
+    // Update the screen display
+    update_screen(NOT_VALID);
+}
+
+    // Really handle dropped files and folders.
+        static void
+RefsReceived(BMessage *m, bool changedir)
+{
+       uint32 type;
+       int32 count;
+
+       m->PrintToStream();
+       switch (m->what) {
+               case B_REFS_RECEIVED:
+               case B_SIMPLE_DATA:
+                       m->GetInfo("refs", &type, &count);
+                       if (type != B_REF_TYPE)
+                               goto bad;
+                       break;
+               case B_ARGV_RECEIVED:
+                       m->GetInfo("argv", &type, &count);
+                       if (type != B_STRING_TYPE)
+                               goto bad;
+                       if (changedir) {
+                               char *dirname;
+                               if (m->FindString("cwd", (const char **) &dirname) == B_OK) {
+                                       chdir(dirname);
+                                       do_cmdline_cmd((char_u *)"cd .");
+                               }
+                       }
+                       break;
+               default:
+bad:
+                       /*fprintf(stderr, "bad!\n"); */
+                       delete m;
+                       return;
+       }
+
+#ifdef FEAT_VISUAL
+       reset_VIsual();
+#endif
+
+       char_u  **fnames;
+       fnames = (char_u **) alloc(count * sizeof(char_u *));
+       int fname_index = 0;
+
+       switch (m->what) {
+               case B_REFS_RECEIVED:
+               case B_SIMPLE_DATA:
+                       // fprintf(stderr, "case B_REFS_RECEIVED\n");
+                       for (int i = 0; i < count; ++i)
+                       {
+                               entry_ref ref;
+                               if (m->FindRef("refs", i, &ref) == B_OK) {
+                                       BEntry entry(&ref, false);
+                                       BPath path;
+                                       entry.GetPath(&path);
+
+                                       // Change to parent directory?
+                                       if (changedir) {
+                                               BPath parentpath;
+                                               path.GetParent(&parentpath);
+                                               docd(parentpath);
+                                       }
+
+                                       // Is it a directory? If so, cd into it.
+                                       BDirectory bdir(&ref);
+                                       if (bdir.InitCheck() == B_OK) {
+                                               // don't cd if we already did it
+                                               if (!changedir)
+                                                       docd(path);
+                                       } else {
+                                               mch_dirname(IObuff, IOSIZE);
+                                               char_u *fname = shorten_fname((char_u *)path.Path(), IObuff);
+                                               if (fname == NULL)
+                                                       fname = (char_u *)path.Path();
+                                               fnames[fname_index++] = vim_strsave(fname);
+                                               // fprintf(stderr, "%s\n", fname);
+                                       }
+
+                                       // Only do it for the first file/dir
+                                       changedir = false;
+                               }
+                       }
+                       break;
+               case B_ARGV_RECEIVED:
+                       // fprintf(stderr, "case B_ARGV_RECEIVED\n");
+                       for (int i = 1; i < count; ++i)
+                       {
+                               char *fname;
+
+                               if (m->FindString("argv", i, (const char **) &fname) == B_OK) {
+                                       fnames[fname_index++] = vim_strsave((char_u *)fname);
+                               }
+                       }
+                       break;
+               default:
+                       // fprintf(stderr, "case default\n");
+                       break;
+       }
+
+       delete m;
+
+       // Handle the drop, :edit to get to the file
+       if (fname_index > 0) {
+               handle_drop(fname_index, fnames, FALSE, drop_callback, NULL);
+
+               setcursor();
+               out_flush();
+       } else {
+               vim_free(fnames);
+       }
+}
+
+VimApp::VimApp(const char *appsig):
+       BApplication(appsig),
+       fFilePanelSem(-1),
+       fFilePanel(NULL)
+{
+}
+
+VimApp::~VimApp()
+{
+}
+
+       void
+VimApp::ReadyToRun()
+{
+       /*
+        * Apparently signals are inherited by the created thread -
+        * disable the most annoying ones.
+        */
+       signal(SIGINT, SIG_IGN);
+       signal(SIGQUIT, SIG_IGN);
+}
+
+       void
+VimApp::ArgvReceived(int32 arg_argc, char **arg_argv)
+{
+       if (!IsLaunching()) {
+               /*
+                * This can happen if we are set to Single or Exclusive
+                * Launch. Be nice and open the file(s).
+                */
+               if (gui.vimWindow)
+                       gui.vimWindow->Minimize(false);
+               BMessage *m = CurrentMessage();
+               DetachCurrentMessage();
+               SendRefs(m, true);
+       }
+}
+
+       void
+VimApp::RefsReceived(BMessage *m)
+{
+       // Horrible hack!!! XXX XXX XXX
+       // The real problem is that b_start_ffc is set too late for
+       // the initial empty buffer. As a result the window will be
+       // split instead of abandoned.
+       int limit = 15;
+       while (--limit >= 0 && (curbuf == NULL || curbuf->b_start_ffc == 0))
+               snooze(100000);    //  0.1 s
+       if (gui.vimWindow)
+               gui.vimWindow->Minimize(false);
+       DetachCurrentMessage();
+       SendRefs(m, true);
+}
+
+/*
+ * Pass a BMessage on to the main() thread.
+ * Caller must have detached the message.
+ */
+       void
+VimApp::SendRefs(BMessage *m, bool changedir)
+{
+       VimRefsMsg rm;
+       rm.message = m;
+       rm.changedir = changedir;
+
+       write_port(gui.vdcmp, VimMsg::Refs, &rm, sizeof(rm));
+       //  calls ::RefsReceived
+}
+
+       void
+VimApp::MessageReceived(BMessage *m)
+{
+       switch (m->what) {
+               case 'save':
+                       {
+                               entry_ref refDirectory;
+                               m->FindRef("directory", &refDirectory);
+                               fBrowsedPath.SetTo(&refDirectory);
+                               BString strName;
+                               m->FindString("name", &strName);
+                               fBrowsedPath.Append(strName.String());
+                       }
+                       break;
+               case 'open':
+                       {
+                               entry_ref ref;
+                               m->FindRef("refs", &ref);
+                               fBrowsedPath.SetTo(&ref);
+                       }
+                       break;
+               case B_CANCEL:
+                       {
+                               BFilePanel *panel;
+                               m->FindPointer("source", (void**)&panel);
+                               if(fFilePanelSem != -1 && panel == fFilePanel)
+                               {
+                                       delete_sem(fFilePanelSem);
+                                       fFilePanelSem = -1;
+                               }
+
+                       }
+                       break;
+               default:
+                       Inherited::MessageReceived(m);
+                       break;
+       }
+}
+
+       bool
+VimApp::QuitRequested()
+{
+       (void)Inherited::QuitRequested();
+       return false;
+}
+
+// ---------------- VimWindow ----------------
+
+VimWindow::VimWindow():
+       BWindow(BRect(40, 40, 150, 150),
+                       "Vim",
+                       B_TITLED_WINDOW,
+                       0,
+                       B_CURRENT_WORKSPACE)
+
+{
+       init();
+}
+
+VimWindow::~VimWindow()
+{
+       if (formView) {
+               RemoveChild(formView);
+               delete formView;
+       }
+       gui.vimWindow = NULL;
+}
+
+       void
+VimWindow::init()
+{
+       // Attach the VimFormView
+       formView = new VimFormView(Bounds());
+       if (formView != NULL) {
+               AddChild(formView);
+       }
+}
+
+#if 0  //  disabled in zeta patch
+       void
+VimWindow::DispatchMessage(BMessage *m, BHandler *h)
+{
+       /*
+        * Route B_MOUSE_UP messages to MouseUp(), in
+        * a manner that should be compatible with the
+        * intended future system behaviour.
+        */
+       switch (m->what) {
+               case B_MOUSE_UP:
+                       //  if (!h) h = PreferredHandler();
+                       //  gcc isn't happy without this extra set of braces, complains about
+                       //  jump to case label crosses init of 'class BView * v'
+                       //  richard@whitequeen.com jul 99
+                       {
+                               BView *v = dynamic_cast<BView *>(h);
+                               if (v) {
+                                       // m->PrintToStream();
+                                       BPoint where;
+                                       m->FindPoint("where", &where);
+                                       v->MouseUp(where);
+                               } else {
+                                       Inherited::DispatchMessage(m, h);
+                               }
+                       }
+                       break;
+               default:
+                       Inherited::DispatchMessage(m, h);
+       }
+}
+#endif
+
+       void
+VimWindow::WindowActivated(bool active)
+{
+       Inherited::WindowActivated(active);
+       // the textArea gets the keyboard action
+       if (active && gui.vimTextArea)
+               gui.vimTextArea->MakeFocus(true);
+
+       struct VimFocusMsg fm;
+       fm.active = active;
+
+       write_port(gui.vdcmp, VimMsg::Focus, &fm, sizeof(fm));
+}
+
+       bool
+VimWindow::QuitRequested()
+{
+       struct VimKeyMsg km;
+       km.length = 5;
+       memcpy((char *)km.chars, "\033:qa\r", km.length);
+       km.csi_escape = false;
+       write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km));
+       return false;
+}
+
+// ---------------- VimFormView ----------------
+
+VimFormView::VimFormView(BRect frame):
+       BView(frame, "VimFormView", B_FOLLOW_ALL_SIDES,
+                       B_WILL_DRAW | B_FRAME_EVENTS),
+       menuBar(NULL),
+#ifdef FEAT_TOOLBAR
+       toolBar(NULL),
+#endif
+#ifdef FEAT_GUI_TABLINE
+//     showingTabLine(false),
+       tabLine(NULL),
+#endif
+       textArea(NULL)
+{
+       init(frame);
+}
+
+VimFormView::~VimFormView()
+{
+       if (menuBar) {
+               RemoveChild(menuBar);
+#ifdef never
+               //  deleting the menuBar leads to SEGV on exit
+               //  richard@whitequeen.com Jul 99
+               delete menuBar;
+#endif
+       }
+
+#ifdef FEAT_TOOLBAR
+       delete toolBar;
+#endif
+
+#ifdef FEAT_GUI_TABLINE
+       delete tabLine;
+#endif
+
+       if (textArea) {
+               RemoveChild(textArea);
+               delete textArea;
+       }
+       gui.vimForm = NULL;
+}
+
+       void
+VimFormView::init(BRect frame)
+{
+       menuBar = new BMenuBar(BRect(0,0,-MENUBAR_MARGIN,-MENUBAR_MARGIN),
+                       "VimMenuBar");
+
+       AddChild(menuBar);
+
+#ifdef FEAT_TOOLBAR
+       toolBar = new VimToolbar(BRect(0,0,0,0), "VimToolBar");
+       toolBar->PrepareButtonBitmaps();
+       AddChild(toolBar);
+#endif
+
+#ifdef FEAT_GUI_TABLINE
+       tabLine = new VimTabLine(BRect(0,0,0,0));
+//     tabLine->PrepareButtonBitmaps();
+       AddChild(tabLine);
+#endif
+
+       BRect remaining = frame;
+       textArea = new VimTextAreaView(remaining);
+       AddChild(textArea);
+       // The textArea will be resized later when menus are added
+
+       gui.vimForm = this;
+}
+
+#ifdef FEAT_TOOLBAR
+       float
+VimFormView::ToolbarHeight() const
+{
+       return toolBar ? toolBar->ToolbarHeight() : 0.;
+}
+#endif
+
+#ifdef FEAT_GUI_TABLINE
+       float
+VimFormView::TablineHeight() const
+{
+       return (tabLine && IsShowingTabLine()) ? tabLine->TablineHeight() : 0.;
+}
+#endif
+
+       void
+VimFormView::AllAttached()
+{
+       /*
+        * Apparently signals are inherited by the created thread -
+        * disable the most annoying ones.
+        */
+       signal(SIGINT, SIG_IGN);
+       signal(SIGQUIT, SIG_IGN);
+
+       if (menuBar && textArea) {
+               /*
+                * Resize the textArea to fill the space left over by the menu.
+                * This is somewhat futile since it will be done again once
+                * menus are added to the menu bar.
+                */
+               BRect remaining = Bounds();
+
+#ifdef FEAT_MENU
+               remaining.top += MenuHeight();
+               menuBar->ResizeTo(remaining.right, remaining.top);
+               gui.menu_height = (int) MenuHeight();
+#endif
+
+#ifdef FEAT_TOOLBAR
+               toolBar->MoveTo(remaining.left, remaining.top);
+               toolBar->ResizeTo(remaining.right, ToolbarHeight());
+               remaining.top += ToolbarHeight();
+               gui.toolbar_height = ToolbarHeight();
+#endif
+
+#ifdef FEAT_GUI_TABLINE
+               tabLine->MoveTo(remaining.left, remaining.top);
+               tabLine->ResizeTo(remaining.right + 1, TablineHeight());
+               remaining.top += TablineHeight();
+               gui.tabline_height = TablineHeight();
+#endif
+
+               textArea->ResizeTo(remaining.Width(), remaining.Height());
+               textArea->MoveTo(remaining.left, remaining.top);
+       }
+
+
+       Inherited::AllAttached();
+}
+
+       void
+VimFormView::FrameResized(float new_width, float new_height)
+{
+       struct VimResizeMsg sm;
+       int adjust_h, adjust_w;
+
+       new_width += 1;     //  adjust from width to number of pixels occupied
+       new_height += 1;
+
+       sm.width = (int) new_width;
+       sm.height = (int) new_height;
+       adjust_w = ((int)new_width - gui_get_base_width()) % gui.char_width;
+       adjust_h = ((int)new_height - gui_get_base_height()) % gui.char_height;
+
+       if (adjust_w > 0 || adjust_h > 0) {
+               sm.width  -= adjust_w;
+               sm.height -= adjust_h;
+       }
+
+       write_port(gui.vdcmp, VimMsg::Resize, &sm, sizeof(sm));
+       //  calls gui_resize_shell(new_width, new_height);
+
+       return;
+
+       /*
+        * The area below the vertical scrollbar is erased to the colour
+        * set with SetViewColor() automatically, because we had set
+        * B_WILL_DRAW. Resizing the window tight around the vertical
+        * scroll bar also helps to avoid debris.
+        */
+}
+
+// ---------------- VimTextAreaView ----------------
+
+VimTextAreaView::VimTextAreaView(BRect frame):
+       BView(frame, "VimTextAreaView", B_FOLLOW_ALL_SIDES,
+#ifdef FEAT_MBYTE_IME
+               B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_INPUT_METHOD_AWARE),
+#else
+               B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
+#endif
+       mouseDragEventCount(0)
+{
+#ifdef FEAT_MBYTE_IME
+       IMData.messenger = NULL;
+       IMData.message = NULL;
+#endif
+       init(frame);
+}
+
+VimTextAreaView::~VimTextAreaView()
+{
+       gui.vimTextArea = NULL;
+}
+
+       void
+VimTextAreaView::init(BRect frame)
+{
+       // set up global var for fast access
+       gui.vimTextArea = this;
+
+       /*
+        * Tell the app server not to erase the view: we will
+        * fill it in completely by ourselves.
+        * (Does this really work? Even if not, it won't harm either.)
+        */
+       SetViewColor(B_TRANSPARENT_32_BIT);
+#define PEN_WIDTH   1
+       SetPenSize(PEN_WIDTH);
+#define W_WIDTH(curwin)   0
+}
+
+       void
+VimTextAreaView::Draw(BRect updateRect)
+{
+       /*
+        * XXX Other ports call here:
+        * out_flush();      * make sure all output has been processed *
+        * but we can't do that, since it involves too much information
+        * that is owned by other threads...
+        */
+
+       /*
+        *  No need to use gui.vimWindow->Lock(): we are locked already.
+        *  However, it would not hurt.
+        */
+       rgb_color rgb = GUI_TO_RGB(gui.back_pixel);
+       SetLowColor(rgb);
+       FillRect(updateRect, B_SOLID_LOW);
+       gui_redraw((int) updateRect.left, (int) updateRect.top,
+                       (int) (updateRect.Width() + PEN_WIDTH), (int) (updateRect.Height() + PEN_WIDTH));
+
+       // Clear the border areas if needed
+       SetLowColor(rgb);
+
+       if (updateRect.left < FILL_X(0))        //  left border
+               FillRect(BRect(updateRect.left, updateRect.top,
+                                       FILL_X(0)-PEN_WIDTH, updateRect.bottom), B_SOLID_LOW);
+       if (updateRect.top < FILL_Y(0)) //  top border
+               FillRect(BRect(updateRect.left, updateRect.top,
+                                       updateRect.right, FILL_Y(0)-PEN_WIDTH), B_SOLID_LOW);
+       if (updateRect.right >= FILL_X(Columns)) //  right border
+               FillRect(BRect(FILL_X((int)Columns), updateRect.top,
+                                       updateRect.right, updateRect.bottom), B_SOLID_LOW);
+       if (updateRect.bottom >= FILL_Y(Rows))   //  bottom border
+               FillRect(BRect(updateRect.left, FILL_Y((int)Rows),
+                                       updateRect.right, updateRect.bottom), B_SOLID_LOW);
+
+#ifdef FEAT_MBYTE_IME
+       DrawIMString();
+#endif
+}
+
+       void
+VimTextAreaView::KeyDown(const char *bytes, int32 numBytes)
+{
+       struct VimKeyMsg km;
+       char_u *dest = km.chars;
+
+       bool canHaveVimModifiers = false;
+
+       BMessage *msg = Window()->CurrentMessage();
+       assert(msg);
+       // msg->PrintToStream();
+
+       /*
+        * Convert special keys to Vim codes.
+        * I think it is better to do it in the window thread
+        * so we use at least a little bit of the potential
+        * of our 2 CPUs. Besides, due to the fantastic mapping
+        * of special keys to UTF-8, we have quite some work to
+        * do...
+        * TODO: I'm not quite happy with detection of special
+        * keys. Perhaps I should use scan codes after all...
+        */
+       if (numBytes > 1) {
+               // This cannot be a special key
+               if (numBytes > KEY_MSG_BUFSIZ)
+                       numBytes = KEY_MSG_BUFSIZ;          //  should never happen... ???
+               km.length = numBytes;
+               memcpy((char *)dest, bytes, numBytes);
+               km.csi_escape = true;
+       } else {
+               int32 scancode = 0;
+               msg->FindInt32("key", &scancode);
+
+               int32 beModifiers = 0;
+               msg->FindInt32("modifiers", &beModifiers);
+
+               char_u string[3];
+               int len = 0;
+               km.length = 0;
+
+               /*
+                * For normal, printable ASCII characters, don't look them up
+                * to check if they might be a special key. They aren't.
+                */
+               assert(B_BACKSPACE <= 0x20);
+               assert(B_DELETE == 0x7F);
+               if (((char_u)bytes[0] <= 0x20 || (char_u)bytes[0] == 0x7F) &&
+                               numBytes == 1) {
+                       /*
+                        * Due to the great nature of Be's mapping of special keys,
+                        * viz. into the range of the control characters,
+                        * we can only be sure it is *really* a special key if
+                        * if it is special without using ctrl. So, only if ctrl is
+                        * used, we need to check it unmodified.
+                        */
+                       if (beModifiers & B_CONTROL_KEY) {
+                               int index = keyMap->normal_map[scancode];
+                               int newNumBytes = keyMapChars[index];
+                               char_u *newBytes = (char_u *)&keyMapChars[index + 1];
+
+                               /*
+                                * Check if still special without the control key.
+                                * This is needed for BACKSPACE: that key does produce
+                                * different values with modifiers (DEL).
+                                * Otherwise we could simply have checked for equality.
+                                */
+                               if (newNumBytes != 1 || (*newBytes > 0x20 &&
+                                                       *newBytes != 0x7F )) {
+                                       goto notspecial;
+                               }
+                               bytes = (char *)newBytes;
+                       }
+                       canHaveVimModifiers = true;
+
+                       uint16 beoskey;
+                       int first, last;
+
+                       /*
+                        * If numBytes == 0 that probably always indicates a special key.
+                        * (does not happen yet)
+                        */
+                       if (numBytes == 0 || bytes[0] == B_FUNCTION_KEY) {
+                               beoskey = F(scancode);
+                               first = FIRST_FUNCTION_KEY;
+                               last = NUM_SPECIAL_KEYS;
+                       } else if (*bytes == '\n' && scancode == 0x47) {
+                               // remap the (non-keypad) ENTER key from \n to \r.
+                               string[0] = '\r';
+                               len = 1;
+                               first = last = 0;
+                       } else {
+                               beoskey = K(bytes[0]);
+                               first = 0;
+                               last = FIRST_FUNCTION_KEY;
+                       }
+
+                       for (int i = first; i < last; i++) {
+                               if (special_keys[i].BeKeys == beoskey) {
+                                       string[0] = CSI;
+                                       string[1] = special_keys[i].vim_code0;
+                                       string[2] = special_keys[i].vim_code1;
+                                       len = 3;
+                               }
+                       }
+               }
+notspecial:
+               if (len == 0) {
+                       string[0] = bytes[0];
+                       len = 1;
+               }
+
+               // Special keys (and a few others) may have modifiers
+#if 0
+               if (len == 3 ||
+                               bytes[0] == B_SPACE || bytes[0] == B_TAB ||
+                               bytes[0] == B_RETURN || bytes[0] == '\r' ||
+                               bytes[0] == B_ESCAPE)
+#else
+                       if (canHaveVimModifiers)
+#endif
+                       {
+                               int modifiers;
+                               modifiers = 0;
+                               if (beModifiers & B_SHIFT_KEY)
+                                       modifiers |= MOD_MASK_SHIFT;
+                               if (beModifiers & B_CONTROL_KEY)
+                                       modifiers |= MOD_MASK_CTRL;
+                               if (beModifiers & B_OPTION_KEY)
+                                       modifiers |= MOD_MASK_ALT;
+
+                               /*
+                                * For some keys a shift modifier is translated into another key
+                                * code.  Do we need to handle the case where len != 1 and
+                                * string[0] != CSI? (Not for BeOS, since len == 3 implies
+                                * string[0] == CSI...)
+                                */
+                               int key;
+                               if (string[0] == CSI && len == 3)
+                                       key = TO_SPECIAL(string[1], string[2]);
+                               else
+                                       key = string[0];
+                               key = simplify_key(key, &modifiers);
+                               if (IS_SPECIAL(key))
+                               {
+                                       string[0] = CSI;
+                                       string[1] = K_SECOND(key);
+                                       string[2] = K_THIRD(key);
+                                       len = 3;
+                               }
+                               else
+                               {
+                                       string[0] = key;
+                                       len = 1;
+                               }
+
+                               if (modifiers)
+                               {
+                                       *dest++ = CSI;
+                                       *dest++ = KS_MODIFIER;
+                                       *dest++ = modifiers;
+                                       km.length = 3;
+                               }
+                       }
+               memcpy((char *)dest, string, len);
+               km.length += len;
+               km.csi_escape = false;
+       }
+
+       write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km));
+
+       /*
+        * blank out the pointer if necessary
+        */
+       if (p_mh && !gui.pointer_hidden)
+       {
+               guiBlankMouse(true);
+               gui.pointer_hidden = TRUE;
+       }
+}
+void
+VimTextAreaView::guiSendMouseEvent(
+               int         button,
+               int         x,
+               int         y,
+               int         repeated_click,
+               int_u   modifiers)
+{
+       VimMouseMsg mm;
+
+       mm.button = button;
+       mm.x = x;
+       mm.y = y;
+       mm.repeated_click = repeated_click;
+       mm.modifiers = modifiers;
+
+       write_port(gui.vdcmp, VimMsg::Mouse, &mm, sizeof(mm));
+       //  calls gui_send_mouse_event()
+
+       /*
+        * if our pointer is currently hidden, then we should show it.
+        */
+       if (gui.pointer_hidden)
+       {
+               guiBlankMouse(false);
+               gui.pointer_hidden = FALSE;
+       }
+}
+
+void
+VimTextAreaView::guiMouseMoved(
+               int         x,
+               int         y)
+{
+       VimMouseMovedMsg mm;
+
+       mm.x = x;
+       mm.y = y;
+
+       write_port(gui.vdcmp, VimMsg::MouseMoved, &mm, sizeof(mm));
+
+       if (gui.pointer_hidden)
+       {
+               guiBlankMouse(false);
+               gui.pointer_hidden = FALSE;
+       }
+}
+
+       void
+VimTextAreaView::guiBlankMouse(bool should_hide)
+{
+       if (should_hide) {
+               // gui.vimApp->HideCursor();
+               gui.vimApp->ObscureCursor();
+               /*
+                * ObscureCursor() would even be easier, but then
+                * Vim's idea of mouse visibility does not necessarily
+                * correspond to reality.
+                */
+       } else {
+               // gui.vimApp->ShowCursor();
+       }
+}
+
+       int_u
+VimTextAreaView::mouseModifiersToVim(int32 beModifiers)
+{
+       int_u vim_modifiers = 0x0;
+
+       if (beModifiers & B_SHIFT_KEY)
+               vim_modifiers |= MOUSE_SHIFT;
+       if (beModifiers & B_CONTROL_KEY)
+               vim_modifiers |= MOUSE_CTRL;
+       if (beModifiers & B_OPTION_KEY)     // Alt or Meta key
+               vim_modifiers |= MOUSE_ALT;
+
+       return vim_modifiers;
+}
+
+       void
+VimTextAreaView::MouseDown(BPoint point)
+{
+       BMessage *m = Window()->CurrentMessage();
+       assert(m);
+
+       int32 buttons = 0;
+       m->FindInt32("buttons", &buttons);
+
+       int vimButton;
+
+       if (buttons & B_PRIMARY_MOUSE_BUTTON)
+               vimButton = MOUSE_LEFT;
+       else if (buttons & B_SECONDARY_MOUSE_BUTTON)
+               vimButton = MOUSE_RIGHT;
+       else if (buttons & B_TERTIARY_MOUSE_BUTTON)
+               vimButton = MOUSE_MIDDLE;
+       else
+               return;                 // Unknown button
+
+       vimMouseButton = 1;             // don't care which one
+
+       // Handle multiple clicks
+       int32 clicks = 0;
+       m->FindInt32("clicks", &clicks);
+
+       int32 modifiers = 0;
+       m->FindInt32("modifiers", &modifiers);
+
+       vimMouseModifiers = mouseModifiersToVim(modifiers);
+
+       guiSendMouseEvent(vimButton, point.x, point.y,
+                       clicks > 1 /* = repeated_click*/, vimMouseModifiers);
+}
+
+       void
+VimTextAreaView::MouseUp(BPoint point)
+{
+       vimMouseButton = 0;
+
+       BMessage *m = Window()->CurrentMessage();
+       assert(m);
+       // m->PrintToStream();
+
+       int32 modifiers = 0;
+       m->FindInt32("modifiers", &modifiers);
+
+       vimMouseModifiers = mouseModifiersToVim(modifiers);
+
+       guiSendMouseEvent(MOUSE_RELEASE, point.x, point.y,
+                       0 /* = repeated_click*/, vimMouseModifiers);
+
+       Inherited::MouseUp(point);
+}
+
+       void
+VimTextAreaView::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
+{
+       /*
+        * if our pointer is currently hidden, then we should show it.
+        */
+       if (gui.pointer_hidden)
+       {
+               guiBlankMouse(false);
+               gui.pointer_hidden = FALSE;
+       }
+
+       if (!vimMouseButton) {    // could also check m->"buttons"
+               guiMouseMoved(point.x, point.y);
+               return;
+       }
+
+       atomic_add(&mouseDragEventCount, 1);
+
+       // Don't care much about "transit"
+       guiSendMouseEvent(MOUSE_DRAG, point.x, point.y, 0, vimMouseModifiers);
+}
+
+       void
+VimTextAreaView::MessageReceived(BMessage *m)
+{
+       switch (m->what) {
+               case 'menu':
+                       {
+                               VimMenuMsg mm;
+                               mm.guiMenu = NULL;      // in case no pointer in msg
+                               m->FindPointer("VimMenu", (void **)&mm.guiMenu);
+                               write_port(gui.vdcmp, VimMsg::Menu, &mm, sizeof(mm));
+                       }
+                       break;
+               case B_MOUSE_WHEEL_CHANGED:
+                       {
+                               VimScrollBar* scb = curwin->w_scrollbars[1].id;
+                               float small=0, big=0, dy=0;
+                               m->FindFloat("be:wheel_delta_y", &dy);
+                               scb->GetSteps(&small, &big);
+                               scb->SetValue(scb->Value()+small*dy*3);
+                               scb->ValueChanged(scb->Value());
+#if 0
+                               scb = curwin->w_scrollbars[0].id;
+                               scb->GetSteps(&small, &big);
+                               scb->SetValue(scb->Value()+small*dy);
+                               scb->ValueChanged(scb->Value());
+#endif
+                       }
+                       break;
+#ifdef FEAT_MBYTE_IME
+               case B_INPUT_METHOD_EVENT:
+                       {
+                               int32 opcode;
+                               m->FindInt32("be:opcode", &opcode);
+                               switch(opcode)
+                               {
+                                       case B_INPUT_METHOD_STARTED:
+                                               if(!IMData.messenger) delete IMData.messenger;
+                                               IMData.messenger = new BMessenger();
+                                               m->FindMessenger("be:reply_to", IMData.messenger);
+                                               break;
+                                       case B_INPUT_METHOD_CHANGED:
+                                               {
+                                                       BString str;
+                                                       bool confirmed;
+                                                       if(IMData.message) *(IMData.message) = *m;
+                                                       else               IMData.message = new BMessage(*m);
+                                                       DrawIMString();
+                                                       m->FindBool("be:confirmed", &confirmed);
+                                                       if (confirmed)
+                                                       {
+                                                               m->FindString("be:string", &str);
+                                                               char_u *chars = (char_u*)str.String();
+                                                               struct VimKeyMsg km;
+                                                               km.csi_escape = true;
+                                                               int clen;
+                                                               int i = 0;
+                                                               while (i < str.Length())
+                                                               {
+                                                                       clen = utf_ptr2len(chars+i);
+                                                                       memcpy(km.chars, chars+i, clen);
+                                                                       km.length = clen;
+                                                                       write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km));
+                                                                       i += clen;
+                                                               }
+                                                       }
+                                               }
+                                               break;
+                                       case B_INPUT_METHOD_LOCATION_REQUEST:
+                                               {
+                                                       BMessage msg(B_INPUT_METHOD_EVENT);
+                                                       msg.AddInt32("be:opcode", B_INPUT_METHOD_LOCATION_REQUEST);
+                                                       msg.AddPoint("be:location_reply", IMData.location);
+                                                       msg.AddFloat("be:height_reply", FILL_Y(1));
+                                                       IMData.messenger->SendMessage(&msg);
+                                               }
+                                               break;
+                                       case B_INPUT_METHOD_STOPPED:
+                                               delete IMData.messenger;
+                                               delete IMData.message;
+                                               IMData.messenger = NULL;
+                                               IMData.message = NULL;
+                                               break;
+                               }
+                       }
+                       // TODO: sz: break here???
+#endif
+               default:
+                       if (m->WasDropped()) {
+                               BWindow *w = Window();
+                               w->DetachCurrentMessage();
+                               w->Minimize(false);
+                               VimApp::SendRefs(m, (modifiers() & B_SHIFT_KEY) != 0);
+                       } else {
+                               Inherited::MessageReceived(m);
+                       }
+                       break;
+       }
+}
+
+       int
+VimTextAreaView::mchInitFont(char_u *name)
+{
+       VimFont *newFont = (VimFont *)gui_mch_get_font(name, 1);
+       if(newFont != NOFONT) {
+               gui.norm_font = (GuiFont)newFont;
+               gui_mch_set_font((GuiFont)newFont);
+               if (name && STRCMP(name, "*") != 0)
+                       hl_set_font_name(name);
+
+               SetDrawingMode(B_OP_COPY);
+
+               /*
+                * Try to load other fonts for bold, italic, and bold-italic.
+                * We should also try to work out what font to use for these when they are
+                * not specified by X resources, but we don't yet.
+                */
+               return OK;
+       }
+       return FAIL;
+}
+
+       void
+VimTextAreaView::mchDrawString(int row, int col, char_u *s, int len, int flags)
+{
+       /*
+        * First we must erase the area, because DrawString won't do
+        * that for us. XXX Most of the time this is a waste of effort
+        * since the bachground has been erased already... DRAW_TRANSP
+        * should be set when appropriate!!!
+        * (Rectangles include the bottom and right edge)
+        */
+       if (!(flags & DRAW_TRANSP)) {
+               int cells;
+               cells = 0;
+               for(int i=0; i<len; i++) {
+                       int cn = utf_ptr2cells((char_u *)(s+i));
+                       if(cn<4) cells += cn;
+               }
+
+               BRect r(FILL_X(col), FILL_Y(row),
+                               FILL_X(col + cells) - PEN_WIDTH, FILL_Y(row + 1) - PEN_WIDTH);
+               FillRect(r, B_SOLID_LOW);
+       }
+
+       BFont font;
+       this->GetFont(&font);
+       if(!font.IsFixed())
+       {
+               char* p = (char*)s;
+               int32 clen, lastpos = 0;
+               BPoint where;
+               int cells;
+               while((p - (char*)s) < len) {
+                       clen = utf_ptr2len((u_char*)p);
+                       where.Set(TEXT_X(col+lastpos), TEXT_Y(row));
+                       DrawString(p, clen, where);
+                       if (flags & DRAW_BOLD) {
+                               where.x += 1.0;
+                               SetDrawingMode(B_OP_BLEND);
+                               DrawString(p, clen, where);
+                               SetDrawingMode(B_OP_COPY);
+                       }
+                       cells = utf_ptr2cells((char_u *)p);
+                       if(cells<4) lastpos += cells;
+                       else        lastpos++;
+                       p += clen;
+               }
+       }
+       else
+       {
+               BPoint where(TEXT_X(col), TEXT_Y(row));
+               DrawString((char*)s, len, where);
+               if (flags & DRAW_BOLD) {
+                       where.x += 1.0;
+                       SetDrawingMode(B_OP_BLEND);
+                       DrawString((char*)s, len, where);
+                       SetDrawingMode(B_OP_COPY);
+               }
+       }
+
+       if (flags & DRAW_UNDERL) {
+               int cells;
+               cells = 0;
+               for(int i=0; i<len; i++) {
+                       int cn = utf_ptr2cells((char_u *)(s+i));
+                       if(cn<4) cells += cn;
+               }
+
+               BPoint start(FILL_X(col), FILL_Y(row + 1) - PEN_WIDTH);
+               BPoint end(FILL_X(col + cells) - PEN_WIDTH, start.y);
+
+               StrokeLine(start, end);
+       }
+}
+
+void
+VimTextAreaView::mchClearBlock(
+               int             row1,
+               int             col1,
+               int             row2,
+               int             col2)
+{
+       BRect r(FILL_X(col1), FILL_Y(row1),
+                       FILL_X(col2 + 1) - PEN_WIDTH, FILL_Y(row2 + 1) - PEN_WIDTH);
+       gui_mch_set_bg_color(gui.back_pixel);
+       FillRect(r, B_SOLID_LOW);
+}
+
+       void
+VimTextAreaView::mchClearAll()
+{
+       gui_mch_set_bg_color(gui.back_pixel);
+       FillRect(Bounds(), B_SOLID_LOW);
+}
+
+/*
+ * mchDeleteLines() Lock()s the window by itself.
+ */
+       void
+VimTextAreaView::mchDeleteLines(int row, int num_lines)
+{
+       BRect source, dest;
+       source.left = FILL_X(gui.scroll_region_left);
+       source.top = FILL_Y(row + num_lines);
+       source.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH;
+       source.bottom = FILL_Y(gui.scroll_region_bot + 1) - PEN_WIDTH;
+
+       dest.left = FILL_X(gui.scroll_region_left);
+       dest.top = FILL_Y(row);
+       dest.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH;
+       dest.bottom = FILL_Y(gui.scroll_region_bot - num_lines + 1) - PEN_WIDTH;
+
+       if (gui.vimWindow->Lock()) {
+               // Clear one column more for when bold has spilled over
+               CopyBits(source, dest);
+               gui_clear_block(gui.scroll_region_bot - num_lines + 1,
+                               gui.scroll_region_left,
+                               gui.scroll_region_bot, gui.scroll_region_right);
+
+
+               gui.vimWindow->Unlock();
+               /*
+                * The Draw() callback will be called now if some of the source
+                * bits were not in the visible region.
+                */
+       }
+       // gui_x11_check_copy_area();
+       //  }
+}
+
+/*
+ * mchInsertLines() Lock()s the window by itself.
+ */
+       void
+VimTextAreaView::mchInsertLines(int row, int num_lines)
+{
+       BRect source, dest;
+
+       // XXX Attempt at a hack:
+       gui.vimWindow->UpdateIfNeeded();
+       source.left = FILL_X(gui.scroll_region_left);
+       source.top = FILL_Y(row);
+       source.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH;
+       source.bottom = FILL_Y(gui.scroll_region_bot - num_lines + 1) - PEN_WIDTH;
+
+       dest.left = FILL_X(gui.scroll_region_left);
+       dest.top = FILL_Y(row + num_lines);
+       dest.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH;
+       dest.bottom = FILL_Y(gui.scroll_region_bot + 1) - PEN_WIDTH;
+
+       if (gui.vimWindow->Lock()) {
+               // Clear one column more for when bold has spilled over
+               CopyBits(source, dest);
+               gui_clear_block(row, gui.scroll_region_left,
+                               row + num_lines - 1, gui.scroll_region_right);
+
+               gui.vimWindow->Unlock();
+               /*
+                * The Draw() callback will be called now if some of the source
+                * bits were not in the visible region.
+                * However, if we scroll too fast it can't keep up and the
+                * update region gets messed up. This seems to be because copying
+                * un-Draw()n bits does not generate Draw() calls for the copy...
+                * I moved the hack to before the CopyBits() to reduce the
+                * amount of additional waiting needed.
+                */
+
+               // gui_x11_check_copy_area();
+
+       }
+}
+
+#ifdef FEAT_MBYTE_IME
+/*
+ * DrawIMString draws string with IMData.message.
+ */
+void VimTextAreaView::DrawIMString(void)
+{
+       static const rgb_color r_highlight = {255, 152, 152, 255},
+                                b_highlight = {152, 203, 255, 255};
+       BString str;
+       const char* s;
+       int len;
+       BMessage* msg = IMData.message;
+       if (!msg)
+               return;
+       gui_redraw_block(IMData.row, 0,
+                       IMData.row + IMData.count, W_WIDTH(curwin), GUI_MON_NOCLEAR);
+       bool confirmed = false;
+       msg->FindBool("be:confirmed", &confirmed);
+       if (confirmed)
+               return;
+       rgb_color hcolor = HighColor(), lcolor = LowColor();
+       msg->FindString("be:string", &str);
+       s = str.String();
+       len = str.Length();
+       SetHighColor(0, 0, 0);
+       IMData.row = gui.row;
+       IMData.col = gui.col;
+       int32 sel_start = 0, sel_end = 0;
+       msg->FindInt32("be:selection", 0, &sel_start);
+       msg->FindInt32("be:selection", 1, &sel_end);
+       int clen, cn;
+       BPoint pos(IMData.col, 0);
+       BRect r;
+       BPoint where;
+       IMData.location = ConvertToScreen(
+                       BPoint(FILL_X(pos.x), FILL_Y(IMData.row + pos.y)));
+       for (int i=0; i<len; i+=clen)
+       {
+               cn = utf_ptr2cells((char_u *)(s+i));
+               clen = utf_ptr2len((char_u *)(s+i));
+               if (pos.x + cn > W_WIDTH(curwin))
+               {
+                       pos.y++;
+                       pos.x = 0;
+               }
+               if (sel_start<=i && i<sel_end)
+               {
+                       SetLowColor(r_highlight);
+                       IMData.location = ConvertToScreen(
+                                       BPoint(FILL_X(pos.x), FILL_Y(IMData.row + pos.y)));
+               }
+               else
+               {
+                       SetLowColor(b_highlight);
+               }
+               r.Set(FILL_X(pos.x), FILL_Y(IMData.row + pos.y),
+                               FILL_X(pos.x + cn) - PEN_WIDTH,
+                               FILL_Y(IMData.row + pos.y + 1) - PEN_WIDTH);
+               FillRect(r, B_SOLID_LOW);
+               where.Set(TEXT_X(pos.x), TEXT_Y(IMData.row + pos.y));
+               DrawString((s+i), clen, where);
+               pos.x += cn;
+       }
+       IMData.count = (int)pos.y;
+
+       SetHighColor(hcolor);
+       SetLowColor(lcolor);
+}
+#endif
+// ---------------- VimScrollBar ----------------
+
+/*
+ * BUG: XXX
+ * It seems that BScrollBar determine their direction not from
+ * "posture" but from if they are "tall" or "wide" in shape...
+ *
+ * Also, place them out of sight, because Vim enables them before
+ * they are positioned.
+ */
+VimScrollBar::VimScrollBar(scrollbar_T *g, orientation posture):
+       BScrollBar(posture == B_HORIZONTAL ?  BRect(-100,-100,-10,-90) :
+                       BRect(-100,-100,-90,-10),
+                       "vim scrollbar", (BView *)NULL,
+                       0.0, 10.0, posture),
+       ignoreValue(-1),
+       scrollEventCount(0)
+{
+       gsb = g;
+       SetResizingMode(B_FOLLOW_NONE);
+}
+
+VimScrollBar::~VimScrollBar()
+{
+}
+
+       void
+VimScrollBar::ValueChanged(float newValue)
+{
+       if (ignoreValue >= 0.0 && newValue == ignoreValue) {
+               ignoreValue = -1;
+               return;
+       }
+       ignoreValue = -1;
+       /*
+        * We want to throttle the amount of scroll messages generated.
+        * Normally I presume you won't get a new message before we've
+        * handled the previous one, but because we're passing them on this
+        * happens very quickly. So instead we keep a counter of how many
+        * scroll events there are (or will be) in the VDCMP, and the
+        * throttling happens at the receiving end.
+        */
+       atomic_add(&scrollEventCount, 1);
+
+       struct VimScrollBarMsg sm;
+
+       sm.sb = this;
+       sm.value = (long) newValue;
+       sm.stillDragging = TRUE;
+
+       write_port(gui.vdcmp, VimMsg::ScrollBar, &sm, sizeof(sm));
+
+       //  calls gui_drag_scrollbar(sb, newValue, TRUE);
+}
+
+/*
+ * When the mouse goes up, report that scrolling has stopped.
+ * MouseUp() is NOT called when the mouse-up occurs outside
+ * the window, even though the thumb does move while the mouse
+ * is outside... This has some funny effects... XXX
+ * So we do special processing when the window de/activates.
+ */
+       void
+VimScrollBar::MouseUp(BPoint where)
+{
+       // BMessage *m = Window()->CurrentMessage();
+       // m->PrintToStream();
+
+       atomic_add(&scrollEventCount, 1);
+
+       struct VimScrollBarMsg sm;
+
+       sm.sb = this;
+       sm.value = (long) Value();
+       sm.stillDragging = FALSE;
+
+       write_port(gui.vdcmp, VimMsg::ScrollBar, &sm, sizeof(sm));
+
+       //  calls gui_drag_scrollbar(sb, newValue, FALSE);
+
+       Inherited::MouseUp(where);
+}
+
+       void
+VimScrollBar::SetValue(float newValue)
+{
+       if (newValue == Value())
+               return;
+
+       ignoreValue = newValue;
+       Inherited::SetValue(newValue);
+}
+
+// ---------------- VimFont ----------------
+
+VimFont::VimFont(): BFont()
+{
+       init();
+}
+
+VimFont::VimFont(const VimFont *rhs): BFont(rhs)
+{
+       init();
+}
+
+VimFont::VimFont(const BFont *rhs): BFont(rhs)
+{
+       init();
+}
+
+VimFont::VimFont(const VimFont &rhs): BFont(rhs)
+{
+       init();
+}
+
+VimFont::~VimFont()
+{
+}
+
+       void
+VimFont::init()
+{
+       next = NULL;
+       refcount = 1;
+       name = NULL;
+}
+
+// ---------------- VimDialog ----------------
+
+#if defined(FEAT_GUI_DIALOG)
+
+const unsigned int     kVimDialogButtonMsg = 'VMDB';
+const unsigned int     kVimDialogIconStripeWidth = 30;
+const unsigned int     kVimDialogButtonsSpacingX = 9;
+const unsigned int     kVimDialogButtonsSpacingY = 4;
+const unsigned int     kVimDialogSpacingX = 6;
+const unsigned int     kVimDialogSpacingY = 10;
+const unsigned int     kVimDialogMinimalWidth  = 310;
+const unsigned int     kVimDialogMinimalHeight = 75;
+const BRect                    kDefaultRect =
+BRect(0, 0, kVimDialogMinimalWidth, kVimDialogMinimalHeight);
+
+VimDialog::VimDialog(int type, const char *title, const char *message,
+               const char *buttons, int dfltbutton, const char *textfield, int ex_cmd)
+: BWindow(kDefaultRect, title, B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL,
+               B_NOT_CLOSABLE | B_NOT_RESIZABLE |
+               B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_ASYNCHRONOUS_CONTROLS)
+       , fDialogSem(-1)
+       , fDialogValue(dfltbutton)
+       , fMessageView(NULL)
+       , fInputControl(NULL)
+       , fInputValue(textfield)
+{
+       //  master view
+       VimDialog::View* view = new VimDialog::View(Bounds());
+       if(view == NULL)
+               return;
+
+       if(title == NULL)
+               SetTitle("Vim " VIM_VERSION_MEDIUM);
+
+       AddChild(view);
+
+       //  icon
+       view->InitIcon(type);
+
+       //  buttons
+       int32 which = 1;
+       float maxButtonWidth  = 0;
+       float maxButtonHeight = 0;
+       float buttonsWidth    = 0;
+       float buttonsHeight   = 0;
+       BString strButtons(buttons);
+       strButtons.RemoveAll("&");
+       do {
+               int32 end = strButtons.FindFirst('\n');
+               if(end != B_ERROR)
+                       strButtons.SetByteAt(end, '\0');
+
+               BButton *button = _CreateButton(which++, strButtons.String());
+               view->AddChild(button);
+               fButtonsList.AddItem(button);
+
+               maxButtonWidth  = max_c(maxButtonWidth,  button->Bounds().Width());
+               maxButtonHeight = max_c(maxButtonHeight, button->Bounds().Height());
+               buttonsWidth   += button->Bounds().Width();
+               buttonsHeight  += button->Bounds().Height();
+
+               if(end == B_ERROR)
+                       break;
+
+               strButtons.Remove(0, end + 1);
+       } while(true);
+
+       int32 buttonsCount = fButtonsList.CountItems();
+       buttonsWidth      += kVimDialogButtonsSpacingX * (buttonsCount - 1);
+       buttonsHeight     += kVimDialogButtonsSpacingY * (buttonsCount - 1);
+       float dialogWidth  = buttonsWidth + kVimDialogIconStripeWidth +
+               kVimDialogSpacingX * 2;
+       float dialogHeight = maxButtonHeight + kVimDialogSpacingY * 3;
+
+       // Check 'v' flag in 'guioptions': vertical button placement.
+       bool vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL) ||
+               dialogWidth >= gui.vimWindow->Bounds().Width();
+       if(vertical) {
+               dialogWidth  -= buttonsWidth;
+               dialogWidth  += maxButtonWidth;
+               dialogHeight -= maxButtonHeight;
+               dialogHeight += buttonsHeight;
+       }
+
+       dialogWidth  = max_c(dialogWidth,  kVimDialogMinimalWidth);
+
+       //  message view
+       BRect rect(0, 0, dialogWidth, 0);
+       rect.left  += kVimDialogIconStripeWidth + 16 + kVimDialogSpacingX;
+       rect.top   += kVimDialogSpacingY;
+       rect.right -= kVimDialogSpacingX;
+       rect.bottom = rect.top;
+       fMessageView = new BTextView(rect, "_tv_", rect.OffsetByCopy(B_ORIGIN),
+                       B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW);
+
+       fMessageView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
+       rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR);
+       fMessageView->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor);
+       fMessageView->SetText(message);
+       fMessageView->MakeEditable(false);
+       fMessageView->MakeSelectable(false);
+       fMessageView->SetWordWrap(true);
+       AddChild(fMessageView);
+
+       float messageHeight = fMessageView->TextHeight(0, fMessageView->CountLines());
+       fMessageView->ResizeBy(0, messageHeight);
+       fMessageView->SetTextRect(BRect(0, 0, rect.Width(), messageHeight));
+
+       dialogHeight += messageHeight;
+
+       //  input view
+       if(fInputValue != NULL) {
+               rect.top     =
+                       rect.bottom += messageHeight + kVimDialogSpacingY;
+               fInputControl = new BTextControl(rect, "_iv_", NULL, fInputValue, NULL,
+                               B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE |  B_PULSE_NEEDED);
+               fInputControl->TextView()->SetText(fInputValue);
+               fInputControl->TextView()->SetWordWrap(false);
+               AddChild(fInputControl);
+
+               float width = 0.f, height = 0.f;
+               fInputControl->GetPreferredSize(&width, &height);
+               fInputControl->MakeFocus(true);
+
+               dialogHeight += height + kVimDialogSpacingY * 1.5;
+       }
+
+       dialogHeight = max_c(dialogHeight, kVimDialogMinimalHeight);
+
+       ResizeTo(dialogWidth, dialogHeight);
+       MoveTo((gui.vimWindow->Bounds().Width() - dialogWidth) / 2,
+                       (gui.vimWindow->Bounds().Height() - dialogHeight) / 2);
+
+       //  adjust layout of buttons
+       float buttonWidth = max_c(maxButtonWidth, rect.Width() * 0.66);
+       BPoint origin(dialogWidth, dialogHeight);
+       origin.x -= kVimDialogSpacingX + (vertical ? buttonWidth : buttonsWidth);
+       origin.y -= kVimDialogSpacingY + (vertical ? buttonsHeight  : maxButtonHeight);
+
+       for(int32 i = 0 ; i < buttonsCount; i++) {
+               BButton *button = (BButton*)fButtonsList.ItemAt(i);
+               button->MoveTo(origin);
+               if(vertical) {
+                       origin.y += button->Frame().Height() + kVimDialogButtonsSpacingY;
+                       button->ResizeTo(buttonWidth, button->Frame().Height());
+               } else
+                       origin.x += button->Frame().Width() + kVimDialogButtonsSpacingX;
+
+               if(dfltbutton == i + 1) {
+                       button->MakeDefault(true);
+                       button->MakeFocus(fInputControl == NULL);
+               }
+       }
+}
+
+VimDialog::~VimDialog()
+{
+       if(fDialogSem > B_OK)
+               delete_sem(fDialogSem);
+}
+
+       int
+VimDialog::Go()
+{
+       fDialogSem = create_sem(0, "VimDialogSem");
+       if(fDialogSem < B_OK) {
+               Quit();
+               return fDialogValue;
+       }
+
+       Show();
+
+       while(acquire_sem(fDialogSem) == B_INTERRUPTED);
+
+       int retValue = fDialogValue;
+       if(fInputValue != NULL)
+               vim_strncpy((char_u*)fInputValue, (char_u*)fInputControl->Text(), IOSIZE - 1);
+
+       if(Lock())
+               Quit();
+
+       return retValue;
+}
+
+void VimDialog::MessageReceived(BMessage *msg)
+{
+       int32 which = 0;
+       if(msg->what != kVimDialogButtonMsg ||
+                       msg->FindInt32("which", &which) != B_OK)
+               return BWindow::MessageReceived(msg);
+
+       fDialogValue = which;
+       delete_sem(fDialogSem);
+       fDialogSem = -1;
+}
+
+BButton* VimDialog::_CreateButton(int32 which, const char* label)
+{
+       BMessage *message = new BMessage(kVimDialogButtonMsg);
+       message->AddInt32("which", which);
+
+       BRect rect(0, 0, 0, 0);
+       BString name;
+       name << "_b" << which << "_";
+
+       BButton* button = new BButton(rect, name.String(), label, message,
+                       B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
+
+       float width = 0.f, height = 0.f;
+       button->GetPreferredSize(&width, &height);
+       button->ResizeTo(width, height);
+
+       return button;
+}
+
+VimDialog::View::View(BRect frame)
+       :       BView(frame, "VimDialogView", B_FOLLOW_ALL_SIDES, B_WILL_DRAW),
+       fIconBitmap(NULL)
+{
+       SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
+}
+
+VimDialog::View::~View()
+{
+       delete fIconBitmap;
+}
+
+void VimDialog::View::Draw(BRect updateRect)
+{
+       BRect stripeRect = Bounds();
+       stripeRect.right = kVimDialogIconStripeWidth;
+       SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT));
+       FillRect(stripeRect);
+
+       if(fIconBitmap == NULL)
+               return;
+
+       SetDrawingMode(B_OP_ALPHA);
+       SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
+       DrawBitmapAsync(fIconBitmap, BPoint(18, 6));
+}
+
+void VimDialog::View::InitIcon(int32 type)
+{
+       if(type == VIM_GENERIC)
+               return;
+
+       BPath path;
+       status_t status = find_directory(B_BEOS_SERVERS_DIRECTORY, &path);
+       if(status != B_OK) {
+               fprintf(stderr, "Cannot retrieve app info:%s\n", strerror(status));
+               return;
+       }
+
+       path.Append("app_server");
+
+       BFile file(path.Path(), O_RDONLY);
+       if(file.InitCheck() != B_OK) {
+               fprintf(stderr, "App file assignment failed:%s\n",
+                               strerror(file.InitCheck()));
+               return;
+       }
+
+       BResources resources(&file);
+       if(resources.InitCheck() != B_OK) {
+               fprintf(stderr, "App server resources assignment failed:%s\n",
+                               strerror(resources.InitCheck()));
+               return;
+       }
+
+       const char *name = "";
+       switch(type) {
+               case VIM_ERROR:         name = "stop"; break;
+               case VIM_WARNING:       name = "warn"; break;
+               case VIM_INFO:          name = "info"; break;
+               case VIM_QUESTION:      name = "idea"; break;
+               default: return;
+       }
+
+       int32 iconSize = 32;
+       fIconBitmap = new BBitmap(BRect(0, 0, iconSize - 1, iconSize - 1), 0, B_RGBA32);
+       if(fIconBitmap == NULL || fIconBitmap->InitCheck() != B_OK) {
+               fprintf(stderr, "Icon bitmap allocation failed:%s\n",
+                               (fIconBitmap == NULL) ? "null" : strerror(fIconBitmap->InitCheck()));
+               return;
+       }
+
+       size_t size = 0;
+       const uint8* iconData = NULL;
+       //  try vector icon first?
+       iconData = (const uint8*)resources.LoadResource(B_VECTOR_ICON_TYPE, name, &size);
+       if(iconData != NULL && BIconUtils::GetVectorIcon(iconData, size, fIconBitmap) == B_OK)
+               return;
+
+       //  try bitmap icon now
+       iconData = (const uint8*)resources.LoadResource(B_LARGE_ICON_TYPE, name, &size);
+       if(iconData == NULL) {
+               fprintf(stderr, "Bitmap icon resource not found\n");
+               delete fIconBitmap;
+               fIconBitmap = NULL;
+               return;
+       }
+
+       if(fIconBitmap->ColorSpace() != B_CMAP8)
+               BIconUtils::ConvertFromCMAP8(iconData, iconSize, iconSize, iconSize, fIconBitmap);
+}
+
+const unsigned int     kVimDialogOKButtonMsg = 'FDOK';
+const unsigned int     kVimDialogCancelButtonMsg = 'FDCN';
+const unsigned int     kVimDialogSizeInputMsg = 'SICH';
+const unsigned int     kVimDialogFamilySelectMsg = 'MSFM';
+const unsigned int     kVimDialogStyleSelectMsg = 'MSST';
+const unsigned int     kVimDialogSizeSelectMsg = 'MSSZ';
+
+VimSelectFontDialog::VimSelectFontDialog(font_family* family, font_style* style, float* size)
+: BWindow(kDefaultRect, "Font Selection", B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL,
+               B_NOT_CLOSABLE | B_NOT_RESIZABLE |
+               B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_ASYNCHRONOUS_CONTROLS)
+       , fStatus(B_NO_INIT)
+       , fDialogSem(-1)
+       , fDialogValue(false)
+       , fFamily(family)
+       , fStyle(style)
+       , fSize(size)
+       , fFontSize(*size)
+       , fPreview(0)
+       , fFamiliesList(0)
+       , fStylesList(0)
+       , fSizesList(0)
+       , fSizesInput(0)
+{
+       strncpy(fFontFamily, *family, B_FONT_FAMILY_LENGTH);
+       strncpy(fFontStyle, *style, B_FONT_STYLE_LENGTH);
+
+       //  "client" area view
+       BBox *clientBox = new BBox(Bounds(), B_EMPTY_STRING, B_FOLLOW_ALL_SIDES,
+                                       B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP | B_PULSE_NEEDED,
+                                       B_PLAIN_BORDER);
+       AddChild(clientBox);
+
+       //  client view
+       BRect RC = clientBox->Bounds();
+       RC.InsetBy(kVimDialogSpacingX, kVimDialogSpacingY);
+       BRect rc(RC.LeftTop(), RC.LeftTop());
+
+       //  at first create all controls
+       fPreview = new BStringView(rc, "preview", "DejaVu Sans Mono");
+       clientBox->AddChild(fPreview);
+
+       BBox* boxDivider = new BBox(rc, B_EMPTY_STRING,
+                       B_FOLLOW_NONE, B_WILL_DRAW, B_FANCY_BORDER);
+       clientBox->AddChild(boxDivider);
+
+       BStringView *labelFamily = new BStringView(rc, "labelFamily", "Family:");
+       clientBox->AddChild(labelFamily);
+       labelFamily->ResizeToPreferred();
+
+       BStringView *labelStyle = new BStringView(rc, "labelStyle", "Style:");
+       clientBox->AddChild(labelStyle);
+       labelStyle->ResizeToPreferred();
+
+       BStringView *labelSize = new BStringView(rc, "labelSize", "Size:");
+       clientBox->AddChild(labelSize);
+       labelSize->ResizeToPreferred();
+
+       fFamiliesList = new BListView(rc, "listFamily",
+                       B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES);
+       BScrollView *scrollFamilies = new BScrollView("scrollFamily",
+                       fFamiliesList, B_FOLLOW_LEFT_RIGHT, 0, false, true);
+       clientBox->AddChild(scrollFamilies);
+
+       fStylesList= new BListView(rc, "listStyles",
+                       B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES);
+       BScrollView *scrollStyles = new BScrollView("scrollStyle",
+                       fStylesList, B_FOLLOW_LEFT_RIGHT, 0, false, true);
+       clientBox->AddChild(scrollStyles);
+
+       fSizesInput = new BTextControl(rc, "inputSize", NULL, "???",
+                       new BMessage(kVimDialogSizeInputMsg));
+       clientBox->AddChild(fSizesInput);
+       fSizesInput->ResizeToPreferred();
+
+       fSizesList = new BListView(rc, "listSizes",
+                       B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES);
+       BScrollView *scrollSizes = new BScrollView("scrollSize",
+                       fSizesList, B_FOLLOW_LEFT_RIGHT, 0, false, true);
+       clientBox->AddChild(scrollSizes);
+
+       BButton *buttonOK = new BButton(rc, "buttonOK", "OK",
+                                               new BMessage(kVimDialogOKButtonMsg));
+       clientBox->AddChild(buttonOK);
+       buttonOK->ResizeToPreferred();
+
+       BButton *buttonCancel = new BButton(rc, "buttonCancel", "Cancel",
+                                               new BMessage(kVimDialogCancelButtonMsg));
+       clientBox->AddChild(buttonCancel);
+       buttonCancel->ResizeToPreferred();
+
+       //  layout controls
+       float lineHeight = labelFamily->Bounds().Height();
+       float previewHeight = lineHeight * 3;
+       float offsetYLabels = previewHeight + kVimDialogSpacingY;
+       float offsetYLists = offsetYLabels + lineHeight + kVimDialogSpacingY / 2;
+       float offsetYSizes = offsetYLists + fSizesInput->Bounds().Height() + kVimDialogSpacingY / 2;
+       float listsHeight = lineHeight * 9;
+       float offsetYButtons = offsetYLists + listsHeight +  kVimDialogSpacingY;
+       float maxControlsHeight = offsetYButtons + buttonOK->Bounds().Height();
+       float familiesWidth = labelFamily->Bounds().Width() * 5;
+       float offsetXStyles = familiesWidth + kVimDialogSpacingX;
+       float stylesWidth = labelStyle->Bounds().Width() * 4;
+       float offsetXSizes = offsetXStyles + stylesWidth + kVimDialogSpacingX;
+       float sizesWidth = labelSize->Bounds().Width() * 2;
+       float maxControlsWidth = offsetXSizes + sizesWidth;
+
+       ResizeTo(maxControlsWidth + kVimDialogSpacingX * 2,
+               maxControlsHeight + kVimDialogSpacingY * 2);
+
+       BRect rcVim = gui.vimWindow->Frame();
+       MoveTo(rcVim.left + (rcVim.Width() - Frame().Width()) / 2,
+                       rcVim.top + (rcVim.Height() - Frame().Height()) / 2);
+
+       fPreview->ResizeTo(maxControlsWidth, previewHeight);
+       fPreview->SetAlignment(B_ALIGN_CENTER);
+
+       boxDivider->MoveBy(0.f, previewHeight + kVimDialogSpacingY / 2);
+       boxDivider->ResizeTo(maxControlsWidth, 1.f);
+
+       labelFamily->MoveBy(0.f, offsetYLabels);
+       labelStyle->MoveBy(offsetXStyles, offsetYLabels);
+       labelSize->MoveBy(offsetXSizes, offsetYLabels);
+
+       //  text control alignment issues
+       float insetX = fSizesInput->TextView()->Bounds().Width() - fSizesInput->Bounds().Width();
+       float insetY = fSizesInput->TextView()->Bounds().Width() - fSizesInput->Bounds().Width();
+
+       scrollFamilies->MoveBy(0.f, offsetYLists);
+       scrollStyles->MoveBy(offsetXStyles, offsetYLists);
+       fSizesInput->MoveBy(offsetXSizes + insetX / 2, offsetYLists + insetY / 2);
+       scrollSizes->MoveBy(offsetXSizes, offsetYSizes);
+
+       fSizesInput->SetAlignment(B_ALIGN_CENTER, B_ALIGN_CENTER);
+
+       scrollFamilies->ResizeTo(familiesWidth, listsHeight);
+       scrollStyles->ResizeTo(stylesWidth, listsHeight);
+       fSizesInput->ResizeTo(sizesWidth, fSizesInput->Bounds().Height());
+       scrollSizes->ResizeTo(sizesWidth,
+                       listsHeight - (offsetYSizes - offsetYLists));
+
+       buttonOK->MoveBy(maxControlsWidth - buttonOK->Bounds().Width(), offsetYButtons);
+       buttonCancel->MoveBy(maxControlsWidth - buttonOK->Bounds().Width()
+                       - buttonCancel->Bounds().Width() - kVimDialogSpacingX, offsetYButtons);
+
+       //  fill lists
+       int selIndex = -1;
+       int count = count_font_families();
+       for (int i = 0; i < count; i++) {
+               font_family family;
+               if (get_font_family(i, &family ) == B_OK) {
+                       fFamiliesList->AddItem(new BStringItem((const char*)family));
+                       if (strncmp(family, fFontFamily, B_FONT_FAMILY_LENGTH) == 0)
+                               selIndex = i;
+               }
+       }
+
+       if (selIndex >= 0) {
+               fFamiliesList->Select(selIndex);
+               fFamiliesList->ScrollToSelection();
+       }
+
+       _UpdateFontStyles();
+
+       selIndex = -1;
+       for (int size = 8, index = 0; size <= 18; size++, index++) {
+               BString str;
+               str << size;
+               fSizesList->AddItem(new BStringItem(str));
+               if (size == fFontSize)
+                       selIndex = index;
+
+       }
+
+       if (selIndex >= 0) {
+               fSizesList->Select(selIndex);
+               fSizesList->ScrollToSelection();
+       }
+
+       fFamiliesList->SetSelectionMessage(new BMessage(kVimDialogFamilySelectMsg));
+       fStylesList->SetSelectionMessage(new BMessage(kVimDialogStyleSelectMsg));
+       fSizesList->SetSelectionMessage(new BMessage(kVimDialogSizeSelectMsg));
+       fSizesInput->SetModificationMessage(new BMessage(kVimDialogSizeInputMsg));
+
+       _UpdateSizeInputPreview();
+       _UpdateFontPreview();
+
+       fStatus = B_OK;
+}
+
+VimSelectFontDialog::~VimSelectFontDialog()
+{
+       _CleanList(fFamiliesList);
+       _CleanList(fStylesList);
+       _CleanList(fSizesList);
+
+       if (fDialogSem > B_OK)
+               delete_sem(fDialogSem);
+}
+
+       void
+VimSelectFontDialog::_CleanList(BListView* list)
+{
+       while(0 < list->CountItems())
+               delete (dynamic_cast<BStringItem*>(list->RemoveItem((int32)0)));
+}
+
+       bool
+VimSelectFontDialog::Go()
+{
+       if (fStatus != B_OK) {
+               Quit();
+               return NOFONT;
+       }
+
+       fDialogSem = create_sem(0, "VimFontSelectDialogSem");
+       if(fDialogSem < B_OK) {
+               Quit();
+               return fDialogValue;
+       }
+
+       Show();
+
+       while(acquire_sem(fDialogSem) == B_INTERRUPTED);
+
+       bool retValue = fDialogValue;
+
+       if(Lock())
+               Quit();
+
+       return retValue;
+}
+
+
+void VimSelectFontDialog::_UpdateFontStyles()
+{
+       _CleanList(fStylesList);
+
+       int32 selIndex = -1;
+       int32 count = count_font_styles(fFontFamily);
+       for (int32 i = 0; i < count; i++) {
+               font_style style;
+               uint32 flags = 0;
+               if (get_font_style(fFontFamily, i, &style, &flags) == B_OK) {
+                       fStylesList->AddItem(new BStringItem((const char*)style));
+                       if (strncmp(style, fFontStyle, B_FONT_STYLE_LENGTH) == 0)
+                               selIndex = i;
+               }
+       }
+
+       if (selIndex >= 0) {
+               fStylesList->Select(selIndex);
+               fStylesList->ScrollToSelection();
+       } else
+               fStylesList->Select(0);
+}
+
+
+void VimSelectFontDialog::_UpdateSizeInputPreview()
+{
+       char buf[10] = {0};
+       vim_snprintf(buf, sizeof(buf), (char*)"%.0f", fFontSize);
+       fSizesInput->SetText(buf);
+}
+
+
+void VimSelectFontDialog::_UpdateFontPreview()
+{
+       BFont font;
+       fPreview->GetFont(&font);
+       font.SetSize(fFontSize);
+       font.SetFamilyAndStyle(fFontFamily, fFontStyle);
+       fPreview->SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE);
+
+       BString str;
+       str << fFontFamily << " " << fFontStyle << ", " << (int)fFontSize << " pt.";
+       fPreview->SetText(str);
+}
+
+
+       bool
+VimSelectFontDialog::_UpdateFromListItem(BListView* list, char* text, int textSize)
+{
+       int32 index = list->CurrentSelection();
+       if (index < 0)
+               return false;
+       BStringItem* item = (BStringItem*)list->ItemAt(index);
+       if (item == NULL)
+               return false;
+       strncpy(text, item->Text(), textSize);
+       return true;
+}
+
+
+void VimSelectFontDialog::MessageReceived(BMessage *msg)
+{
+       switch (msg->what) {
+               case kVimDialogOKButtonMsg:
+                       strncpy(*fFamily, fFontFamily, B_FONT_FAMILY_LENGTH);
+                       strncpy(*fStyle, fFontStyle, B_FONT_STYLE_LENGTH);
+                       *fSize = fFontSize;
+                       fDialogValue = true;
+               case kVimDialogCancelButtonMsg:
+                       delete_sem(fDialogSem);
+                       fDialogSem = -1;
+                       return;
+               case B_KEY_UP:
+                       {
+                               int32 key = 0;
+                               if (msg->FindInt32("raw_char", &key) == B_OK
+                                               && key == B_ESCAPE) {
+                                       delete_sem(fDialogSem);
+                                       fDialogSem = -1;
+                               }
+                       }
+                       break;
+
+               case kVimDialogFamilySelectMsg:
+                       if (_UpdateFromListItem(fFamiliesList,
+                                       fFontFamily, B_FONT_FAMILY_LENGTH)) {
+                               _UpdateFontStyles();
+                               _UpdateFontPreview();
+                       }
+                       break;
+               case kVimDialogStyleSelectMsg:
+                       if (_UpdateFromListItem(fStylesList,
+                                       fFontStyle, B_FONT_STYLE_LENGTH))
+                               _UpdateFontPreview();
+                       break;
+               case kVimDialogSizeSelectMsg:
+                       {
+                               char buf[10] = {0};
+                               if (_UpdateFromListItem(fSizesList,     buf, sizeof(buf))) {
+                                       float size = atof(buf);
+                                       if (size > 0.f) {
+                                               fFontSize = size;
+                                               _UpdateSizeInputPreview();
+                                               _UpdateFontPreview();
+                                       }
+                               }
+                       }
+                       break;
+               case kVimDialogSizeInputMsg:
+                       {
+                               float size = atof(fSizesInput->Text());
+                               if (size > 0.f) {
+                                       fFontSize = size;
+                                       _UpdateFontPreview();
+                               }
+                       }
+                       break;
+               default:
+                       break;
+       }
+       return BWindow::MessageReceived(msg);
+}
+
+#endif // FEAT_GUI_DIALOG
+
+#ifdef FEAT_TOOLBAR
+
+//  some forward declaration required by toolbar functions...
+static BMessage * MenuMessage(vimmenu_T *menu);
+
+VimToolbar::VimToolbar(BRect frame, const char *name) :
+       BBox(frame, name, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_FRAME_EVENTS, B_PLAIN_BORDER)
+{
+}
+
+VimToolbar::~VimToolbar()
+{
+       int32 count = fButtonsList.CountItems();
+       for(int32 i = 0; i < count; i++)
+               delete (BPictureButton*)fButtonsList.ItemAt(i);
+       fButtonsList.MakeEmpty();
+
+       delete normalButtonsBitmap;
+       delete grayedButtonsBitmap;
+       normalButtonsBitmap    = NULL;
+       grayedButtonsBitmap  = NULL;
+}
+
+       void
+VimToolbar::AttachedToWindow()
+{
+       BBox::AttachedToWindow();
+
+       SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
+}
+
+       float
+VimToolbar::ToolbarHeight() const
+{
+       float size = NULL == normalButtonsBitmap ? 18. : normalButtonsBitmap->Bounds().Height();
+       return size + ToolbarMargin * 2 + ButtonMargin * 2 + 1;
+}
+
+       bool
+VimToolbar::ModifyBitmapToGrayed(BBitmap *bitmap)
+{
+       float height = bitmap->Bounds().Height();
+       float width  = bitmap->Bounds().Width();
+
+       rgb_color *bits = (rgb_color*)bitmap->Bits();
+       int32 pixels = bitmap->BitsLength() / 4;
+       for(int32 i = 0; i < pixels; i++) {
+               bits[i].red = bits[i].green =
+               bits[i].blue = ((uint32)bits[i].red + bits[i].green + bits[i].blue) / 3;
+               bits[i].alpha /= 4;
+       }
+
+       return true;
+}
+
+       bool
+VimToolbar::PrepareButtonBitmaps()
+{
+       //  first try to load potentially customized $VIRUNTIME/bitmaps/builtin-tools.png
+       normalButtonsBitmap = LoadVimBitmap("builtin-tools.png");
+       if(normalButtonsBitmap == NULL)
+               //  customized not found? dig application resources for "builtin-tools" one
+               normalButtonsBitmap = BTranslationUtils::GetBitmap(B_PNG_FORMAT, "builtin-tools");
+
+       if(normalButtonsBitmap == NULL)
+               return false;
+
+       BMessage archive;
+       normalButtonsBitmap->Archive(&archive);
+
+       grayedButtonsBitmap = new BBitmap(&archive);
+       if(grayedButtonsBitmap == NULL)
+               return false;
+
+       //  modify grayed bitmap
+       ModifyBitmapToGrayed(grayedButtonsBitmap);
+
+       return true;
+}
+
+BBitmap *VimToolbar::LoadVimBitmap(const char* fileName)
+{
+       BBitmap *bitmap = NULL;
+
+       int mustfree = 0;
+       char_u* runtimePath = vim_getenv((char_u*)"VIMRUNTIME", &mustfree);
+       if(runtimePath != NULL && fileName != NULL) {
+               BString strPath((char*)runtimePath);
+               strPath << "/bitmaps/" << fileName;
+               bitmap = BTranslationUtils::GetBitmap(strPath.String());
+       }
+
+       if(mustfree)
+               vim_free(runtimePath);
+
+       return bitmap;
+}
+
+       bool
+VimToolbar::GetPictureFromBitmap(BPicture *pictureTo, int32 index, BBitmap *bitmapFrom, bool pressed)
+{
+       float size = bitmapFrom->Bounds().Height() + 1.;
+
+       BView view(BRect(0, 0, size, size), "", 0, 0);
+
+       AddChild(&view);
+       view.BeginPicture(pictureTo);
+
+       view.SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
+       view.FillRect(view.Bounds());
+       view.SetDrawingMode(B_OP_OVER);
+
+       BRect source(0, 0, size - 1, size - 1);
+       BRect destination(source);
+
+       source.OffsetBy(size * index, 0);
+       destination.OffsetBy(ButtonMargin, ButtonMargin);
+
+       view.DrawBitmap(bitmapFrom, source, destination);
+
+       if(pressed)     {
+               rgb_color shineColor  = ui_color(B_SHINE_COLOR);
+               rgb_color shadowColor = ui_color(B_SHADOW_COLOR);
+               size += ButtonMargin * 2 - 1;
+               view.BeginLineArray(4);
+               view.AddLine(BPoint(0, 0),               BPoint(size, 0),        shadowColor);
+               view.AddLine(BPoint(size, 0),    BPoint(size, size), shineColor);
+               view.AddLine(BPoint(size, size), BPoint(0, size),        shineColor);
+               view.AddLine(BPoint(0, size),    BPoint(0, 0),           shadowColor);
+               view.EndLineArray();
+       }
+
+       view.EndPicture();
+       RemoveChild(&view);
+
+       return true;
+}
+
+       bool
+VimToolbar::AddButton(int32 index, vimmenu_T *menu)
+{
+       BPictureButton *button = NULL;
+       if(!menu_is_separator(menu->name)) {
+               float size = normalButtonsBitmap ?
+                       normalButtonsBitmap->Bounds().Height() + 1. + ButtonMargin * 2 : 18.;
+               BRect frame(0, 0, size, size);
+               BPicture pictureOn;
+               BPicture pictureOff;
+               BPicture pictureGray;
+
+               if(menu->iconfile == NULL && menu->iconidx >= 0 && normalButtonsBitmap) {
+                       GetPictureFromBitmap(&pictureOn,  menu->iconidx, normalButtonsBitmap, true);
+                       GetPictureFromBitmap(&pictureOff, menu->iconidx, normalButtonsBitmap, false);
+                       GetPictureFromBitmap(&pictureGray, menu->iconidx, grayedButtonsBitmap, false);
+               } else {
+
+                       char_u buffer[MAXPATHL] = {0};
+                       BBitmap *bitmap = NULL;
+
+                       if(menu->iconfile) {
+                               gui_find_iconfile(menu->iconfile, buffer, (char*)"png");
+                               bitmap = BTranslationUtils::GetBitmap((char*)buffer);
+                       }
+
+                       if(bitmap == NULL && gui_find_bitmap(menu->name, buffer, (char*)"png") == OK)
+                               bitmap = BTranslationUtils::GetBitmap((char*)buffer);
+
+                       if(bitmap == NULL)
+                               bitmap = new BBitmap(BRect(0, 0, size, size), B_RGB32);
+
+                       GetPictureFromBitmap(&pictureOn,   0, bitmap, true);
+                       GetPictureFromBitmap(&pictureOff,  0, bitmap, false);
+                       ModifyBitmapToGrayed(bitmap);
+                       GetPictureFromBitmap(&pictureGray, 0, bitmap, false);
+
+                       delete bitmap;
+               }
+
+               button = new BPictureButton(frame, (char*)menu->name,
+                                       &pictureOff, &pictureOn, MenuMessage(menu));
+
+               button->SetDisabledOn(&pictureGray);
+               button->SetDisabledOff(&pictureGray);
+
+               button->SetTarget(gui.vimTextArea);
+
+               AddChild(button);
+
+               menu->button = button;
+       }
+
+       bool result = fButtonsList.AddItem(button, index);
+       InvalidateLayout();
+       return result;
+}
+
+       bool
+VimToolbar::RemoveButton(vimmenu_T *menu)
+{
+       if(menu->button) {
+               if(fButtonsList.RemoveItem(menu->button)) {
+                       delete menu->button;
+                       menu->button = NULL;
+               }
+       }
+}
+
+       bool
+VimToolbar::GrayButton(vimmenu_T *menu, int grey)
+{
+       if(menu->button) {
+               int32 index = fButtonsList.IndexOf(menu->button);
+               if(index >= 0)
+                       menu->button->SetEnabled(grey ? false : true);
+       }
+}
+
+       void
+VimToolbar::InvalidateLayout()
+{
+       int32 offset = ToolbarMargin;
+       int32 count = fButtonsList.CountItems();
+       for(int32 i = 0; i < count; i++) {
+               BPictureButton *button = (BPictureButton *)fButtonsList.ItemAt(i);
+               if(button) {
+                       button->MoveTo(offset, ToolbarMargin);
+                       offset += button->Bounds().Width() + ToolbarMargin;
+               } else
+                       offset += ToolbarMargin * 3;
+       }
+}
+
+#endif /*FEAT_TOOLBAR*/
+
+#if defined(FEAT_GUI_TABLINE)
+
+       float
+VimTabLine::TablineHeight() const
+{
+//     float size = NULL == normalButtonsBitmap ? 18. : normalButtonsBitmap->Bounds().Height();
+//     return size + ToolbarMargin * 2 + ButtonMargin * 2 + 1;
+       return TabHeight(); //  + ToolbarMargin;
+}
+
+void
+VimTabLine::MouseDown(BPoint point)
+{
+       if(!gui_mch_showing_tabline())
+               return;
+
+       BMessage *m = Window()->CurrentMessage();
+       assert(m);
+
+       int32 buttons = 0;
+       m->FindInt32("buttons", &buttons);
+
+       int32 clicks = 0;
+       m->FindInt32("clicks", &clicks);
+
+       int index = 0; //  0 means here - no tab found
+       for (int i = 0; i < CountTabs(); i++) {
+               if(TabFrame(i).Contains(point)) {
+                       index = i + 1; //  indexes are 1-based
+                       break;
+               }
+       }
+
+       int event = -1;
+
+       if ((buttons & B_PRIMARY_MOUSE_BUTTON) && clicks > 1)
+               //  left button double click on - create new tab
+               event = TABLINE_MENU_NEW;
+
+       else if (buttons & B_TERTIARY_MOUSE_BUTTON)
+               //  middle button click - close the pointed tab
+               //  or create new one in case empty space
+               event = index > 0 ? TABLINE_MENU_CLOSE : TABLINE_MENU_NEW;
+
+       else if (buttons & B_SECONDARY_MOUSE_BUTTON) {
+               //  right button click - show context menu
+               BPopUpMenu* popUpMenu = new BPopUpMenu("tabLineContextMenu", false, false);
+               popUpMenu->AddItem(new BMenuItem(_("Close tabi R"), new BMessage(TABLINE_MENU_CLOSE)));
+               popUpMenu->AddItem(new BMenuItem(_("New tab    T"), new BMessage(TABLINE_MENU_NEW)));
+               popUpMenu->AddItem(new BMenuItem(_("Open tab..."), new BMessage(TABLINE_MENU_OPEN)));
+
+               ConvertToScreen(&point);
+               BMenuItem* item = popUpMenu->Go(point);
+               if (item != NULL) {
+                       event = item->Command();
+               }
+
+               delete popUpMenu;
+
+       } else {
+               //  default processing
+               BTabView::MouseDown(point);
+               return;
+       }
+
+       if (event < 0)
+               return;
+
+       VimTablineMenuMsg tmm;
+       tmm.index = index;
+       tmm.event = event;
+       write_port(gui.vdcmp, VimMsg::TablineMenu, &tmm, sizeof(tmm));
+}
+
+void
+VimTabLine::VimTab::Select(BView* owner)
+{
+       BTab::Select(owner);
+
+       VimTabLine *tabLine = gui.vimForm->TabLine();
+       if(tabLine != NULL) {
+
+               int32 i = 0;
+               for (; i < tabLine->CountTabs(); i++)
+                       if(this == tabLine->TabAt(i))
+                               break;
+
+//             printf("%d:%d:%s\n", i, tabLine->CountTabs(), tabLine->TabAt(i)->Label());
+               if(i < tabLine->CountTabs()) {
+                       VimTablineMsg tm;
+                       tm.index = i + 1;
+                       write_port(gui.vdcmp, VimMsg::Tabline, &tm, sizeof(tm));
+               }
+       }
+}
+
+#endif //  defined(FEAT_GUI_TABLINE)
+
+// ---------------- ----------------
+
+//  some global variables
+static char appsig[] = "application/x-vnd.Haiku-Vim-8";
+key_map *keyMap;
+char *keyMapChars;
+int main_exitcode = 127;
+
+       status_t
+gui_haiku_process_event(bigtime_t timeout)
+{
+       struct VimMsg vm;
+       int32 what;
+       ssize_t size;
+
+       size = read_port_etc(gui.vdcmp, &what, &vm, sizeof(vm),
+                       B_TIMEOUT, timeout);
+
+       if (size >= 0) {
+               switch (what) {
+                       case VimMsg::Key:
+                               {
+                                       char_u *string = vm.u.Key.chars;
+                                       int len = vm.u.Key.length;
+                                       if (len == 1 && string[0] == Ctrl_chr('C')) {
+                                               trash_input_buf();
+                                               got_int = TRUE;
+                                       }
+
+                                       if (vm.u.Key.csi_escape)
+#ifndef FEAT_MBYTE_IME
+                                       {
+                                               int             i;
+                                               char_u  buf[2];
+
+                                               for (i = 0; i < len; ++i)
+                                               {
+                                                       add_to_input_buf(string + i, 1);
+                                                       if (string[i] == CSI)
+                                                       {
+                                                               // Turn CSI into K_CSI.
+                                                               buf[0] = KS_EXTRA;
+                                                               buf[1] = (int)KE_CSI;
+                                                               add_to_input_buf(buf, 2);
+                                                       }
+                                               }
+                                       }
+#else
+                                       add_to_input_buf_csi(string, len);
+#endif
+                                       else
+                                               add_to_input_buf(string, len);
+                               }
+                               break;
+                       case VimMsg::Resize:
+                               gui_resize_shell(vm.u.NewSize.width, vm.u.NewSize.height);
+                               break;
+                       case VimMsg::ScrollBar:
+                               {
+                                       /*
+                                        * If loads of scroll messages queue up, use only the last
+                                        * one. Always report when the scrollbar stops dragging.
+                                        * This is not perfect yet anyway: these events are queued
+                                        * yet again, this time in the keyboard input buffer.
+                                        */
+                                       int32 oldCount =
+                                               atomic_add(&vm.u.Scroll.sb->scrollEventCount, -1);
+                                       if (oldCount <= 1 || !vm.u.Scroll.stillDragging)
+                                               gui_drag_scrollbar(vm.u.Scroll.sb->getGsb(),
+                                                               vm.u.Scroll.value, vm.u.Scroll.stillDragging);
+                               }
+                               break;
+#if defined(FEAT_MENU)
+                       case VimMsg::Menu:
+                               gui_menu_cb(vm.u.Menu.guiMenu);
+                               break;
+#endif
+                       case VimMsg::Mouse:
+                               {
+                                       int32 oldCount;
+                                       if (vm.u.Mouse.button == MOUSE_DRAG)
+                                               oldCount =
+                                                       atomic_add(&gui.vimTextArea->mouseDragEventCount, -1);
+                                       else
+                                               oldCount = 0;
+                                       if (oldCount <= 1)
+                                               gui_send_mouse_event(vm.u.Mouse.button, vm.u.Mouse.x,
+                                                               vm.u.Mouse.y, vm.u.Mouse.repeated_click,
+                                                               vm.u.Mouse.modifiers);
+                               }
+                               break;
+                       case VimMsg::MouseMoved:
+                               {
+                                       gui_mouse_moved(vm.u.MouseMoved.x, vm.u.MouseMoved.y);
+                               }
+                               break;
+                       case VimMsg::Focus:
+                               gui.in_focus = vm.u.Focus.active;
+                               // XXX Signal that scrollbar dragging has stopped?
+                               // This is needed because we don't get a MouseUp if
+                               // that happens while outside the window... :-(
+                               if (gui.dragged_sb) {
+                                       gui.dragged_sb = SBAR_NONE;
+                               }
+                               //  gui_update_cursor(TRUE, FALSE);
+                               break;
+                       case VimMsg::Refs:
+                               ::RefsReceived(vm.u.Refs.message, vm.u.Refs.changedir);
+                               break;
+                       case VimMsg::Tabline:
+                               send_tabline_event(vm.u.Tabline.index);
+                               break;
+                       case VimMsg::TablineMenu:
+                               send_tabline_menu_event(vm.u.TablineMenu.index, vm.u.TablineMenu.event);
+                               break;
+                       default:
+                               //  unrecognised message, ignore it
+                               break;
+               }
+       }
+
+       /*
+        * If size < B_OK, it is an error code.
+        */
+       return size;
+}
+
+/*
+ * Here are some functions to protect access to ScreenLines[] and
+ * LineOffset[]. These are used from the window thread to respond
+ * to a Draw() callback. When that occurs, the window is already
+ * locked by the system.
+ *
+ * Other code that needs to lock is any code that changes these
+ * variables. Other read-only access, or access merely to the
+ * contents of the screen buffer, need not be locked.
+ *
+ * If there is no window, don't call Lock() but do succeed.
+ */
+
+       int
+vim_lock_screen()
+{
+       return !gui.vimWindow || gui.vimWindow->Lock();
+}
+
+       void
+vim_unlock_screen()
+{
+       if (gui.vimWindow)
+               gui.vimWindow->Unlock();
+}
+
+#define RUN_BAPPLICATION_IN_NEW_THREAD 0
+
+#if RUN_BAPPLICATION_IN_NEW_THREAD
+
+       int32
+run_vimapp(void *args)
+{
+       VimApp app(appsig);
+
+       gui.vimApp = &app;
+       app.Run();                          // Run until Quit() called
+
+       return 0;
+}
+
+#else
+
+       int32
+call_main(void *args)
+{
+       struct MainArgs *ma = (MainArgs *)args;
+
+       return main(ma->argc, ma->argv);
+}
+#endif
+
+/*
+ * Parse the GUI related command-line arguments.  Any arguments used are
+ * deleted from argv, and *argc is decremented accordingly.  This is called
+ * when vim is started, whether or not the GUI has been started.
+ */
+       void
+gui_mch_prepare(
+               int             *argc,
+               char    **argv)
+{
+       /*
+        * We don't have any command line arguments for the BeOS GUI yet,
+        * but this is an excellent place to create our Application object.
+        */
+       if (!gui.vimApp) {
+               thread_info tinfo;
+               get_thread_info(find_thread(NULL), &tinfo);
+
+               // May need the port very early on to process RefsReceived()
+               gui.vdcmp = create_port(B_MAX_PORT_COUNT, "vim VDCMP");
+
+#if RUN_BAPPLICATION_IN_NEW_THREAD
+               thread_id tid = spawn_thread(run_vimapp, "vim VimApp",
+                               tinfo.priority, NULL);
+               if (tid >= B_OK) {
+                       resume_thread(tid);
+               } else {
+                       getout(1);
+               }
+#else
+               MainArgs ma = { *argc, argv };
+               thread_id tid = spawn_thread(call_main, "vim main()",
+                               tinfo.priority, &ma);
+               if (tid >= B_OK) {
+                       VimApp app(appsig);
+
+                       gui.vimApp = &app;
+                       resume_thread(tid);
+                       /*
+                        * This is rather horrible.
+                        * call_main will call main() again...
+                        * There will be no infinite recursion since
+                        * gui.vimApp is set now.
+                        */
+                       app.Run();                          // Run until Quit() called
+                       // fprintf(stderr, "app.Run() returned...\n");
+                       status_t dummy_exitcode;
+                       (void)wait_for_thread(tid, &dummy_exitcode);
+
+                       /*
+                        * This path should be the normal one taken to exit Vim.
+                        * The main() thread calls mch_exit() which calls
+                        * gui_mch_exit() which terminates its thread.
+                        */
+                       exit(main_exitcode);
+               }
+#endif
+       }
+       // Don't fork() when starting the GUI. Spawned threads are not
+       // duplicated with a fork(). The result is a mess.
+       gui.dofork = FALSE;
+       /*
+        * XXX Try to determine whether we were started from
+        * the Tracker or the terminal.
+        * It would be nice to have this work, because the Tracker
+        * follows symlinks, so even if you double-click on gvim,
+        * when it is a link to vim it will still pass a command name
+        * of vim...
+        * We try here to see if stdin comes from /dev/null. If so,
+        * (or if there is an error, which should never happen) start the GUI.
+        * This does the wrong thing for vim - </dev/null, and we're
+        * too early to see the command line parsing. Tough.
+        * On the other hand, it starts the gui for vim file & which is nice.
+        */
+       if (!isatty(0)) {
+               struct stat stat_stdin, stat_dev_null;
+
+               if (fstat(0, &stat_stdin) == -1 ||
+                               stat("/dev/null", &stat_dev_null) == -1 ||
+                               (stat_stdin.st_dev == stat_dev_null.st_dev &&
+                                stat_stdin.st_ino == stat_dev_null.st_ino))
+                       gui.starting = TRUE;
+       }
+}
+
+/*
+ * Check if the GUI can be started.  Called before gvimrc is sourced.
+ * Return OK or FAIL.
+ */
+       int
+gui_mch_init_check(void)
+{
+       return OK;              // TODO: GUI can always be started?
+}
+
+/*
+ * Initialise the GUI.  Create all the windows, set up all the call-backs
+ * etc.
+ */
+       int
+gui_mch_init()
+{
+    display_errors();
+       gui.def_norm_pixel = RGB(0x00, 0x00, 0x00);     //  black
+       gui.def_back_pixel = RGB(0xFF, 0xFF, 0xFF);     //  white
+       gui.norm_pixel = gui.def_norm_pixel;
+       gui.back_pixel = gui.def_back_pixel;
+
+       gui.scrollbar_width = (int) B_V_SCROLL_BAR_WIDTH;
+       gui.scrollbar_height = (int) B_H_SCROLL_BAR_HEIGHT;
+#ifdef FEAT_MENU
+       gui.menu_height = 19;   //  initial guess -
+       //  correct for my default settings
+#endif
+       gui.border_offset = 3;  //  coordinates are inside window borders
+
+       if (gui.vdcmp < B_OK)
+               return FAIL;
+       get_key_map(&keyMap, &keyMapChars);
+
+       gui.vimWindow = new VimWindow();        // hidden and locked
+       if (!gui.vimWindow)
+               return FAIL;
+
+       gui.vimWindow->Run();           // Run() unlocks but does not show
+
+       // Get the colors from the "Normal" group (set in syntax.c or in a vimrc
+       // file)
+       set_normal_colors();
+
+       /*
+        * Check that none of the colors are the same as the background color
+        */
+       gui_check_colors();
+
+       // Get the colors for the highlight groups (gui_check_colors() might have
+       // changed them)
+       highlight_gui_started();                // re-init colors and fonts
+
+       gui_mch_new_colors();           // window must exist for this
+
+       return OK;
+}
+
+/*
+ * Called when the foreground or background color has been changed.
+ */
+       void
+gui_mch_new_colors()
+{
+       rgb_color rgb = GUI_TO_RGB(gui.back_pixel);
+
+       if (gui.vimWindow->Lock()) {
+               gui.vimForm->SetViewColor(rgb);
+               //  Does this not have too much effect for those small rectangles?
+               gui.vimForm->Invalidate();
+               gui.vimWindow->Unlock();
+       }
+}
+
+/*
+ * Open the GUI window which was created by a call to gui_mch_init().
+ */
+       int
+gui_mch_open()
+{
+       if (gui_win_x != -1 && gui_win_y != -1)
+               gui_mch_set_winpos(gui_win_x, gui_win_y);
+
+       // Actually open the window
+       if (gui.vimWindow->Lock()) {
+               gui.vimWindow->Show();
+               gui.vimWindow->Unlock();
+               return OK;
+       }
+
+       return FAIL;
+}
+
+       void
+gui_mch_exit(int vim_exitcode)
+{
+       if (gui.vimWindow) {
+               thread_id tid = gui.vimWindow->Thread();
+               gui.vimWindow->Lock();
+               gui.vimWindow->Quit();
+               // Wait until it is truely gone
+               int32 exitcode;
+               wait_for_thread(tid, &exitcode);
+       }
+       delete_port(gui.vdcmp);
+#if !RUN_BAPPLICATION_IN_NEW_THREAD
+       /*
+        * We are in the main() thread - quit the App thread and
+        * quit ourselves (passing on the exitcode). Use a global since the
+        * value from exit_thread() is only used if wait_for_thread() is
+        * called in time (race condition).
+        */
+#endif
+       if (gui.vimApp) {
+               VimTextAreaView::guiBlankMouse(false);
+
+               main_exitcode = vim_exitcode;
+#if RUN_BAPPLICATION_IN_NEW_THREAD
+               thread_id tid = gui.vimApp->Thread();
+               int32 exitcode;
+               gui.vimApp->Lock();
+               gui.vimApp->Quit();
+               gui.vimApp->Unlock();
+               wait_for_thread(tid, &exitcode);
+#else
+               gui.vimApp->Lock();
+               gui.vimApp->Quit();
+               gui.vimApp->Unlock();
+               // suicide
+               exit_thread(vim_exitcode);
+#endif
+       }
+       // If we are somehow still here, let mch_exit() handle things.
+}
+
+/*
+ * Get the position of the top left corner of the window.
+ */
+       int
+gui_mch_get_winpos(int *x, int *y)
+{
+       if (gui.vimWindow->Lock()) {
+               BRect r;
+               r = gui.vimWindow->Frame();
+               gui.vimWindow->Unlock();
+               *x = (int)r.left;
+               *y = (int)r.top;
+               return OK;
+       }
+       else
+               return FAIL;
+}
+
+/*
+ * Set the position of the top left corner of the window to the given
+ * coordinates.
+ */
+       void
+gui_mch_set_winpos(int x, int y)
+{
+       if (gui.vimWindow->Lock()) {
+               gui.vimWindow->MoveTo(x, y);
+               gui.vimWindow->Unlock();
+       }
+}
+
+/*
+ * Set the size of the window to the given width and height in pixels.
+ */
+void
+gui_mch_set_shellsize(
+               int             width,
+               int             height,
+               int             min_width,
+               int             min_height,
+               int             base_width,
+               int             base_height,
+               int             direction) // TODO: utilize?
+{
+       /*
+        * We are basically given the size of the VimForm, if I understand
+        * correctly. Since it fills the window completely, this will also
+        * be the size of the window.
+        */
+       if (gui.vimWindow->Lock()) {
+               gui.vimWindow->ResizeTo(width - PEN_WIDTH, height - PEN_WIDTH);
+
+               // set size limits
+               float minWidth, maxWidth, minHeight, maxHeight;
+
+               gui.vimWindow->GetSizeLimits(&minWidth, &maxWidth,
+                               &minHeight, &maxHeight);
+               gui.vimWindow->SetSizeLimits(min_width, maxWidth,
+                               min_height, maxHeight);
+
+               /*
+                * Set the resizing alignment depending on font size.
+                */
+               gui.vimWindow->SetWindowAlignment(
+                               B_PIXEL_ALIGNMENT,              //  window_alignment mode,
+                               1,                              //  int32 h,
+                               0,                              //  int32 hOffset = 0,
+                               gui.char_width,         //  int32 width = 0,
+                               base_width,                     //  int32 widthOffset = 0,
+                               1,                              //  int32 v = 0,
+                               0,                              //  int32 vOffset = 0,
+                               gui.char_height,                //  int32 height = 0,
+                               base_height                     //  int32 heightOffset = 0
+                               );
+
+               gui.vimWindow->Unlock();
+       }
+}
+
+void
+gui_mch_get_screen_dimensions(
+               int             *screen_w,
+               int             *screen_h)
+{
+       BRect frame;
+
+       {
+               BScreen screen(gui.vimWindow);
+
+               if (screen.IsValid()) {
+                       frame = screen.Frame();
+               } else {
+                       frame.right = 640;
+                       frame.bottom = 480;
+               }
+       }
+
+       // XXX approximations...
+       *screen_w = (int) frame.right - 2 * gui.scrollbar_width - 20;
+       *screen_h = (int) frame.bottom - gui.scrollbar_height
+#ifdef FEAT_MENU
+               - gui.menu_height
+#endif
+               - 30;
+}
+
+void
+gui_mch_set_text_area_pos(
+               int             x,
+               int             y,
+               int             w,
+               int             h)
+{
+       if (!gui.vimTextArea)
+               return;
+
+       if (gui.vimWindow->Lock()) {
+               gui.vimTextArea->MoveTo(x, y);
+               gui.vimTextArea->ResizeTo(w - PEN_WIDTH, h - PEN_WIDTH);
+
+/*#ifdef FEAT_GUI_TABLINE
+               if(gui.vimForm->TabLine() != NULL) {
+                       gui.vimForm->TabLine()->ResizeTo(w, gui.vimForm->TablineHeight());
+               }
+#endif // FEAT_GUI_TABLINE
+
+               gui.vimWindow->Unlock();
+       }
+}
+
+
+/*
+ * Scrollbar stuff:
+ */
+
+void
+gui_mch_enable_scrollbar(
+               scrollbar_T     *sb,
+               int             flag)
+{
+       VimScrollBar *vsb = sb->id;
+       if (gui.vimWindow->Lock()) {
+               /*
+                * This function is supposed to be idempotent, but Show()/Hide()
+                * is not. Therefore we test if they are needed.
+                */
+               if (flag) {
+                       if (vsb->IsHidden()) {
+                               vsb->Show();
+                       }
+               } else {
+                       if (!vsb->IsHidden()) {
+                               vsb->Hide();
+                       }
+               }
+               gui.vimWindow->Unlock();
+       }
+}
+
+void
+gui_mch_set_scrollbar_thumb(
+               scrollbar_T *sb,
+               int             val,
+               int             size,
+               int             max)
+{
+       if (gui.vimWindow->Lock()) {
+               VimScrollBar *s = sb->id;
+               if (max == 0) {
+                       s->SetValue(0);
+                       s->SetRange(0.0, 0.0);
+               } else {
+                       s->SetProportion((float)size / (max + 1.0));
+                       s->SetSteps(1.0, size > 5 ? size - 2 : size);
+#ifndef SCROLL_PAST_END                //  really only defined in gui.c...
+                       max = max + 1 - size;
+#endif
+                       if (max < s->Value()) {
+                               /*
+                                * If the new maximum is lower than the current value,
+                                * setting it would cause the value to be clipped and
+                                * therefore a ValueChanged() call.
+                                * We avoid this by setting the value first, because
+                                * it presumably is <= max.
+                                */
+                               s->SetValue(val);
+                               s->SetRange(0.0, max);
+                       } else {
+                               /*
+                                * In the other case, set the range first, since the
+                                * new value might be higher than the current max.
+                                */
+                               s->SetRange(0.0, max);
+                               s->SetValue(val);
+                       }
+               }
+               gui.vimWindow->Unlock();
+       }
+}
+
+void
+gui_mch_set_scrollbar_pos(
+               scrollbar_T *sb,
+               int             x,
+               int             y,
+               int             w,
+               int             h)
+{
+       if (gui.vimWindow->Lock()) {
+               BRect winb = gui.vimWindow->Bounds();
+               float vsbx = x, vsby = y;
+               VimScrollBar *vsb = sb->id;
+               vsb->ResizeTo(w - PEN_WIDTH, h - PEN_WIDTH);
+               if(winb.right-(x+w)<w) vsbx = winb.right - (w - PEN_WIDTH);
+               vsb->MoveTo(vsbx, vsby);
+               gui.vimWindow->Unlock();
+       }
+}
+
+void
+gui_mch_create_scrollbar(
+               scrollbar_T *sb,
+               int             orient)         // SBAR_VERT or SBAR_HORIZ
+{
+       orientation posture =
+               (orient == SBAR_HORIZ) ? B_HORIZONTAL : B_VERTICAL;
+
+       VimScrollBar *vsb = sb->id = new VimScrollBar(sb, posture);
+       if (gui.vimWindow->Lock()) {
+               vsb->SetTarget(gui.vimTextArea);
+               vsb->Hide();
+               gui.vimForm->AddChild(vsb);
+               gui.vimWindow->Unlock();
+       }
+}
+
+#if defined(FEAT_WINDOWS) || defined(PROTO)
+void
+gui_mch_destroy_scrollbar(
+               scrollbar_T     *sb)
+{
+       if (gui.vimWindow->Lock()) {
+               sb->id->RemoveSelf();
+               delete sb->id;
+               gui.vimWindow->Unlock();
+       }
+}
+#endif
+
+/*
+ * Cursor does not flash
+ */
+    int
+gui_mch_is_blink_off(void)
+{
+    return FALSE;
+}
+
+/*
+ * Cursor blink functions.
+ *
+ * This is a simple state machine:
+ * BLINK_NONE  not blinking at all
+ * BLINK_OFF   blinking, cursor is not shown
+ * BLINK_ON    blinking, cursor is shown
+ */
+
+#define BLINK_NONE  0
+#define BLINK_OFF   1
+#define BLINK_ON    2
+
+static int             blink_state = BLINK_NONE;
+static long_u          blink_waittime = 700;
+static long_u          blink_ontime = 400;
+static long_u          blink_offtime = 250;
+static int     blink_timer = 0;
+
+void
+gui_mch_set_blinking(
+               long    waittime,
+               long    on,
+               long    off)
+{
+       // TODO
+       blink_waittime = waittime;
+       blink_ontime = on;
+       blink_offtime = off;
+}
+
+/*
+ * Stop the cursor blinking.  Show the cursor if it wasn't shown.
+ */
+       void
+gui_mch_stop_blink()
+{
+       // TODO
+       if (blink_timer != 0)
+       {
+               // XtRemoveTimeOut(blink_timer);
+               blink_timer = 0;
+       }
+       if (blink_state == BLINK_OFF)
+               gui_update_cursor(TRUE, FALSE);
+       blink_state = BLINK_NONE;
+}
+
+/*
+ * Start the cursor blinking.  If it was already blinking, this restarts the
+ * waiting time and shows the cursor.
+ */
+       void
+gui_mch_start_blink()
+{
+       // TODO
+       if (blink_timer != 0)
+               ;// XtRemoveTimeOut(blink_timer);
+       // Only switch blinking on if none of the times is zero
+       if (blink_waittime && blink_ontime && blink_offtime && gui.in_focus)
+       {
+               blink_timer = 1; // XtAppAddTimeOut(app_context, blink_waittime,
+               blink_state = BLINK_ON;
+               gui_update_cursor(TRUE, FALSE);
+       }
+}
+
+/*
+ * Initialise vim to use the font with the given name. Return FAIL if the font
+ * could not be loaded, OK otherwise.
+ */
+int
+gui_mch_init_font(
+               char_u          *font_name,
+               int                     fontset)
+{
+       if (gui.vimWindow->Lock())
+       {
+               int rc = gui.vimTextArea->mchInitFont(font_name);
+               gui.vimWindow->Unlock();
+
+               return rc;
+       }
+
+       return FAIL;
+}
+
+
+       int
+gui_mch_adjust_charsize()
+{
+       return FAIL;
+}
+
+
+       int
+gui_mch_font_dialog(font_family* family, font_style* style, float* size)
+{
+#if defined(FEAT_GUI_DIALOG)
+               // gui.vimWindow->Unlock();
+       VimSelectFontDialog *dialog = new VimSelectFontDialog(family, style, size);
+       return dialog->Go();
+#else
+       return NOFONT;
+#endif // FEAT_GUI_DIALOG
+}
+
+
+GuiFont
+gui_mch_get_font(
+               char_u          *name,
+               int                     giveErrorIfMissing)
+{
+       static VimFont *fontList = NULL;
+
+       if (!gui.in_use)        //  can't do this when GUI not running
+               return NOFONT;
+
+       //  storage for locally modified name;
+       const int buff_size = B_FONT_FAMILY_LENGTH + B_FONT_STYLE_LENGTH + 20;
+       static char font_name[buff_size] = {0};
+       font_family family = {0};
+       font_style  style  = {0};
+       float size = 0.f;
+
+       if (name == 0 && be_fixed_font == 0) {
+               if(giveErrorIfMissing)
+                        semsg(_(e_font), name);
+               return NOFONT;
+       }
+
+       bool useSelectGUI = false;
+       if (name != NULL)
+               if (STRCMP(name, "*") == 0) {
+                       useSelectGUI = true;
+                       STRNCPY(font_name, hl_get_font_name(), buff_size);
+               } else
+                       STRNCPY(font_name, name, buff_size);
+
+       if (font_name[0] == 0) {
+               be_fixed_font->GetFamilyAndStyle(&family, &style);
+               size = be_fixed_font->Size();
+               vim_snprintf(font_name, buff_size,
+                       (char*)"%s/%s/%.0f", family, style, size);
+       }
+
+       //  replace underscores with spaces
+       char* end = 0;
+       while (end = strchr((char *)font_name, '_'))
+               *end = ' ';
+
+       //  store the name before strtok corrupt the buffer ;-)
+       static char buff[buff_size] = {0};
+       STRNCPY(buff, font_name, buff_size);
+       STRNCPY(family, strtok(buff, "/\0"), B_FONT_FAMILY_LENGTH);
+       char* style_s = strtok(0, "/\0");
+       if (style_s != 0)
+               STRNCPY(style, style_s, B_FONT_STYLE_LENGTH);
+       size = atof((style_s != 0) ? strtok(0, "/\0") : "0");
+
+       if (useSelectGUI) {
+               if(gui_mch_font_dialog(&family, &style, &size) == NOFONT)
+                       return FAIL;
+               //  compose for further processing
+               vim_snprintf(font_name, buff_size,
+                               (char*)"%s/%s/%.0f", family, style, size);
+               hl_set_font_name((char_u*)font_name);
+
+               //  Set guifont to the name of the selected font.
+               char_u* 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 = '_';
+               }
+       }
+
+       VimFont *flp;
+       for (flp = fontList; flp; flp = flp->next) {
+               if (STRCMP(font_name, flp->name) == 0) {
+                       flp->refcount++;
+                       return (GuiFont)flp;
+               }
+       }
+
+       VimFont *font = new VimFont();
+       font->name = vim_strsave((char_u*)font_name);
+
+       if(count_font_styles(family) <= 0) {
+               if (giveErrorIfMissing)
+                        semsg(_(e_font), font->name);
+               delete font;
+               return NOFONT;
+       }
+
+       //  Remember font in the static list for later use
+       font->next = fontList;
+       fontList = font;
+
+       font->SetFamilyAndStyle(family, style);
+       if(size > 0.f)
+               font->SetSize(size);
+
+       font->SetSpacing(B_FIXED_SPACING);
+       font->SetEncoding(B_UNICODE_UTF8);
+
+       return (GuiFont)font;
+}
+
+/*
+ * Set the current text font.
+ */
+void
+gui_mch_set_font(
+               GuiFont font)
+{
+       if (gui.vimWindow->Lock()) {
+               VimFont *vf = (VimFont *)font;
+
+               gui.vimTextArea->SetFont(vf);
+
+               gui.char_width = (int) vf->StringWidth("n");
+               font_height fh;
+               vf->GetHeight(&fh);
+               gui.char_height = (int)(fh.ascent + 0.9999)
+                       + (int)(fh.descent + 0.9999) + (int)(fh.leading + 0.9999);
+               gui.char_ascent = (int)(fh.ascent + 0.9999);
+
+               gui.vimWindow->Unlock();
+       }
+}
+
+// XXX TODO This is apparently never called...
+void
+gui_mch_free_font(
+               GuiFont font)
+{
+       if(font == NOFONT)
+               return;
+       VimFont *f = (VimFont *)font;
+       if (--f->refcount <= 0) {
+               if (f->refcount < 0)
+                       fprintf(stderr, "VimFont: refcount < 0\n");
+               delete f;
+       }
+}
+
+       char_u *
+gui_mch_get_fontname(GuiFont font, char_u *name)
+{
+       if (name == NULL)
+               return NULL;
+       return vim_strsave(name);
+}
+
+/*
+ * Adjust gui.char_height (after 'linespace' was changed).
+ */
+       int
+gui_mch_adjust_charheight()
+{
+
+       // TODO: linespace support?
+
+// #ifdef FEAT_XFONTSET
+//     if (gui.fontset != NOFONTSET)
+//     {
+//     gui.char_height = fontset_height((XFontSet)gui.fontset) + p_linespace;
+//     gui.char_ascent = fontset_ascent((XFontSet)gui.fontset)
+//     + p_linespace / 2;
+//     }
+//     else
+// #endif
+       {
+               VimFont *font = (VimFont *)gui.norm_font;
+               font_height fh = {0};
+               font->GetHeight(&fh);
+               gui.char_height = (int)(fh.ascent + fh.descent + 0.5) + p_linespace;
+               gui.char_ascent = (int)(fh.ascent + 0.5) + p_linespace / 2;
+       }
+       return OK;
+}
+
+/*
+ * Display the saved error message(s).
+ */
+#ifdef USE_MCH_ERRMSG
+    void
+display_errors(void)
+{
+    char       *p;
+    char_u     pError[256];
+
+    if (error_ga.ga_data == NULL)
+       return;
+
+    // avoid putting up a message box with blanks only
+    for (p = (char *)error_ga.ga_data; *p; ++p)
+       if (!isspace(*p))
+       {
+           if (STRLEN(p) > 255)
+               pError[0] = 255;
+           else
+               pError[0] = STRLEN(p);
+
+           STRNCPY(&pError[1], p, pError[0]);
+//         ParamText(pError, nil, nil, nil);
+//         Alert(128, nil);
+           break;
+           // TODO: handled message longer than 256 chars
+           //   use auto-sizeable alert
+           //   or dialog with scrollbars (TextEdit zone)
+       }
+    ga_clear(&error_ga);
+}
+#endif
+
+       void
+gui_mch_getmouse(int *x, int *y)
+{
+       fprintf(stderr, "gui_mch_getmouse");
+
+       /*int           rootx, rooty, winx, winy;
+         Window        root, child;
+         unsigned int mask;
+
+         if (gui.wid && XQueryPointer(gui.dpy, gui.wid, &root, &child,
+         &rootx, &rooty, &winx, &winy, &mask)) {
+        *x = winx;
+        *y = winy;
+        } else*/ {
+                *x = -1;
+                *y = -1;
+        }
+}
+
+       void
+gui_mch_mousehide(int hide)
+{
+       fprintf(stderr, "gui_mch_getmouse");
+       //  TODO
+}
+
+       static int
+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;
+}
+
+/*
+ * This function has been lifted from gui_w32.c and extended a bit.
+ *
+ * Return the Pixel value (color) for the given color name.
+ * Return INVALCOLOR for error.
+ */
+guicolor_T
+gui_mch_get_color(
+               char_u  *name)
+{
+       typedef struct GuiColourTable
+       {
+               const char    *name;
+               guicolor_T     colour;
+       } GuiColourTable;
+
+#define NSTATIC_COLOURS                50 // 32
+#define NDYNAMIC_COLOURS       33
+#define NCOLOURS               (NSTATIC_COLOURS + NDYNAMIC_COLOURS)
+
+       static GuiColourTable table[NCOLOURS] =
+       {
+               {"Black",           RGB(0x00, 0x00, 0x00)},
+               {"DarkGray",        RGB(0x80, 0x80, 0x80)},
+               {"DarkGrey",        RGB(0x80, 0x80, 0x80)},
+               {"Gray",            RGB(0xC0, 0xC0, 0xC0)},
+               {"Grey",            RGB(0xC0, 0xC0, 0xC0)},
+               {"LightGray",       RGB(0xD3, 0xD3, 0xD3)},
+               {"LightGrey",       RGB(0xD3, 0xD3, 0xD3)},
+               {"Gray10",          RGB(0x1A, 0x1A, 0x1A)},
+               {"Grey10",          RGB(0x1A, 0x1A, 0x1A)},
+               {"Gray20",          RGB(0x33, 0x33, 0x33)},
+               {"Grey20",          RGB(0x33, 0x33, 0x33)},
+               {"Gray30",          RGB(0x4D, 0x4D, 0x4D)},
+               {"Grey30",          RGB(0x4D, 0x4D, 0x4D)},
+               {"Gray40",          RGB(0x66, 0x66, 0x66)},
+               {"Grey40",          RGB(0x66, 0x66, 0x66)},
+               {"Gray50",          RGB(0x7F, 0x7F, 0x7F)},
+               {"Grey50",          RGB(0x7F, 0x7F, 0x7F)},
+               {"Gray60",          RGB(0x99, 0x99, 0x99)},
+               {"Grey60",          RGB(0x99, 0x99, 0x99)},
+               {"Gray70",          RGB(0xB3, 0xB3, 0xB3)},
+               {"Grey70",          RGB(0xB3, 0xB3, 0xB3)},
+               {"Gray80",          RGB(0xCC, 0xCC, 0xCC)},
+               {"Grey80",          RGB(0xCC, 0xCC, 0xCC)},
+               {"Gray90",          RGB(0xE5, 0xE5, 0xE5)},
+               {"Grey90",          RGB(0xE5, 0xE5, 0xE5)},
+               {"White",           RGB(0xFF, 0xFF, 0xFF)},
+               {"DarkRed",         RGB(0x80, 0x00, 0x00)},
+               {"Red",             RGB(0xFF, 0x00, 0x00)},
+               {"LightRed",        RGB(0xFF, 0xA0, 0xA0)},
+               {"DarkBlue",        RGB(0x00, 0x00, 0x80)},
+               {"Blue",            RGB(0x00, 0x00, 0xFF)},
+               {"LightBlue",       RGB(0xA0, 0xA0, 0xFF)},
+               {"DarkGreen",       RGB(0x00, 0x80, 0x00)},
+               {"Green",           RGB(0x00, 0xFF, 0x00)},
+               {"LightGreen",      RGB(0xA0, 0xFF, 0xA0)},
+               {"DarkCyan",        RGB(0x00, 0x80, 0x80)},
+               {"Cyan",            RGB(0x00, 0xFF, 0xFF)},
+               {"LightCyan",       RGB(0xA0, 0xFF, 0xFF)},
+               {"DarkMagenta",     RGB(0x80, 0x00, 0x80)},
+               {"Magenta",         RGB(0xFF, 0x00, 0xFF)},
+               {"LightMagenta",    RGB(0xFF, 0xA0, 0xFF)},
+               {"Brown",           RGB(0x80, 0x40, 0x40)},
+               {"Yellow",          RGB(0xFF, 0xFF, 0x00)},
+               {"LightYellow",     RGB(0xFF, 0xFF, 0xA0)},
+               {"DarkYellow",      RGB(0xBB, 0xBB, 0x00)},
+               {"SeaGreen",        RGB(0x2E, 0x8B, 0x57)},
+               {"Orange",          RGB(0xFF, 0xA5, 0x00)},
+               {"Purple",          RGB(0xA0, 0x20, 0xF0)},
+               {"SlateBlue",       RGB(0x6A, 0x5A, 0xCD)},
+               {"Violet",          RGB(0xEE, 0x82, 0xEE)},
+               //  NOTE: some entries are zero-allocated for NDDYNAMIC_COLORS
+               //               in this table!
+       };
+
+       static int endColour = NSTATIC_COLOURS;
+       static int newColour = NSTATIC_COLOURS;
+
+       int                 r, g, b;
+       int                 i;
+
+       if (name[0] == '#' && STRLEN(name) == 7)
+       {
+               // Name is in "#rrggbb" format
+               r = hex_digit(name[1]) * 16 + hex_digit(name[2]);
+               g = hex_digit(name[3]) * 16 + hex_digit(name[4]);
+               b = hex_digit(name[5]) * 16 + hex_digit(name[6]);
+               if (r < 0 || g < 0 || b < 0)
+                       return INVALCOLOR;
+               return RGB(r, g, b);
+       }
+       else
+       {
+               // Check if the name is one of the colours we know
+               for (i = 0; i < endColour; i++)
+                       if (STRICMP(name, table[i].name) == 0)
+                               return table[i].colour;
+       }
+
+       /*
+        * Last attempt. Look in the file "$VIMRUNTIME/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    *colour;
+
+                       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;
+
+                       colour = line + pos;
+
+                       if (STRICMP(colour, name) == 0)
+                       {
+                               fclose(fd);
+                               /*
+                                * Now remember this colour in the table.
+                                * A LRU scheme might be better but this is simpler.
+                                * Or could use a growing array.
+                                */
+                               guicolor_T gcolour = RGB(r,g,b);
+
+                               // NOTE: see note above in table allocation! We are working here with
+                               //              dynamically allocated names, not constant ones!
+                               vim_free((char*)table[newColour].name);
+                               table[newColour].name = (char *)vim_strsave((char_u *)colour);
+                               table[newColour].colour = gcolour;
+
+                               newColour++;
+                               if (newColour >= NCOLOURS)
+                                       newColour = NSTATIC_COLOURS;
+                               if (endColour < NCOLOURS)
+                                       endColour = newColour;
+
+                               return gcolour;
+                       }
+               }
+
+               fclose(fd);
+       }
+
+       return INVALCOLOR;
+}
+
+/*
+ * Set the current text foreground color.
+ */
+void
+gui_mch_set_fg_color(
+               guicolor_T      color)
+{
+       rgb_color rgb = GUI_TO_RGB(color);
+       if (gui.vimWindow->Lock()) {
+               gui.vimTextArea->SetHighColor(rgb);
+               gui.vimWindow->Unlock();
+       }
+}
+
+/*
+ * Set the current text background color.
+ */
+void
+gui_mch_set_bg_color(
+               guicolor_T      color)
+{
+       rgb_color rgb = GUI_TO_RGB(color);
+       if (gui.vimWindow->Lock()) {
+               gui.vimTextArea->SetLowColor(rgb);
+               gui.vimWindow->Unlock();
+       }
+}
+
+/*
+ * Set the current text special color.
+ */
+       void
+gui_mch_set_sp_color(guicolor_T        color)
+{
+       // prev_sp_color = color;
+}
+
+void
+gui_mch_draw_string(
+               int             row,
+               int             col,
+               char_u  *s,
+               int             len,
+               int             flags)
+{
+       if (gui.vimWindow->Lock()) {
+               gui.vimTextArea->mchDrawString(row, col, s, len, flags);
+               gui.vimWindow->Unlock();
+       }
+}
+
+        guicolor_T
+gui_mch_get_rgb_color(int r, int g, int b)
+{
+    return gui_get_rgb_color_cmn(r, g, b);
+}
+
+
+// Return OK if the key with the termcap name "name" is supported.
+int
+gui_mch_haskey(
+               char_u  *name)
+{
+       int i;
+
+       for (i = 0; special_keys[i].BeKeys != 0; i++)
+               if (name[0] == special_keys[i].vim_code0 &&
+                               name[1] == special_keys[i].vim_code1)
+                       return OK;
+       return FAIL;
+}
+
+       void
+gui_mch_beep()
+{
+       ::beep();
+}
+
+       void
+gui_mch_flash(int msec)
+{
+       // Do a visual beep by reversing the foreground and background colors
+
+       if (gui.vimWindow->Lock()) {
+               BRect rect = gui.vimTextArea->Bounds();
+
+               gui.vimTextArea->SetDrawingMode(B_OP_INVERT);
+               gui.vimTextArea->FillRect(rect);
+               gui.vimTextArea->Sync();
+               snooze(msec * 1000);     // wait for a few msec
+               gui.vimTextArea->FillRect(rect);
+               gui.vimTextArea->SetDrawingMode(B_OP_COPY);
+               gui.vimTextArea->Flush();
+               gui.vimWindow->Unlock();
+       }
+}
+
+/*
+ * Invert a rectangle from row r, column c, for nr rows and nc columns.
+ */
+void
+gui_mch_invert_rectangle(
+               int             r,
+               int             c,
+               int             nr,
+               int             nc)
+{
+       BRect rect;
+       rect.left = FILL_X(c);
+       rect.top = FILL_Y(r);
+       rect.right = rect.left + nc * gui.char_width - PEN_WIDTH;
+       rect.bottom = rect.top + nr * gui.char_height - PEN_WIDTH;
+
+       if (gui.vimWindow->Lock()) {
+               gui.vimTextArea->SetDrawingMode(B_OP_INVERT);
+               gui.vimTextArea->FillRect(rect);
+               gui.vimTextArea->SetDrawingMode(B_OP_COPY);
+               gui.vimWindow->Unlock();
+       }
+}
+
+/*
+ * Iconify the GUI window.
+ */
+       void
+gui_mch_iconify()
+{
+       if (gui.vimWindow->Lock()) {
+               gui.vimWindow->Minimize(true);
+               gui.vimWindow->Unlock();
+       }
+}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Bring the Vim window to the foreground.
+ */
+       void
+gui_mch_set_foreground(void)
+{
+       // TODO
+}
+#endif
+
+/*
+ * Set the window title
+ */
+void
+gui_mch_settitle(
+               char_u  *title,
+               char_u  *icon)
+{
+       if (gui.vimWindow->Lock()) {
+               gui.vimWindow->SetTitle((char *)title);
+               gui.vimWindow->Unlock();
+       }
+}
+
+/*
+ * Draw a cursor without focus.
+ */
+       void
+gui_mch_draw_hollow_cursor(guicolor_T color)
+{
+       gui_mch_set_fg_color(color);
+
+       BRect r;
+       r.left = FILL_X(gui.col);
+       r.top = FILL_Y(gui.row);
+       int cells = utf_off2cells(LineOffset[gui.row] + gui.col, 100); // TODO-TODO
+       if(cells>=4) cells = 1;
+       r.right = r.left + cells*gui.char_width - PEN_WIDTH;
+       r.bottom = r.top + gui.char_height - PEN_WIDTH;
+
+       if (gui.vimWindow->Lock()) {
+               gui.vimTextArea->StrokeRect(r);
+               gui.vimWindow->Unlock();
+               // gui_mch_flush();
+       }
+}
+
+/*
+ * Draw part of a cursor, only w pixels wide, and h pixels high.
+ */
+void
+gui_mch_draw_part_cursor(
+               int             w,
+               int             h,
+               guicolor_T      color)
+{
+       gui_mch_set_fg_color(color);
+
+       BRect r;
+       r.left =
+#ifdef FEAT_RIGHTLEFT
+               // vertical line should be on the right of current point
+               CURSOR_BAR_RIGHT ? FILL_X(gui.col + 1) - w :
+#endif
+               FILL_X(gui.col);
+       r.right = r.left + w - PEN_WIDTH;
+       r.bottom = FILL_Y(gui.row + 1) - PEN_WIDTH;
+       r.top = r.bottom - h + PEN_WIDTH;
+
+       if (gui.vimWindow->Lock()) {
+               gui.vimTextArea->FillRect(r);
+               gui.vimWindow->Unlock();
+               // gui_mch_flush();
+       }
+}
+
+/*
+ * Catch up with any queued events.  This may put keyboard input into the
+ * input buffer, call resize call-backs, trigger timers etc.  If there is
+ * nothing in the event queue (& no timers pending), then we return
+ * immediately.
+ */
+       void
+gui_mch_update()
+{
+       gui_mch_flush();
+       while (port_count(gui.vdcmp) > 0 &&
+                       !vim_is_input_buf_full() &&
+                       gui_haiku_process_event(0) >= B_OK)
+               /* nothing */ ;
+}
+
+/*
+ * GUI input routine called by gui_wait_for_chars().  Waits for a character
+ * from the keyboard.
+ *     wtime == -1             Wait forever.
+ *     wtime == 0              This should never happen.
+ *     wtime > 0               Wait wtime milliseconds for a character.
+ * Returns OK if a character was found to be available within the given time,
+ * or FAIL otherwise.
+ */
+int
+gui_mch_wait_for_chars(
+               int             wtime)
+{
+       int                 focus;
+       bigtime_t           until, timeout;
+       status_t            st;
+
+       if (wtime >= 0) {
+               timeout = wtime * 1000;
+               until = system_time() + timeout;
+       } else {
+               timeout = B_INFINITE_TIMEOUT;
+       }
+
+       focus = gui.in_focus;
+       for (;;)
+       {
+               // Stop or start blinking when focus changes
+               if (gui.in_focus != focus)
+               {
+                       if (gui.in_focus)
+                               gui_mch_start_blink();
+                       else
+                               gui_mch_stop_blink();
+                       focus = gui.in_focus;
+               }
+
+               gui_mch_flush();
+               /*
+                * Don't use gui_mch_update() because then we will spin-lock until a
+                * char arrives, instead we use gui_haiku_process_event() to hang until
+                * an event arrives.  No need to check for input_buf_full because we
+                * are returning as soon as it contains a single char.
+                */
+               st = gui_haiku_process_event(timeout);
+
+               if (input_available())
+                       return OK;
+               if (st < B_OK)              // includes B_TIMED_OUT
+                       return FAIL;
+
+               /*
+                * Calculate how much longer we're willing to wait for the
+                * next event.
+                */
+               if (wtime >= 0) {
+                       timeout = until - system_time();
+                       if (timeout < 0)
+                               break;
+               }
+       }
+       return FAIL;
+
+}
+
+/*
+ * Output routines.
+ */
+
+/*
+ * Flush any output to the screen. This is typically called before
+ * the app goes to sleep.
+ */
+       void
+gui_mch_flush()
+{
+       //  does this need to lock the window? Apparently not but be safe.
+       if (gui.vimWindow->Lock()) {
+               gui.vimWindow->Flush();
+               gui.vimWindow->Unlock();
+       }
+       return;
+}
+
+/*
+ * Clear a rectangular region of the screen from text pos (row1, col1) to
+ * (row2, col2) inclusive.
+ */
+void
+gui_mch_clear_block(
+               int             row1,
+               int             col1,
+               int             row2,
+               int             col2)
+{
+       if (gui.vimWindow->Lock()) {
+               gui.vimTextArea->mchClearBlock(row1, col1, row2, col2);
+               gui.vimWindow->Unlock();
+       }
+}
+
+       void
+gui_mch_clear_all()
+{
+       if (gui.vimWindow->Lock()) {
+               gui.vimTextArea->mchClearAll();
+               gui.vimWindow->Unlock();
+       }
+}
+
+/*
+ * Delete the given number of lines from the given row, scrolling up any
+ * text further down within the scroll region.
+ */
+void
+gui_mch_delete_lines(
+               int             row,
+               int             num_lines)
+{
+       gui.vimTextArea->mchDeleteLines(row, num_lines);
+}
+
+/*
+ * Insert the given number of lines before the given row, scrolling down any
+ * following text within the scroll region.
+ */
+void
+gui_mch_insert_lines(
+               int             row,
+               int             num_lines)
+{
+       gui.vimTextArea->mchInsertLines(row, num_lines);
+}
+
+#if defined(FEAT_MENU) || defined(PROTO)
+/*
+ * Menu stuff.
+ */
+
+void
+gui_mch_enable_menu(
+               int             flag)
+{
+       if (gui.vimWindow->Lock())
+       {
+               BMenuBar *menubar = gui.vimForm->MenuBar();
+               menubar->SetEnabled(flag);
+               gui.vimWindow->Unlock();
+       }
+}
+
+void
+gui_mch_set_menu_pos(
+               int             x,
+               int             y,
+               int             w,
+               int             h)
+{
+       // It will be in the right place anyway
+}
+
+/*
+ * Add a sub menu to the menu bar.
+ */
+void
+gui_mch_add_menu(
+               vimmenu_T       *menu,
+               int             idx)
+{
+       vimmenu_T       *parent = menu->parent;
+
+       //  popup menu - just create it unattached
+       if (menu_is_popup(menu->name) && parent == NULL) {
+               BPopUpMenu* popUpMenu = new BPopUpMenu((const char*)menu->name, false, false);
+               menu->submenu_id = popUpMenu;
+               menu->id = NULL;
+               return;
+       }
+
+       if (!menu_is_menubar(menu->name)
+                       || (parent != NULL && parent->submenu_id == NULL))
+               return;
+
+       if (gui.vimWindow->Lock())
+       {
+               // Major re-write of the menu code, it was failing with memory corruption when
+               // we started loading multiple files (the Buffer menu)
+               //
+               // Note we don't use the preference values yet, all are inserted into the
+               // menubar on a first come-first served basis...
+               //
+               // richard@whitequeen.com jul 99
+
+               BMenu *tmp;
+
+               if ( parent )
+                       tmp = parent->submenu_id;
+               else
+                       tmp = gui.vimForm->MenuBar();
+               //  make sure we don't try and add the same menu twice. The Buffers menu tries to
+               //  do this and Be starts to crash...
+
+               if ( ! tmp->FindItem((const char *) menu->dname)) {
+
+                       BMenu *bmenu = new BMenu((char *)menu->dname);
+
+                       menu->submenu_id = bmenu;
+
+                       //  when we add a BMenu to another Menu, it creates the interconnecting BMenuItem
+                       tmp->AddItem(bmenu);
+
+                       //  Now its safe to query the menu for the associated MenuItem....
+                       menu->id = tmp->FindItem((const char *) menu->dname);
+
+               }
+               gui.vimWindow->Unlock();
+       }
+}
+
+       void
+gui_mch_toggle_tearoffs(int enable)
+{
+       // no tearoff menus
+}
+
+       static BMessage *
+MenuMessage(vimmenu_T *menu)
+{
+       BMessage *m = new BMessage('menu');
+       m->AddPointer("VimMenu", (void *)menu);
+
+       return m;
+}
+
+/*
+ * Add a menu item to a menu
+ */
+void
+gui_mch_add_menu_item(
+               vimmenu_T       *menu,
+               int             idx)
+{
+       int             mnemonic = 0;
+       vimmenu_T       *parent = menu->parent;
+
+       // TODO: use menu->actext
+       // This is difficult, since on Be, an accelerator must be a single char
+       // and a lot of Vim ones are the standard VI commands.
+       //
+       // Punt for Now...
+       // richard@whiequeen.com jul 99
+       if (gui.vimWindow->Lock())
+       {
+#ifdef FEAT_TOOLBAR
+               if(menu_is_toolbar(parent->name)) {
+                       VimToolbar *toolbar = gui.vimForm->ToolBar();
+                       if(toolbar != NULL) {
+                               toolbar->AddButton(idx, menu);
+                       }
+               } else
+#endif
+
+               if (parent->submenu_id != NULL || menu_is_popup(parent->name)) {
+                       if (menu_is_separator(menu->name)) {
+                               BSeparatorItem *item = new BSeparatorItem();
+                               parent->submenu_id->AddItem(item);
+                               menu->id = item;
+                               menu->submenu_id = NULL;
+                       }
+                       else {
+                               BMenuItem *item = new BMenuItem((char *)menu->dname,
+                                               MenuMessage(menu));
+                               item->SetTarget(gui.vimTextArea);
+                               item->SetTrigger((char) menu->mnemonic);
+                               parent->submenu_id->AddItem(item);
+                               menu->id = item;
+                               menu->submenu_id = NULL;
+                       }
+               }
+               gui.vimWindow->Unlock();
+       }
+}
+
+/*
+ * Destroy the machine specific menu widget.
+ */
+void
+gui_mch_destroy_menu(
+               vimmenu_T       *menu)
+{
+       if (gui.vimWindow->Lock())
+       {
+#ifdef FEAT_TOOLBAR
+               if(menu->parent && menu_is_toolbar(menu->parent->name)) {
+                       VimToolbar *toolbar = gui.vimForm->ToolBar();
+                       if(toolbar != NULL) {
+                               toolbar->RemoveButton(menu);
+                       }
+               } else
+#endif
+               {
+                       assert(menu->submenu_id == NULL || menu->submenu_id->CountItems() == 0);
+                       /*
+                        * Detach this menu from its parent, so that it is not deleted
+                        * twice once we get to delete that parent.
+                        * Deleting a BMenuItem also deletes the associated BMenu, if any
+                        * (which does not have any items anymore since they were
+                        * removed and deleted before).
+                        */
+                       BMenu *bmenu = menu->id->Menu();
+                       if (bmenu)
+                       {
+                               bmenu->RemoveItem(menu->id);
+                               /*
+                                * If we removed the last item from the menu bar,
+                                * resize it out of sight.
+                                */
+                               if (bmenu == gui.vimForm->MenuBar() && bmenu->CountItems() == 0)
+                               {
+                                       bmenu->ResizeTo(-MENUBAR_MARGIN, -MENUBAR_MARGIN);
+                               }
+                       }
+                       delete menu->id;
+                       menu->id = NULL;
+                       menu->submenu_id = NULL;
+
+                       gui.menu_height = (int) gui.vimForm->MenuHeight();
+               }
+               gui.vimWindow->Unlock();
+       }
+}
+
+/*
+ * Make a menu either grey or not grey.
+ */
+void
+gui_mch_menu_grey(
+               vimmenu_T       *menu,
+               int             grey)
+{
+#ifdef FEAT_TOOLBAR
+       if(menu->parent && menu_is_toolbar(menu->parent->name)) {
+               if (gui.vimWindow->Lock()) {
+                       VimToolbar *toolbar = gui.vimForm->ToolBar();
+                       if(toolbar != NULL) {
+                               toolbar->GrayButton(menu, grey);
+                       }
+                       gui.vimWindow->Unlock();
+               }
+       } else
+#endif
+       if (menu->id != NULL)
+               menu->id->SetEnabled(!grey);
+}
+
+/*
+ * Make menu item hidden or not hidden
+ */
+void
+gui_mch_menu_hidden(
+               vimmenu_T       *menu,
+               int             hidden)
+{
+       if (menu->id != NULL)
+               menu->id->SetEnabled(!hidden);
+}
+
+/*
+ * This is called after setting all the menus to grey/hidden or not.
+ */
+       void
+gui_mch_draw_menubar()
+{
+       // Nothing to do in BeOS
+}
+
+       void
+gui_mch_show_popupmenu(vimmenu_T *menu)
+{
+       if (!menu_is_popup(menu->name) || menu->submenu_id == NULL)
+               return;
+
+       BPopUpMenu* popupMenu = dynamic_cast<BPopUpMenu*>(menu->submenu_id);
+       if (popupMenu == NULL)
+               return;
+
+       BPoint point;
+       if(gui.vimWindow->Lock()) {
+               uint32 buttons = 0;
+               gui.vimTextArea->GetMouse(&point, &buttons);
+               gui.vimTextArea->ConvertToScreen(&point);
+               gui.vimWindow->Unlock();
+       }
+       popupMenu->Go(point, true);
+}
+
+#endif // FEAT_MENU
+
+// Mouse stuff
+
+#ifdef FEAT_CLIPBOARD
+/*
+ * Clipboard stuff, for cutting and pasting text to other windows.
+ */
+char textplain[] = "text/plain";
+char vimselectiontype[] = "application/x-vnd.Rhialto-Vim-selectiontype";
+
+/*
+ * Get the current selection and put it in the clipboard register.
+ */
+       void
+clip_mch_request_selection(Clipboard_T *cbd)
+{
+       if (be_clipboard->Lock())
+       {
+               BMessage *m = be_clipboard->Data();
+               // m->PrintToStream();
+
+               char_u *string = NULL;
+               ssize_t stringlen = -1;
+
+               if (m->FindData(textplain, B_MIME_TYPE,
+                                       (const void **)&string, &stringlen) == B_OK
+                               || m->FindString("text", (const char **)&string) == B_OK)
+               {
+                       if (stringlen == -1)
+                               stringlen = STRLEN(string);
+
+                       int type;
+                       char *seltype;
+                       ssize_t seltypelen;
+
+                       /*
+                        * Try to get the special vim selection type first
+                        */
+                       if (m->FindData(vimselectiontype, B_MIME_TYPE,
+                                               (const void **)&seltype, &seltypelen) == B_OK)
+                       {
+                               switch (*seltype)
+                               {
+                                       default:
+                                       case 'L':       type = MLINE;   break;
+                                       case 'C':       type = MCHAR;   break;
+#ifdef FEAT_VISUAL
+                                       case 'B':       type = MBLOCK;  break;
+#endif
+                               }
+                       }
+                       else
+                       {
+                               // Otherwise use heuristic as documented
+                               type = memchr(string, stringlen, '\n') ? MLINE : MCHAR;
+                       }
+                       clip_yank_selection(type, string, (long)stringlen, cbd);
+               }
+               be_clipboard->Unlock();
+       }
+}
+/*
+ * Make vim the owner of the current selection.
+ */
+       void
+clip_mch_lose_selection(Clipboard_T *cbd)
+{
+       // Nothing needs to be done here
+}
+
+/*
+ * Make vim the owner of the current selection.  Return OK upon success.
+ */
+       int
+clip_mch_own_selection(Clipboard_T *cbd)
+{
+       /*
+        * Never actually own the clipboard.  If another application sets the
+        * clipboard, we don't want to think that we still own it.
+        */
+       return FAIL;
+}
+
+/*
+ * Send the current selection to the clipboard.
+ */
+       void
+clip_mch_set_selection(Clipboard_T *cbd)
+{
+       if (be_clipboard->Lock())
+       {
+               be_clipboard->Clear();
+               BMessage *m = be_clipboard->Data();
+               assert(m);
+
+               // If the '*' register isn't already filled in, fill it in now
+               cbd->owned = TRUE;
+               clip_get_selection(cbd);
+               cbd->owned = FALSE;
+
+               char_u  *str = NULL;
+               long_u  count;
+               int     type;
+
+               type = clip_convert_selection(&str, &count, cbd);
+
+               if (type < 0)
+                       return;
+
+               m->AddData(textplain, B_MIME_TYPE, (void *)str, count);
+
+               // Add type of selection
+               char    vtype;
+               switch (type)
+               {
+                       default:
+                       case MLINE:    vtype = 'L';    break;
+                       case MCHAR:    vtype = 'C';    break;
+#ifdef FEAT_VISUAL
+                       case MBLOCK:   vtype = 'B';    break;
+#endif
+               }
+               m->AddData(vimselectiontype, B_MIME_TYPE, (void *)&vtype, 1);
+
+               vim_free(str);
+
+               be_clipboard->Commit();
+               be_clipboard->Unlock();
+       }
+}
+
+#endif // FEAT_CLIPBOARD
+
+#ifdef FEAT_BROWSE
+/*
+ * Pop open a file browser and return the file selected, in allocated memory,
+ * or NULL if Cancel is hit.
+ *  saving  - TRUE if the file will be saved to, FALSE if it will be opened.
+ *  title   - Title message for the file browser dialog.
+ *  dflt    - Default name of file.
+ *  ext     - Default extension to be added to files without extensions.
+ *  initdir - directory in which to open the browser (NULL = current dir)
+ *  filter  - Filter for matched files to choose from.
+ *  Has a format like this:
+ *  "C Files (*.c)\0*.c\0"
+ *  "All Files\0*.*\0\0"
+ *  If these two strings were concatenated, then a choice of two file
+ *  filters will be selectable to the user.  Then only matching files will
+ *  be shown in the browser.  If NULL, the default allows all files.
+ *
+ *  *NOTE* - the filter string must be terminated with TWO nulls.
+ */
+char_u *
+gui_mch_browse(
+               int saving,
+               char_u *title,
+               char_u *dflt,
+               char_u *ext,
+               char_u *initdir,
+               char_u *filter)
+{
+       gui.vimApp->fFilePanel = new BFilePanel((saving == TRUE) ? B_SAVE_PANEL : B_OPEN_PANEL,
+                       NULL, NULL, 0, false,
+                       new BMessage((saving == TRUE) ? 'save' : 'open'), NULL, true);
+
+       gui.vimApp->fBrowsedPath.Unset();
+
+       gui.vimApp->fFilePanel->Window()->SetTitle((char*)title);
+       gui.vimApp->fFilePanel->SetPanelDirectory((const char*)initdir);
+
+       gui.vimApp->fFilePanel->Show();
+
+       gui.vimApp->fFilePanelSem = create_sem(0, "FilePanelSem");
+
+       while(acquire_sem(gui.vimApp->fFilePanelSem) == B_INTERRUPTED);
+
+       char_u *fileName = NULL;
+       status_t result = gui.vimApp->fBrowsedPath.InitCheck();
+       if(result == B_OK) {
+               fileName = vim_strsave((char_u*)gui.vimApp->fBrowsedPath.Path());
+       } else
+               if(result != B_NO_INIT) {
+                       fprintf(stderr, "gui_mch_browse: BPath error: %#08x (%s)\n",
+                                       result, strerror(result));
+               }
+
+       delete gui.vimApp->fFilePanel;
+       gui.vimApp->fFilePanel = NULL;
+
+       return fileName;
+}
+#endif // FEAT_BROWSE
+
+
+#if defined(FEAT_GUI_DIALOG)
+
+/*
+ * Create a dialog dynamically from the parameter strings.
+ * type                = type of dialog (question, alert, etc.)
+ * title       = dialog title. may be NULL for default title.
+ * message     = text to display. Dialog sizes to accommodate it.
+ * buttons     = '\n' separated list of button captions, default first.
+ * dfltbutton  = number of default button.
+ *
+ * This routine returns 1 if the first button is pressed,
+ *                     2 for the second, etc.
+ *
+ *                     0 indicates Esc was pressed.
+ *                     -1 for unexpected error
+ *
+ * If stubbing out this fn, return 1.
+ */
+
+int
+gui_mch_dialog(
+               int              type,
+               char_u  *title,
+               char_u  *message,
+               char_u  *buttons,
+               int              dfltbutton,
+               char_u  *textfield,
+               int ex_cmd)
+{
+       VimDialog *dialog = new VimDialog(type, (char*)title, (char*)message,
+                       (char*)buttons, dfltbutton, (char*)textfield, ex_cmd);
+       return dialog->Go();
+}
+
+#endif // FEAT_GUI_DIALOG
+
+
+/*
+ * Return the RGB value of a pixel as long.
+ */
+    guicolor_T
+gui_mch_get_rgb(guicolor_T pixel)
+{
+       rgb_color rgb = GUI_TO_RGB(pixel);
+
+       return ((rgb.red & 0xff) << 16) + ((rgb.green & 0xff) << 8)
+               + (rgb.blue & 0xff);
+}
+
+       void
+gui_mch_setmouse(int x, int y)
+{
+       TRACE();
+       // TODO
+}
+
+#ifdef FEAT_MBYTE_IME
+       void
+im_set_position(int row, int col)
+{
+       if(gui.vimWindow->Lock())
+       {
+               gui.vimTextArea->DrawIMString();
+               gui.vimWindow->Unlock();
+       }
+       return;
+}
+#endif
+
+       void
+gui_mch_show_toolbar(int showit)
+{
+       VimToolbar *toolbar = gui.vimForm->ToolBar();
+       gui.toolbar_height = (toolbar && showit) ? toolbar->ToolbarHeight() : 0.;
+}
+
+       void
+gui_mch_set_toolbar_pos(int x, int y, int w, int h)
+{
+       VimToolbar *toolbar = gui.vimForm->ToolBar();
+       if(toolbar != NULL) {
+               if (gui.vimWindow->Lock()) {
+                       toolbar->MoveTo(x, y);
+                       toolbar->ResizeTo(w - 1, h - 1);
+                       gui.vimWindow->Unlock();
+               }
+       }
+}
+
+#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
+
+/*
+ * Show or hide the tabline.
+ */
+    void
+gui_mch_show_tabline(int showit)
+{
+       VimTabLine *tabLine = gui.vimForm->TabLine();
+
+    if (tabLine == NULL)
+               return;
+
+    if (!showit != !gui.vimForm->IsShowingTabLine()) {
+               gui.vimForm->SetShowingTabLine(showit != 0);
+               gui.tabline_height = gui.vimForm->TablineHeight();
+    }
+}
+
+       void
+gui_mch_set_tabline_pos(int x, int y, int w, int h)
+{
+       VimTabLine *tabLine = gui.vimForm->TabLine();
+       if(tabLine != NULL) {
+               if (gui.vimWindow->Lock()) {
+                       tabLine->MoveTo(x, y);
+                       tabLine->ResizeTo(w - 1, h - 1);
+                       gui.vimWindow->Unlock();
+               }
+       }
+}
+
+/*
+ * Return TRUE when tabline is displayed.
+ */
+    int
+gui_mch_showing_tabline()
+{
+       VimTabLine *tabLine = gui.vimForm->TabLine();
+    return tabLine != NULL && gui.vimForm->IsShowingTabLine();
+}
+
+/*
+ * Update the labels of the tabline.
+ */
+    void
+gui_mch_update_tabline()
+{
+    tabpage_T  *tp;
+    int                nr = 0;
+    int                curtabidx = 0;
+
+       VimTabLine *tabLine = gui.vimForm->TabLine();
+
+    if (tabLine == NULL)
+               return;
+
+       gui.vimWindow->Lock();
+
+    // Add a label for each tab page.  They all contain the same text area.
+    for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr) {
+               if (tp == curtab)
+                   curtabidx = nr;
+
+               BTab* tab = tabLine->TabAt(nr);
+
+               if (tab == NULL) {
+                       tab = new VimTabLine::VimTab();
+                       tabLine->AddTab(NULL, tab);
+               }
+
+               get_tabline_label(tp, FALSE);
+               tab->SetLabel((const char*)NameBuff);
+               tabLine->Invalidate();
+    }
+
+    // Remove any old labels.
+       while (nr < tabLine->CountTabs())
+               tabLine->RemoveTab(nr);
+
+       if(tabLine->Selection() != curtabidx)
+               tabLine->Select(curtabidx);
+
+       gui.vimWindow->Unlock();
+}
+
+/*
+ * Set the current tab to "nr".  First tab is 1.
+ */
+    void
+gui_mch_set_curtab(int nr)
+{
+       VimTabLine *tabLine = gui.vimForm->TabLine();
+       if(tabLine == NULL)
+               return;
+
+       gui.vimWindow->Lock();
+
+       if(tabLine->Selection() != nr -1)
+               tabLine->Select(nr -1);
+
+       gui.vimWindow->Unlock();
+}
+
+#endif // FEAT_GUI_TABLINE
diff --git a/src/gui_haiku.h b/src/gui_haiku.h
new file mode 100644 (file)
index 0000000..ed8ec70
--- /dev/null
@@ -0,0 +1,51 @@
+/* vi:set ts=8 sts=4 sw=4:
+ *
+ * VIM - Vi IMproved           by Bram Moolenaar
+ *                             GUI support by Olaf "Rhialto" Seibert
+ *
+ * Do ":help uganda"  in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ *
+ * Haiku GUI.
+ *
+ * Based on "GUI support for the Buzzword Enhanced Operating System for PPC."
+ *
+ */
+
+/*
+ * This file must be acceptable both as C and C++.
+ * The BeOS API is defined in terms of C++, but some classes
+ * should be somewhat known in the common C code.
+ */
+
+// System classes
+
+struct BMenu;
+struct BMenuItem;
+struct BPictureButton;
+
+// Our own Vim-related classes
+
+struct VimApp;
+struct VimFormView;
+struct VimTextAreaView;
+struct VimWindow;
+struct VimScrollBar;
+
+// Locking functions
+
+extern int vim_lock_screen();
+extern void vim_unlock_screen();
+
+#ifndef __cplusplus
+
+typedef struct BMenu BMenu;
+typedef struct BMenuItem BMenuItem;
+typedef struct BPictureButton BPictureButton;
+typedef struct VimWindow VimWindow;
+typedef struct VimFormView VimFormView;
+typedef struct VimTextAreaView VimTextAreaView;
+typedef struct VimApp VimApp;
+typedef struct VimScrollBar VimScrollBar;
+
+#endif
index abb07ae5d977bf2f9200443a748fbbda23de7b54..802df49214dee45be87bc75fdbd8e37ef7a19fa9 100644 (file)
@@ -6488,7 +6488,7 @@ im_set_active(int active_arg)
 #  endif
 }
 
-#  if defined(FEAT_GUI) && !defined(VIMDLL)
+#  if defined(FEAT_GUI) && !defined(FEAT_GUI_HAIKU) && !defined(VIMDLL)
     void
 im_set_position(int row UNUSED, int col UNUSED)
 {
index d82f04d8ff122873771da9c49152882c37723792..c57a6c1a6f6ead25adffd5b6b8397e0170b40a7c 100644 (file)
@@ -2525,7 +2525,7 @@ winbar_click(win_T *wp, int col)
 }
 
 #if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_GTK) \
-       || defined(FEAT_TERM_POPUP_MENU) \
+       || defined(FEAT_TERM_POPUP_MENU) || defined(FEAT_GUI_HAIKU) \
        || defined(FEAT_BEVAL_TIP) || defined(PROTO)
 /*
  * Given a menu descriptor, e.g. "File.New", find it in the menu hierarchy.
index 635b87be2aa5b029ef47da98407444d8028d33ca..80aefd81267cbda0122f2dec0925c735a3744382 100644 (file)
 #include "vim.h"
 #include "version.h"
 
+#if defined(__HAIKU__)
+# include <storage/FindDirectory.h>
+#endif
+
 #if defined(MSWIN)
 # include <lm.h>
 #endif
@@ -1667,6 +1671,18 @@ vim_getenv(char_u *name, int *mustfree)
     // handling $VIMRUNTIME and $VIM is below, bail out if it's another name.
     vimruntime = (STRCMP(name, "VIMRUNTIME") == 0);
     if (!vimruntime && STRCMP(name, "VIM") != 0)
+#if defined(__HAIKU__)
+       // special handling for user settings directory...
+       if (STRCMP(name, "BE_USER_SETTINGS") == 0)
+       {
+           static char userSettingsPath[MAXPATHL] = {0};
+
+           if (B_OK == find_directory(B_USER_SETTINGS_DIRECTORY, 0,
+                                           false, userSettingsPath, MAXPATHL))
+               return userSettingsPath;
+       }
+       else
+#endif
        return NULL;
 
     /*
index 5b468d63f8f9e7005dc0bdda4d3d8460042df52e..5abb94221c7bafd820fa5700418554ebdd4594e8 100644 (file)
@@ -538,7 +538,7 @@ do_mouse(
                    // menu on the button down event.
                    return FALSE;
 #  endif
-#  if defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MSWIN)
+#  if defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_HAIKU)
                if (is_click || is_drag)
                    // Ignore right button down and drag mouse events.  Windows
                    // only shows the popup menu on the button up event.
index 8b04d18f36fcc80feac905de4f85660936fe459e..47eb151250247309e72b6a1350666bd0587e7c12 100644 (file)
@@ -10,6 +10,9 @@
  * option.h: definition of global variables for settable options
  */
 
+#ifndef _OPTION_H_
+#define _OPTION_H_
+
 //
 // Flags
 //
@@ -1290,3 +1293,5 @@ enum
 
 // Value for b_p_ul indicating the global value must be used.
 #define NO_LOCAL_UNDOLEVEL -123456
+
+#endif // _OPTION_H_
diff --git a/src/os_haiku.h b/src/os_haiku.h
new file mode 100644 (file)
index 0000000..1977cc1
--- /dev/null
@@ -0,0 +1,37 @@
+/* vi:set ts=8 sts=4 sw=4:
+ *
+ * VIM - Vi IMproved   by Bram Moolenaar
+ *       Haiku port    by Siarzhuk Zharski
+ *
+ * Do ":help uganda"  in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ */
+
+/*
+ * os_haiku.h
+ */
+
+#define USE_TERM_CONSOLE
+
+#define USR_VIM_DIR "$BE_USER_SETTINGS/vim"
+
+#define USR_EXRC_FILE  USR_VIM_DIR "/exrc"
+#define USR_EXRC_FILE2 USR_VIM_DIR "/vim/exrc"
+#define USR_VIMRC_FILE USR_VIM_DIR "/vimrc"
+#define USR_VIMRC_FILE2        USR_VIM_DIR "/vim/vimrc"
+#define USR_GVIMRC_FILE        USR_VIM_DIR "/gvimrc"
+#define USR_GVIMRC_FILE2       USR_VIM_DIR "/vim/gvimrc"
+#define VIMINFO_FILE   USR_VIM_DIR "/viminfo"
+
+#ifdef RUNTIME_GLOBAL
+# ifdef RUNTIME_GLOBAL_AFTER
+#  define DFLT_RUNTIMEPATH     USR_VIM_DIR "," RUNTIME_GLOBAL ",$VIMRUNTIME," RUNTIME_GLOBAL_AFTER "," USR_VIM_DIR "/after"
+#  define CLEAN_RUNTIMEPATH    RUNTIME_GLOBAL ",$VIMRUNTIME," RUNTIME_GLOBAL_AFTER
+# else
+#  define DFLT_RUNTIMEPATH     USR_VIM_DIR "," RUNTIME_GLOBAL ",$VIMRUNTIME," RUNTIME_GLOBAL "/after," USR_VIM_DIR "/after"
+#  define CLEAN_RUNTIMEPATH    RUNTIME_GLOBAL ",$VIMRUNTIME," RUNTIME_GLOBAL "/after"
+# endif
+#else
+# define DFLT_RUNTIMEPATH      USR_VIM_DIR ",$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after," USR_VIM_DIR "/after"
+# define CLEAN_RUNTIMEPATH     "$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after"
+#endif
diff --git a/src/os_haiku.rdef b/src/os_haiku.rdef
new file mode 100644 (file)
index 0000000..bf55aa9
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * os_haiku.rdef
+ */
+
+resource app_signature "application/x-vnd.Haiku-Vim-8";
+
+resource app_version {
+       major  = @MAJOR@,
+       middle = @MIDDLE@,
+       minor  = @MINOR@,
+
+       variety = B_APPV_FINAL,
+       internal = 0,
+
+       short_info = "VIM Editor",
+       long_info = "VI Improved Editor by Bram Moolenaar et al."
+};
+
+resource app_flags B_MULTIPLE_LAUNCH;
+
+resource file_types message {
+       "types" = "text",
+       "types" = "text/plain",
+       "types" = "text/x-source-code",
+       "types" = "text/x-patch",
+       "types" = "text/html",
+       "types" = "text/xml",
+       "types" = "text/x-makefile",
+       "types" = "text/x-jamfile"
+};
+
+resource vector_icon {
+       $"6E636966050501020006023B8CFD3CB8E4BF59B63E2F604BACDB47A13E00FFFF"
+       $"FFFF909DA702000603BAF8BA3CE3F6BF8EB9BDA8484BC75C4AEA1200C1C7CC79"
+       $"D9E0E5FFC1C7CC020006020000003DC000C000000000004C000049FFFF00B3FF"
+       $"B3FF026C52020006023BD04F3BD04FBED4133ED4134B6000462FB00053AB53FF"
+       $"007F00060618FFFCFFFF63FF282528252725262726262627262B262B262C282D"
+       $"272D282D2B2B582B582B592D5A2C5A2D5A2F5A2F5A305ABA2659315ABA26595E"
+       $"2D5E2D5F2C5F2A5F2B5F2A5F275F275F265D255E255D254A254A254925482748"
+       $"264827482B482B482C4A2D492D4A2D4C3A3F2D3C2D3C2D3D2D3E2B3E2C3E2B3E"
+       $"273E273E263C253D253C250618FFFCFFFF63FF28252825272526272626262726"
+       $"2B262B262C282D272D282D2B2B582B582B592D5A2C5A2D5A2F5A2F5A305ABA26"
+       $"59315ABA26595E2D5E2D5F2C5F2A5F2B5F2A5F275F275F265D255E255D254A25"
+       $"4A254925482748264827482B482B482C4A2D492D4A2D4C3A3F2D3C2D3C2D3D2D"
+       $"3E2B3E2C3E2B3E273E273E263C253D253C250A08BEA359BE3D593C5A415AC03B"
+       $"59BFD559434C404C06218A88888888C83E3F02484CC1D359C16D445A49C36B59"
+       $"C305C3CA50C5C8C50359C49D4C5A51C69B59C635C6FA50C8F8C83359C7CD545A"
+       $"59C9CB59C965CA6B4DCA6B4DCA804C5A4C584C584C574CC86D4DC8D34DC86D4D"
+       $"C73B524C534C524C504C504C4F4CC53D4DC5A34DC53D4DC40B4B4C0608EBECC0"
+       $"B64AC0B64AC11C4AC13349C14848C0F847C15E47C0F847C092C01648C02C47C0"
+       $"1648C00149C0504ABFEA4AC0504A0A04405E5E40402222400A0A000105180015"
+       $"01178600040A0001051815FF01178400040A030105000A0401051001157C0004"
+       $"0A000100381D1F001501178600040A000100381D1F15FF01178300040A010101"
+       $"201D1F0A020101301D1F01157E00040A0003020304381D1F15FF01178400040A"
+       $"0203020304281D1F15FF"
+};
+
+resource(1, "builtin-tools") #'PNG ' array {
+       $"89504E470D0A1A0A0000000D494844520000022E0000001208030000004BB3A5"
+       $"1200000300504C5445000000800000008000808000000080800080008080C0C0"
+       $"C0C0DCC0A6CAF0402000602000802000A02000C02000E0200000400020400040"
+       $"4000604000804000A04000C04000E04000006000206000406000606000806000"
+       $"A06000C06000E06000008000208000408000608000808000A08000C08000E080"
+       $"0000A00020A00040A00060A00080A000A0A000C0A000E0A00000C00020C00040"
+       $"C00060C00080C000A0C000C0C000E0C00000E00020E00040E00060E00080E000"
+       $"A0E000C0E000E0E000000040200040400040600040800040A00040C00040E000"
+       $"40002040202040402040602040802040A02040C02040E0204000404020404040"
+       $"4040604040804040A04040C04040E04040006040206040406040606040806040"
+       $"A06040C06040E06040008040208040408040608040808040A08040C08040E080"
+       $"4000A04020A04040A04060A04080A040A0A040C0A040E0A04000C04020C04040"
+       $"C04060C04080C040A0C040C0C040E0C04000E04020E04040E04060E04080E040"
+       $"A0E040C0E040E0E040000080200080400080600080800080A00080C00080E000"
+       $"80002080202080402080602080802080A02080C02080E0208000408020408040"
+       $"4080604080804080A04080C04080E04080006080206080406080606080806080"
+       $"A06080C06080E06080008080208080408080608080808080A08080C08080E080"
+       $"8000A08020A08040A08060A08080A080A0A080C0A080E0A08000C08020C08040"
+       $"C08060C08080C080A0C080C0C080E0C08000E08020E08040E08060E08080E080"
+       $"A0E080C0E080E0E0800000C02000C04000C06000C08000C0A000C0C000C0E000"
+       $"C00020C02020C04020C06020C08020C0A020C0C020C0E020C00040C02040C040"
+       $"40C06040C08040C0A040C0C040C0E040C00060C02060C04060C06060C08060C0"
+       $"A060C0C060C0E060C00080C02080C04080C06080C08080C0A080C0C080C0E080"
+       $"C000A0C020A0C040A0C060A0C080A0C0A0A0C0C0A0C0E0A0C000C0C020C0C040"
+       $"C0C060C0C080C0C0A0C0C0FFFBF0A0A0A4808080FF000000FF00FFFF000000FF"
+       $"FF00FF00FFFFFFFFFF58D234440000000874524E53FFFFFFFFFFFFFF00DE83BD"
+       $"59000000097048597300000B1200000B1201D2DD7EFC0000070D494441546881"
+       $"DD994B6E23390C86695880F6BDCD19BCCD3AD7CA7DB4CD197C965EE7044619D0"
+       $"F0299192AA5C9907D018762776D12A3DA8AF7E520E64B382FFB792FF004BCD4E"
+       $"DF02C1DC0717347779C3FFDB8D5F43A3705900FE8838FCDB868119C3F3E32EDA"
+       $"BB5A1897CA916A1B566CA49DED7865B2E3E930FC6397A9AAEDE232F10409EA37"
+       $"5B851A70793C020BB70C1B8CB4C436057EFFF6BCACE0BD0CAF75159D21567B6D"
+       $"B2BB9EC73AF7E89C21013E3EF03F1A4CD339BDA77E390523594BE549EA7E55DD"
+       $"E8793B68FEF332D4D3BD72BFE1B2D68D19171A87861F37ADB4163A3FEB87E6A7"
+       $"06411B06146E37D8B60D6E9E176C121A212D81976930BAE5C231A657895D5B80"
+       $"8735AE6BD5068729057FCC318FB5183DC682BB8924AC4D5AB456557F9771D647"
+       $"066E0B378A6491FD65381017DDB2793BD2674A9F64E14950CF67DFD8941D3D5D"
+       $"37DA62B1BB1B9ADFE4452BA3B3C41649D58BE6B77E58065C36B3EEC26C856D7A"
+       $"3E2A332ECFA73E3BBD53EE955F5BB8F939B3F85B749D2DDA003A0A5E546B392D"
+       $"6CE11962C1FD4412D6664C01702B990E4FA5C6591F18F4CDF1913475B1597975"
+       $"498A4BB3B632E7EA7B5F5C2E620A83C4C0ED2AFB7BBD4268157191693455129A"
+       $"BF6BD329C265918F461496EAF23219E5E7B3549977BF036FE1DFEDE9ACB2E7FB"
+       $"819736D9B76152F8C7B6B95E5AE06DA99327C682FBF9289E04B46B306D2519AB"
+       $"6480361D9A8ABDC0F291ABFE8271F916D9A849D505432FEA42D3E4965E5D1C2E"
+       $"B486CE463247C025E54159436982B898395C26759970A9BE9386CB948FC64473"
+       $"A676912AC06DFA53E5A51753C0A4D08F17730E6A734C81F7C94853BC3C8AF44B"
+       $"79A9974B5C18EE6573795C86041E49405ACAE68CC72168AEF9FAF686BF4D5DDC"
+       $"74CB98902AB8D7EA70112E0ACE076B1776DEFB7EA4BBE1B2509784893799BCA4"
+       $"76ED71416971BBCEEA623DF1B21197DB50D2840662853E2A2E19E95C2C6883BA"
+       $"A4B6DB63EDB23A19C536BCBF5E5ECAF329F2D22704C221DEE670113016C540DD"
+       $"C18576B7B0BA202CC2CB85B410F9B085F1D5E3228F00F45880CC221891A04EA1"
+       $"E55B7F181705081B15F12C71A9DC41FBC454489B414F4685D0D80A4E3F3E1789"
+       $"9FFA1D7521509ABCC89BF439E2E28B9BA82E0D97F844AD6A17E969D09F1E3448"
+       $"699EA2B0100FC9793C44E7E1B02DA50BA6A3E621655179E9B858FD32D1E11C75"
+       $"74B567B0CB0AC55B4EA37425106AFDEC1D35F2A1692DF24224E8BBB221840117"
+       $"038871F9DEC385122A83AF2E914B6B06E06B17C605E70F776760B8B45A32292E"
+       $"76D01E710907F0E1F4B4A72ECEE3594D417103762C223D688A4B5497391F9CF0"
+       $"80E1622393B290C0607CF2A1BA4CB84CAE6E8A4B257929242EF4CEE078F48599"
+       $"E712F900417117976DC3021AA9907F084703E885BA48426D5955E432F78B880B"
+       $"DD8AFEFB7BB32B182EDD64844299A74CB8D0C1903ED13594A1D47DA12E34B8B7"
+       $"D223E28F0249C5A5056DA52EAEA7AF2FEEE88C87BEA42364DCC83D40D97059D5"
+       $"2E7BC9A8F62D51EBC9A8B2C0DB01C9E8E80BEB7213F880F032E18240081C1D17"
+       $"03E8585D72FE91BA6805E6707987515D4CE9932F598637EECCC7B8F8134D5DA9"
+       $"8BC7E5F1F86A56DCF13AE022EAD282C6B844010CDC15DAFD331EE5C51FA5537D"
+       $"3C727E704A7A3ED9B53A198DA56E0FEB949F7AA92B0072F552A463CA8C7D6156"
+       $"BB0C7CF00E1EE0029BA41E4D47C8E9E6D5E5089755ED62CDD6B80CF21270F9F5"
+       $"ABE3C2E7202970F3E8695B2CEAD28AD81D7571C9E8FEF5B5C4C59BA94B0B9AE0"
+       $"1204D075F478281CAF3DB9A5A3968D522DC8CB0379C1B4C4BCACBF77C9FE201D"
+       $"4F46D666719016846C9D720CF234C8C968E443867BDBC1C578E927A306D0212E"
+       $"35984D09DCC54B5CDEF770E95FB3B883B439CCD3BE7751DD61D3A3D89EBAECE0"
+       $"32ABCB58EA46010C1D8D70EC7A7AADDB78C1D9154E095E5D2EFAAA87AAF990CC"
+       $"59B9D95E1BE0546747EA6CDFBB381AD2E4E158D02ADFDE022F0E17C9A81E5703"
+       $"E8B07681F12EF9C85D2C71C130BAEF78F670B1435083A37DABDB1D599391952F"
+       $"14BA78F0E1DD7500ADE73CE1A20F00DE2B995652909F22DC7B2784C2394FE6BF"
+       $"01683A0237985717AC5D742297A02E1185D196B8F0BBFE374DB730A561F6F458"
+       $"445E3C2E8155C65501A24612D60997D55DAE3399EF1A9769C7965B2867A0E2E2"
+       $"A31E7759F41835B4E9C7A71120F0EA02E51017BA45FF3253665C5C19AB70BCF6"
+       $"642D5B2423411F8C6B97868B8D9E5BED326AB84637E032B5E94A648AED17C634"
+       $"CC1E178B7D5C661302A891ECBE4E07E6591FD81A9781B3A5A339E749F94BFF32"
+       $"75AED701A01D71099DF832450BF94900492EBA3109273CD9FE02C03909FA6024"
+       $"912D194D339C0EC9D6CCAD7AD166F2C485312E93671150B617B88C8D86DC731A"
+       $"1767E7EEF90FEC3599BB77B416E3EAE7689CF114DBE3E262B898CB34FECE845E"
+       $"4CFAEF79764372DC201F65AC97B792C14FE6F387DBB4F83918273C6E9B866FD9"
+       $"FF17F6CF36F92F1B9E631E8B8F3FBC0000000049454E44AE426082"
+};
index 654480d9ed02d3a7ce8fec901b908fde2518ae9d..c0a4fdbe3878c82db736eee7ace884683a8671e6 100644 (file)
@@ -2151,7 +2151,8 @@ mch_settitle(char_u *title, char_u *icon)
     if (get_x11_windis() == OK)
        type = 1;
 #else
-# if defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK)
+# if defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) \
+    || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_HAIKU)
     if (gui.in_use)
        type = 1;
 # endif
@@ -2184,7 +2185,7 @@ mch_settitle(char_u *title, char_u *icon)
 # endif
            set_x11_title(title);               // x11
 #endif
-#if defined(FEAT_GUI_GTK) \
+#if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_HAIKU) \
        || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
        else
            gui_mch_settitle(title, icon);
@@ -4591,7 +4592,7 @@ mch_call_shell_fork(
     {
        SIGSET_DECL(curset)
 
-# ifdef __BEOS__
+# if defined(__BEOS__) && USE_THREAD_FOR_INPUT_WITH_TIMEOUT
        beos_cleanup_read_thread();
 # endif
 
index 53b31f813cb20372c2d470528cdc0289ae27d4b5..485e05775579419e6da0d6d27536eab1c18b5b44 100644 (file)
@@ -364,22 +364,26 @@ typedef struct dsc$descriptor   DESC;
 
 #define DFLT_ERRORFILE         "errors.err"
 
-#ifdef VMS
-# define DFLT_RUNTIMEPATH      "sys$login:vimfiles,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after,sys$login:vimfiles/after"
-# define CLEAN_RUNTIMEPATH      "$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after"
-#else
-# ifdef RUNTIME_GLOBAL
-#  ifdef RUNTIME_GLOBAL_AFTER
-#   define DFLT_RUNTIMEPATH    "~/.vim," RUNTIME_GLOBAL ",$VIMRUNTIME," RUNTIME_GLOBAL_AFTER ",~/.vim/after"
-#   define CLEAN_RUNTIMEPATH   RUNTIME_GLOBAL ",$VIMRUNTIME," RUNTIME_GLOBAL_AFTER
+#ifndef DFLT_RUNTIMEPATH
+
+# ifdef VMS
+#  define DFLT_RUNTIMEPATH      "sys$login:vimfiles,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after,sys$login:vimfiles/after"
+#  define CLEAN_RUNTIMEPATH      "$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after"
+# else
+#  ifdef RUNTIME_GLOBAL
+#   ifdef RUNTIME_GLOBAL_AFTER
+#    define DFLT_RUNTIMEPATH   "~/.vim," RUNTIME_GLOBAL ",$VIMRUNTIME," RUNTIME_GLOBAL_AFTER ",~/.vim/after"
+#    define CLEAN_RUNTIMEPATH  RUNTIME_GLOBAL ",$VIMRUNTIME," RUNTIME_GLOBAL_AFTER
+#   else
+#    define DFLT_RUNTIMEPATH   "~/.vim," RUNTIME_GLOBAL ",$VIMRUNTIME," RUNTIME_GLOBAL "/after,~/.vim/after"
+#    define CLEAN_RUNTIMEPATH  RUNTIME_GLOBAL ",$VIMRUNTIME," RUNTIME_GLOBAL "/after"
+#   endif
 #  else
-#   define DFLT_RUNTIMEPATH    "~/.vim," RUNTIME_GLOBAL ",$VIMRUNTIME," RUNTIME_GLOBAL "/after,~/.vim/after"
-#   define CLEAN_RUNTIMEPATH   RUNTIME_GLOBAL ",$VIMRUNTIME," RUNTIME_GLOBAL "/after"
+#   define DFLT_RUNTIMEPATH    "~/.vim,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after,~/.vim/after"
+#   define CLEAN_RUNTIMEPATH   "$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after"
 #  endif
-# else
-#  define DFLT_RUNTIMEPATH     "~/.vim,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after,~/.vim/after"
-#  define CLEAN_RUNTIMEPATH    "$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after"
 # endif
+
 #endif
 
 #ifdef VMS
index 825fe94d36612aa7ab5abb8adc0f157ec49a0465..4fb3409c6d91bb0c4931e3b19dbbc0c7f1b02760 100644 (file)
@@ -65,7 +65,7 @@ extern void   memmove(char *, char *, int);
 #  endif
 # endif
 #endif
-#ifndef __BIONIC__  // Android's libc #defines bzero to memset.
+#if !defined(__BIONIC__) && !defined(__HAIKU__)  // Android's libc #defines bzero to memset.
 // used inside of FD_ZERO macro
 extern void    bzero(void *, size_t);
 #endif
index 31f75cfd8304087c8b7c69e4acfe9b315baa45fd..a8faa83ca552e4450015de65117eae126445e5ab 100644 (file)
@@ -313,6 +313,9 @@ extern char_u *vimpty_getenv(const char_u *string); // in misc2.c
 extern char *vim_SelFile(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_HAIKU
+#   include "gui_haiku.pro"
+#  endif
 #  ifdef FEAT_GUI_MAC
 #   include "gui_mac.pro"
 #  endif
diff --git a/src/proto/gui_haiku.pro b/src/proto/gui_haiku.pro
new file mode 100644 (file)
index 0000000..4d4c7d3
--- /dev/null
@@ -0,0 +1,95 @@
+/* gui_haiku.cc - hand crafted */
+
+void gui_mch_prepare(int *argc, char **argv);
+int gui_mch_init(void);
+int gui_mch_open(void);
+void gui_mch_exit(int vim_exitcode);
+int gui_mch_init_check(void);
+void gui_mch_flush(void);
+
+void gui_mch_new_colors(void);
+void gui_mch_set_bg_color(guicolor_T color);
+void gui_mch_set_fg_color(guicolor_T color);
+void gui_mch_set_sp_color(guicolor_T color);
+guicolor_T gui_mch_get_rgb(guicolor_T pixel);
+guicolor_T gui_mch_get_rgb_color(int r, int g, int b);
+guicolor_T gui_mch_get_color(char_u *name);
+
+GuiFont gui_mch_get_font(char_u *name, int giveErrorIfMissing);
+void gui_mch_set_font(GuiFont font);
+int gui_mch_init_font(char_u *font_name, int fontset);
+void gui_mch_free_font(GuiFont font);
+char_u *gui_mch_get_fontname(GuiFont font, char_u *name);
+
+void gui_mch_set_winpos(int x, int y);
+int gui_mch_get_winpos(int *x, int *y);
+void gui_mch_set_shellsize(int w, int h, int m_w, int m_h, int b_w, int b_h, int d);
+void gui_mch_get_screen_dimensions(int* screen_w, int* screen_h);
+void gui_mch_set_text_area_pos(int x, int y, int w, int h);
+
+void gui_mch_enable_scrollbar(scrollbar_T *sb, int flag);
+
+//void gui_mch_set_scrollbar_thumb __ARGS((scrollbar_T *sb,int val, int size, int max));
+void gui_mch_set_scrollbar_thumb(scrollbar_T *sb, int val, int size, int max);
+
+void gui_mch_set_scrollbar_pos(scrollbar_T *sb, int x, int y, int w, int h);
+void gui_mch_create_scrollbar(scrollbar_T *sb, int orient);
+void gui_mch_destroy_scrollbar(scrollbar_T *sb);
+
+void gui_mch_set_blinking(long waittime, long on, long off);
+void gui_mch_stop_blink(int may_call_gui_update_cursor);
+void gui_mch_start_blink(void);
+
+int gui_mch_adjust_charheight(void);
+void gui_mch_draw_string(int row, int col, char_u *s, int len, int flags);
+int gui_mch_haskey(char_u *name);
+void gui_mch_beep(void);
+void gui_mch_flash(int msec);
+void gui_mch_invert_rectangle(int r, int c, int nr, int nc);
+void gui_mch_iconify(void);
+void gui_mch_set_foreground(void);
+void gui_mch_settitle(char_u *title, char_u *icon);
+void gui_mch_draw_hollow_cursor(guicolor_T color);
+void gui_mch_draw_part_cursor(int w, int h, guicolor_T color);
+void gui_mch_update(void);
+int gui_mch_wait_for_chars(int wtime);
+void gui_mch_clear_block(int row1, int col1, int row2, int col2);
+void gui_mch_clear_all(void);
+void gui_mch_delete_lines(int row, int num_lines);
+void gui_mch_insert_lines(int row, int num_lines);
+
+void gui_mch_getmouse(int *x, int *y);
+void gui_mch_setmouse(int x, int y);
+void gui_mch_mousehide(int hide);
+
+void gui_mch_enable_menu(int flag);
+void gui_mch_set_menu_pos(int x, int y, int w, int h);
+void gui_mch_add_menu(vimmenu_T *menu, int idx);
+void gui_mch_add_menu_item(vimmenu_T *menu, int idx);
+void gui_mch_destroy_menu(vimmenu_T *menu);
+void gui_mch_menu_grey(vimmenu_T *menu, int grey);
+void gui_mch_menu_hidden(vimmenu_T *menu, int hidden);
+void gui_mch_draw_menubar(void);
+void gui_mch_show_popupmenu(vimmenu_T *menu);
+void gui_mch_toggle_tearoffs(int enable);
+
+void clip_mch_request_selection(Clipboard_T *cbd);
+void clip_mch_set_selection(Clipboard_T *cbd);
+void clip_mch_lose_selection(Clipboard_T *cbd);
+int clip_mch_own_selection(Clipboard_T *cbd);
+
+char_u *gui_mch_browse(int saving, char_u *title, char_u *dflt, char_u *ext, char_u *initdir, char_u *filter);
+int gui_mch_dialog(int type, char_u *title, char_u *message, char_u *buttons, int dfltbutton, char_u *textfield, int ex_cmd);
+
+void im_set_position(int row, int col);
+void im_set_active(int activate);
+int im_get_status(void);
+
+void gui_mch_show_toolbar(int showit);
+void gui_mch_set_toolbar_pos(int x, int y, int w, int h);
+
+void gui_mch_show_tabline(int showit);
+void gui_mch_set_tabline_pos(int x, int y, int w, int h);
+int gui_mch_showing_tabline(void);
+void gui_mch_update_tabline(void);
+void gui_mch_set_curtab(int nr);
index a44d0a08889a1e0991128ffe309b8a677f107c40..03c02af104f25900626991047005169ab0b30283 100644 (file)
--- a/src/pty.c
+++ b/src/pty.c
@@ -386,7 +386,7 @@ mch_openpty(char **ttyn)
 static char PtyProto[] = "/dev/ptym/ptyXY";
 static char TtyProto[] = "/dev/pty/ttyXY";
 # else
-#  ifdef __BEOS__
+#  if defined (__BEOS__) || defined(__HAIKU__)
 static char PtyProto[] = "/dev/pt/XY";
 static char TtyProto[] = "/dev/tt/XY";
 #  else
index 795e749ff6438df432f4866141e7edc5f8ae0cb5..713360039743cd209faa82eb3111d412866c89b4 100644 (file)
@@ -2549,6 +2549,10 @@ retry:
 
     win_new_shellsize();    // fit the windows in the new sized shell
 
+#ifdef FEAT_GUI_HAIKU
+    vim_lock_screen();  // be safe, put it here
+#endif
+
     comp_col();                // recompute columns for shown command and ruler
 
     /*
@@ -2799,6 +2803,10 @@ give_up:
 #endif
     clear_TabPageIdxs();
 
+#ifdef FEAT_GUI_HAIKU
+    vim_unlock_screen();
+#endif
+
     entered = FALSE;
     --RedrawingDisabled;
 
@@ -3646,6 +3654,10 @@ screen_ins_lines(
        clip_scroll_selection(-line_count);
 #endif
 
+#ifdef FEAT_GUI_HAIKU
+    vim_lock_screen();
+#endif
+
 #ifdef FEAT_GUI
     // Don't update the GUI cursor here, ScreenLines[] is invalid until the
     // scrolling is actually carried out.
@@ -3700,6 +3712,10 @@ screen_ins_lines(
        }
     }
 
+#ifdef FEAT_GUI_HAIKU
+    vim_unlock_screen();
+#endif
+
     screen_stop_highlight();
     windgoto(cursor_row, cursor_col);
     if (clear_attr != 0)
@@ -3928,6 +3944,10 @@ screen_del_lines(
        }
     }
 
+#ifdef FEAT_GUI_HAIKU
+    vim_unlock_screen();
+#endif
+
     if (screen_attr != clear_attr)
        screen_stop_highlight();
     if (clear_attr != 0)
index e68c1f906d6cdf4fd2d23740a90a6e71bc35d56e..76d45ea8f2980a8eba6945512708e71833378bae 100644 (file)
@@ -3643,6 +3643,13 @@ struct VimMenu
     HMENU      submenu_id;         // If this is submenu, add children here
     HWND       tearoff_handle;     // hWnd of tearoff if created
 #endif
+#if FEAT_GUI_HAIKU
+    BMenuItem  *id;                // Id of menu item
+    BMenu  *submenu_id;                    // If this is submenu, add children here
+# ifdef FEAT_TOOLBAR
+    BPictureButton *button;
+# endif
+#endif
 #ifdef FEAT_GUI_MAC
 //  MenuHandle id;
 //  short      index;              // the item index within the father menu
index e9a9004a2dcb657334f439ba9b00ba9bdb714fe7..6afecbae8802825acb3ecb09c6012516d57a952f 100644 (file)
@@ -1420,6 +1420,11 @@ termgui_mch_get_rgb(guicolor_T color)
 # define DEFAULT_TERM  (char_u *)"beos-ansi"
 #endif
 
+#ifdef __HAIKU__
+# undef DEFAULT_TERM
+# define DEFAULT_TERM  (char_u *)"xterm"
+#endif
+
 #ifndef DEFAULT_TERM
 # define DEFAULT_TERM  (char_u *)"dumb"
 #endif
index e3ff8e15c26359d7dee3aeb39a2c295a3dbacb3b..46540e9eb943cc7674c755c37ea0a53b69bd20c9 100644 (file)
@@ -738,6 +738,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    320,
 /**/
     319,
 /**/
@@ -1722,6 +1724,9 @@ list_version(void)
     msg_puts(_("with X11-Athena GUI."));
 #    endif
 #   else
+#    ifdef FEAT_GUI_HAIKU
+    msg_puts(_("with Haiku GUI."));
+#    else
 #     ifdef FEAT_GUI_PHOTON
     msg_puts(_("with Photon GUI."));
 #     else
@@ -1736,6 +1741,7 @@ list_version(void)
 #       else
 #       endif
 #      endif
+#       endif
 #      endif
 #    endif
 #   endif
index 4d3ac36633eacb512e929858eaab318f9aced5cc..658a2f129c96a9bc9a4c77aafdeccdbb72b97822 100644 (file)
--- a/src/vim.h
+++ b/src/vim.h
 #if defined(FEAT_GUI_MOTIF) \
     || defined(FEAT_GUI_GTK) \
     || defined(FEAT_GUI_ATHENA) \
+    || defined(FEAT_GUI_HAIKU) \
     || defined(FEAT_GUI_MAC) \
     || defined(FEAT_GUI_MSWIN) \
     || defined(FEAT_GUI_PHOTON)
 # include "os_beos.h"
 #endif
 
+#ifdef __HAIKU__
+# include "os_haiku.h"
+# define __ARGS(x)  x
+#endif
+
 #if (defined(UNIX) || defined(VMS)) \
        && (!defined(MACOS_X) || defined(HAVE_CONFIG_H))
 # include "os_unix.h"      // bring lots of system header files
@@ -2075,6 +2081,9 @@ typedef struct
     int_u      format;         // Vim's own special clipboard format
     int_u      format_raw;     // Vim's raw text clipboard format
 # endif
+# ifdef FEAT_GUI_HAIKU
+    // No clipboard at the moment. TODO?
+# endif
 } Clipboard_T;
 #else
 typedef int Clipboard_T;       // This is required for the prototypes.
@@ -2136,7 +2145,7 @@ typedef enum {
 // functions of these names. The declarations would break if the defines had
 // been seen at that stage.  But it must be before globals.h, where error_ga
 // is declared.
-#if !defined(MSWIN) && !defined(FEAT_GUI_X11) \
+#if !defined(MSWIN) && !defined(FEAT_GUI_X11) && !defined(FEAT_GUI_HAIKU) \
        && !defined(FEAT_GUI_GTK) && !defined(FEAT_GUI_MAC) && !defined(PROTO)
 # define mch_errmsg(str)       fprintf(stderr, "%s", (str))
 # define display_errors()      fflush(stderr)