mirror of
				https://github.com/vim/vim.git
				synced 2025-10-30 09:47:20 -04:00 
			
		
		
		
	Problem:    Recent glibc marks sigset() as a deprecated.
Solution:   Use sigaction() in mch_signal() if possible. (Ozaki Kiichi,
            closes #12373)
		
	
		
			
				
	
	
		
			5093 lines
		
	
	
		
			120 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			5093 lines
		
	
	
		
			120 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* 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 "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)	{ (char_u)((g) >> 16), (char_u)((g) >> 8), (char_u)((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    ARRAY_LENGTH(special_keys)
 | |
| 
 | |
| // ---------------- 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, deleted in 8.2.1422)
 | |
|     // Update the screen display
 | |
|     update_screen(UPD_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.
 | |
|      */
 | |
|     mch_signal(SIGINT, SIG_IGN);
 | |
|     mch_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.
 | |
|      */
 | |
|     mch_signal(SIGINT, SIG_IGN);
 | |
|     mch_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;
 | |
| 	}
 | |
|     }
 | |
|     return true;
 | |
| }
 | |
| 
 | |
|     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);
 | |
|     }
 | |
|     return 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 truly 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();
 | |
|     }
 | |
| }
 | |
| 
 | |
|     int
 | |
| gui_mch_get_scrollbar_xpadding(void)
 | |
| {
 | |
|     // TODO: Calculate the padding for adjust scrollbar position when the
 | |
|     // Window is maximized.
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
|     int
 | |
| gui_mch_get_scrollbar_ypadding(void)
 | |
| {
 | |
|     // TODO: Calculate the padding for adjust scrollbar position when the
 | |
|     // Window is maximized.
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| 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(FEAT_GUI_HAIKU) || 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(int may_call_gui_update_cursor)
 | |
| {
 | |
|     // 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_unknown_font_str), 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 = (char_u*)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_unknown_font_str), 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;
 | |
| }
 | |
| 
 | |
|     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)
 | |
| {
 | |
|     return gui_get_color_cmn(name);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * 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(TRUE);
 | |
| 	    focus = gui.in_focus;
 | |
| 	}
 | |
| 
 | |
| 	gui_mch_flush();
 | |
| 
 | |
| #ifdef MESSAGE_QUEUE
 | |
| # ifdef FEAT_TIMERS
 | |
| 	did_add_timer = FALSE;
 | |
| # endif
 | |
| 	parse_queued_messages();
 | |
| # ifdef FEAT_TIMERS
 | |
| 	if (did_add_timer)
 | |
| 	    // Need to recompute the waiting time.
 | |
| 	    break;
 | |
| # endif
 | |
| # ifdef FEAT_JOB_CHANNEL
 | |
| 	if (has_any_channel())
 | |
| 	{
 | |
| 	    if (wtime < 0 || timeout > 20000)
 | |
| 		timeout = 20000;
 | |
| 	}
 | |
| 	else if (wtime < 0)
 | |
| 	    timeout = B_INFINITE_TIMEOUT;
 | |
| # endif
 | |
| #endif
 | |
| 
 | |
| 	/*
 | |
| 	 * 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 it's 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
 |