blob: 15c4389f860bfb562514364839c040388abb1c56 [file] [log] [blame]
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 * BeBox GUI support Copyright 1998 by Olaf Seibert.
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005 * All Rights Reserved.
Bram Moolenaarb3f74062020-02-26 16:16:53 +01006 *
7 * Do ":help uganda" in Vim to read copying and usage conditions.
8 * Do ":help credits" in Vim to see a list of people who contributed.
9 *
10 * Based on "GUI support for the Buzzword Enhanced Operating System."
11 *
12 * Ported to R4 by Richard Offer <richard@whitequeen.com> Jul 99
13 *
14 * Haiku support by Siarzhuk Zharski <imker@gmx.li> Apr-Mai 2009
15 *
16 */
17
18/*
19 * Structure of the Haiku GUI code:
20 *
21 * There are 3 threads.
22 * 1. The initial thread. In gui_mch_prepare() this gets to run the
23 * BApplication message loop. But before it starts doing that,
24 * it creates thread 2
25 * 2. The main() thread. This thread is created in gui_mch_prepare()
26 * and its purpose in life is to call main(argc, argv) again.
27 * This thread is doing the bulk of the work.
28 * 3. Sooner or later, a window is opened by the main() thread. This
29 * causes a second message loop to be created: the window thread.
30 *
31 * == alternatively ===
32 *
33 * #if RUN_BAPPLICATION_IN_NEW_THREAD...
34 *
35 * 1. The initial thread. In gui_mch_prepare() this gets to spawn
36 * thread 2. After doing that, it returns to main() to do the
37 * bulk of the work, being the main() thread.
38 * 2. Runs the BApplication.
39 * 3. The window thread, just like in the first case.
40 *
41 * This second alternative is cleaner from Vim's viewpoint. However,
42 * the BeBook seems to assume everywhere that the BApplication *must*
43 * run in the initial thread. So perhaps doing otherwise is very wrong.
44 *
45 * However, from a B_SINGLE_LAUNCH viewpoint, the first is better.
46 * If Vim is marked "Single Launch" in its application resources,
47 * and a file is dropped on the Vim icon, and another Vim is already
48 * running, the file is passed on to the earlier Vim. This happens
49 * in BApplication::Run(). So we want Vim to terminate if
50 * BApplication::Run() terminates. (See the BeBook, on BApplication.
51 * However, it seems that the second copy of Vim isn't even started
52 * in this case... which is for the better since I wouldn't know how
53 * to detect this case.)
54 *
55 * Communication between these threads occurs mostly by translating
56 * BMessages that come in and posting an appropriate translation on
57 * the VDCMP (Vim Direct Communication Message Port). Therefore the
58 * actions required for keypresses and window resizes, etc, are mostly
59 * performed in the main() thread.
60 *
61 * A notable exception to this is the Draw() event. The redrawing of
62 * the window contents is performed asynchronously from the window
63 * thread. To make this work correctly, a locking protocol is used when
64 * any thread is accessing the essential variables that are used by
65 * the window thread.
66 *
67 * This locking protocol consists of locking Vim's window. This is both
68 * convenient and necessary.
69 */
70
71extern "C" {
72
73#include <assert.h>
74#include <float.h>
75#include <syslog.h>
76
77#include "vim.h"
Bram Moolenaarb3f74062020-02-26 16:16:53 +010078#include "version.h"
79
Bram Moolenaarb52575f2020-04-24 22:16:13 +020080} // extern "C"
Bram Moolenaarb3f74062020-02-26 16:16:53 +010081
82// ---------------- start of header part ----------------
83
84//#include <Alert.h>
85#include <Application.h>
86#include <Beep.h>
87#include <Bitmap.h>
88#include <Box.h>
89#include <Button.h>
90#include <Clipboard.h>
91#include <Debug.h>
92//#include <Directory.h>
93//#include <Entry.h>
94#include <File.h>
95#include <FilePanel.h>
96#include <FindDirectory.h>
97//#include <Font.h>
98#include <IconUtils.h>
99#include <Input.h>
100#include <ListView.h>
101#include <MenuBar.h>
102#include <MenuItem.h>
103//#include <MessageQueue.h>
104//#include <OS.h>
105#include <Path.h>
106#include <PictureButton.h>
107#include <PopUpMenu.h>
108//#include <Region.h>
109#include <Resources.h>
110//#include <Roster.h>
111#include <Screen.h>
112#include <ScrollBar.h>
113#include <ScrollView.h>
114#include <String.h>
115#include <StringView.h>
116//#include <SupportDefs.h>
117#include <TabView.h>
118#include <TextControl.h>
119#include <TextView.h>
120#include <TranslationUtils.h>
121#include <TranslatorFormats.h>
122#include <View.h>
123#include <Window.h>
124
125class VimApp;
126class VimFormView;
127class VimTextAreaView;
128class VimWindow;
129class VimToolbar;
130class VimTabLine;
131
132extern key_map *keyMap;
133extern char *keyMapChars;
134
135extern int main(int argc, char **argv);
136
137#ifndef B_MAX_PORT_COUNT
138#define B_MAX_PORT_COUNT 255
139#endif
140
141// VimApp seems comparable to the X "vimShell"
142class VimApp: public BApplication
143{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200144 typedef BApplication Inherited;
145 public:
146 VimApp(const char *appsig);
147 ~VimApp();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100148
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200149 // callbacks:
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100150#if 0
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200151 virtual void DispatchMessage(BMessage *m, BHandler *h)
152 {
153 m->PrintToStream();
154 Inherited::DispatchMessage(m, h);
155 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100156#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200157 virtual void ReadyToRun();
158 virtual void ArgvReceived(int32 argc, char **argv);
159 virtual void RefsReceived(BMessage *m);
160 virtual bool QuitRequested();
161 virtual void MessageReceived(BMessage *m);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100162
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200163 static void SendRefs(BMessage *m, bool changedir);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100164
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200165 sem_id fFilePanelSem;
166 BFilePanel* fFilePanel;
167 BPath fBrowsedPath;
168 private:
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100169};
170
171class VimWindow: public BWindow
172{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200173 typedef BWindow Inherited;
174 public:
175 VimWindow();
176 ~VimWindow();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100177
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200178 // virtual void DispatchMessage(BMessage *m, BHandler *h);
179 virtual void WindowActivated(bool active);
180 virtual bool QuitRequested();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100181
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200182 VimFormView *formView;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100183
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200184 private:
185 void init();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100186
187};
188
189class VimFormView: public BView
190{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200191 typedef BView Inherited;
192 public:
193 VimFormView(BRect frame);
194 ~VimFormView();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100195
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200196 // callbacks:
197 virtual void AllAttached();
198 virtual void FrameResized(float new_width, float new_height);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100199
200#define MENUBAR_MARGIN 1
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200201 float MenuHeight() const
202 { return menuBar ? menuBar->Frame().Height() + MENUBAR_MARGIN: 0; }
203 BMenuBar *MenuBar() const
204 { return menuBar; }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100205
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200206 private:
207 void init(BRect);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100208
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200209 BMenuBar *menuBar;
210 VimTextAreaView *textArea;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100211
212#ifdef FEAT_TOOLBAR
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200213 public:
214 float ToolbarHeight() const;
215 VimToolbar *ToolBar() const
216 { return toolBar; }
217 private:
218 VimToolbar *toolBar;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100219#endif
220
221#ifdef FEAT_GUI_TABLINE
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200222 public:
223 VimTabLine *TabLine() const { return tabLine; }
224 bool IsShowingTabLine() const { return showingTabLine; }
225 void SetShowingTabLine(bool showing) { showingTabLine = showing; }
226 float TablineHeight() const;
227 private:
228 VimTabLine *tabLine;
229 int showingTabLine;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100230#endif
231};
232
233class VimTextAreaView: public BView
234{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200235 typedef BView Inherited;
236 public:
237 VimTextAreaView(BRect frame);
238 ~VimTextAreaView();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100239
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200240 // callbacks:
241 virtual void Draw(BRect updateRect);
242 virtual void KeyDown(const char *bytes, int32 numBytes);
243 virtual void MouseDown(BPoint point);
244 virtual void MouseUp(BPoint point);
245 virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *message);
246 virtual void MessageReceived(BMessage *m);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100247
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200248 // own functions:
249 int mchInitFont(char_u *name);
250 void mchDrawString(int row, int col, char_u *s, int len, int flags);
251 void mchClearBlock(int row1, int col1, int row2, int col2);
252 void mchClearAll();
253 void mchDeleteLines(int row, int num_lines);
254 void mchInsertLines(int row, int num_lines);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100255
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200256 static void guiSendMouseEvent(int button, int x, int y, int repeated_click, int_u modifiers);
257 static void guiMouseMoved(int x, int y);
258 static void guiBlankMouse(bool should_hide);
259 static int_u mouseModifiersToVim(int32 beModifiers);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100260
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200261 int32 mouseDragEventCount;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100262
263#ifdef FEAT_MBYTE_IME
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200264 void DrawIMString(void);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100265#endif
266
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200267 private:
268 void init(BRect);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100269
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200270 int_u vimMouseButton;
271 int_u vimMouseModifiers;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100272
273#ifdef FEAT_MBYTE_IME
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200274 struct {
275 BMessenger* messenger;
276 BMessage* message;
277 BPoint location;
278 int row;
279 int col;
280 int count;
281 } IMData;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100282#endif
283};
284
285class VimScrollBar: public BScrollBar
286{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200287 typedef BScrollBar Inherited;
288 public:
289 VimScrollBar(scrollbar_T *gsb, orientation posture);
290 ~VimScrollBar();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100291
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200292 virtual void ValueChanged(float newValue);
293 virtual void MouseUp(BPoint where);
294 void SetValue(float newval);
295 scrollbar_T *getGsb()
296 { return gsb; }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100297
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200298 int32 scrollEventCount;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100299
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200300 private:
301 scrollbar_T *gsb;
302 float ignoreValue;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100303};
304
305
306#ifdef FEAT_TOOLBAR
307
308class VimToolbar : public BBox
309{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200310 static BBitmap *normalButtonsBitmap;
311 static BBitmap *grayedButtonsBitmap;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100312
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200313 BBitmap *LoadVimBitmap(const char* fileName);
314 bool GetPictureFromBitmap(BPicture *pictureTo, int32 index, BBitmap *bitmapFrom, bool pressed);
315 bool ModifyBitmapToGrayed(BBitmap *bitmap);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100316
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200317 BList fButtonsList;
318 void InvalidateLayout();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100319
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200320 public:
321 VimToolbar(BRect frame, const char * name);
322 ~VimToolbar();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100323
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200324 bool PrepareButtonBitmaps();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100325
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200326 bool AddButton(int32 index, vimmenu_T *menu);
327 bool RemoveButton(vimmenu_T *menu);
328 bool GrayButton(vimmenu_T *menu, int grey);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100329
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200330 float ToolbarHeight() const;
331 virtual void AttachedToWindow();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100332};
333
334BBitmap *VimToolbar::normalButtonsBitmap = NULL;
335BBitmap *VimToolbar::grayedButtonsBitmap = NULL;
336
337const float ToolbarMargin = 3.;
338const float ButtonMargin = 3.;
339
340#endif //FEAT_TOOLBAR
341
342#ifdef FEAT_GUI_TABLINE
343
344class VimTabLine : public BTabView
345{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200346 public:
347 class VimTab : public BTab {
348 public:
349 VimTab() : BTab(new BView(BRect(), "-Empty-", 0, 0)) {}
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100350
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200351 virtual void Select(BView* owner);
352 };
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100353
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200354 VimTabLine(BRect r) : BTabView(r, "vimTabLine", B_WIDTH_FROM_LABEL,
355 B_FOLLOW_LEFT | B_FOLLOW_TOP | B_FOLLOW_RIGHT, B_WILL_DRAW | B_FRAME_EVENTS) {}
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100356
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200357 float TablineHeight() const;
358 virtual void MouseDown(BPoint point);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100359};
360
361#endif //FEAT_GUI_TABLINE
362
363
364// For caching the fonts that are used;
365// Vim seems rather sloppy in this regard.
366class VimFont: public BFont
367{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200368 typedef BFont Inherited;
369 public:
370 VimFont();
371 VimFont(const VimFont *rhs);
372 VimFont(const BFont *rhs);
373 VimFont(const VimFont &rhs);
374 ~VimFont();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100375
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200376 VimFont *next;
377 int refcount;
378 char_u *name;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100379
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200380 private:
381 void init();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100382};
383
384#if defined(FEAT_GUI_DIALOG)
385
386class VimDialog : public BWindow
387{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200388 typedef BWindow Inherited;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100389
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200390 BButton* _CreateButton(int32 which, const char* label);
391
392 public:
393
394 class View : public BView {
395 typedef BView Inherited;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100396
397 public:
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200398 View(BRect frame);
399 ~View();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100400
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200401 virtual void Draw(BRect updateRect);
402 void InitIcon(int32 type);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100403
404 private:
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200405 BBitmap* fIconBitmap;
406 };
407
408 VimDialog(int type, const char *title, const char *message,
409 const char *buttons, int dfltbutton, const char *textfield,
410 int ex_cmd);
411 ~VimDialog();
412
413 int Go();
414
415 virtual void MessageReceived(BMessage *msg);
416
417 private:
418 sem_id fDialogSem;
419 int fDialogValue;
420 BList fButtonsList;
421 BTextView* fMessageView;
422 BTextControl* fInputControl;
423 const char* fInputValue;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100424};
425
426class VimSelectFontDialog : public BWindow
427{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200428 typedef BWindow Inherited;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100429
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200430 void _CleanList(BListView* list);
431 void _UpdateFontStyles();
432 void _UpdateSizeInputPreview();
433 void _UpdateFontPreview();
434 bool _UpdateFromListItem(BListView* list, char* text, int textSize);
435 public:
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100436
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200437 VimSelectFontDialog(font_family* family, font_style* style, float* size);
438 ~VimSelectFontDialog();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100439
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200440 bool Go();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100441
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200442 virtual void MessageReceived(BMessage *msg);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100443
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200444 private:
445 status_t fStatus;
446 sem_id fDialogSem;
447 bool fDialogValue;
448 font_family* fFamily;
449 font_style* fStyle;
450 float* fSize;
451 font_family fFontFamily;
452 font_style fFontStyle;
453 float fFontSize;
454 BStringView* fPreview;
455 BListView* fFamiliesList;
456 BListView* fStylesList;
457 BListView* fSizesList;
458 BTextControl* fSizesInput;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100459};
460
461#endif // FEAT_GUI_DIALOG
462
463// ---------------- end of GUI classes ----------------
464
465struct MainArgs {
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200466 int argc;
467 char **argv;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100468};
469
470// These messages are copied through the VDCMP.
471// Therefore they ought not to have anything fancy.
472// They must be of POD type (Plain Old Data)
473// as the C++ standard calls them.
474
475#define KEY_MSG_BUFSIZ 7
476#if KEY_MSG_BUFSIZ < MAX_KEY_CODE_LEN
477#error Increase KEY_MSG_BUFSIZ!
478#endif
479
480struct VimKeyMsg {
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200481 char_u length;
482 char_u chars[KEY_MSG_BUFSIZ]; // contains Vim encoding
483 bool csi_escape;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100484};
485
486struct VimResizeMsg {
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200487 int width;
488 int height;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100489};
490
491struct VimScrollBarMsg {
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200492 VimScrollBar *sb;
493 long value;
494 int stillDragging;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100495};
496
497struct VimMenuMsg {
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200498 vimmenu_T *guiMenu;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100499};
500
501struct VimMouseMsg {
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200502 int button;
503 int x;
504 int y;
505 int repeated_click;
506 int_u modifiers;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100507};
508
509struct VimMouseMovedMsg {
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200510 int x;
511 int y;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100512};
513
514struct VimFocusMsg {
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200515 bool active;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100516};
517
518struct VimRefsMsg {
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200519 BMessage *message;
520 bool changedir;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100521};
522
523struct VimTablineMsg {
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200524 int index;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100525};
526
527struct VimTablineMenuMsg {
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200528 int index;
529 int event;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100530};
531
532struct VimMsg {
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200533 enum VimMsgType {
534 Key, Resize, ScrollBar, Menu, Mouse, MouseMoved, Focus, Refs, Tabline, TablineMenu
535 };
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100536
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200537 union {
538 struct VimKeyMsg Key;
539 struct VimResizeMsg NewSize;
540 struct VimScrollBarMsg Scroll;
541 struct VimMenuMsg Menu;
542 struct VimMouseMsg Mouse;
543 struct VimMouseMovedMsg MouseMoved;
544 struct VimFocusMsg Focus;
545 struct VimRefsMsg Refs;
546 struct VimTablineMsg Tabline;
547 struct VimTablineMenuMsg TablineMenu;
548 } u;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100549};
550
551#define RGB(r, g, b) ((char_u)(r) << 16 | (char_u)(g) << 8 | (char_u)(b) << 0)
Bram Moolenaar9e175142020-04-30 22:51:01 +0200552#define GUI_TO_RGB(g) { (char_u)((g) >> 16), (char_u)((g) >> 8), (char_u)((g) >> 0), 255 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100553
554// ---------------- end of header part ----------------
555
556static struct specialkey
557{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200558 uint16 BeKeys;
559#define KEY(a,b) ((a)<<8|(b))
560#define K(a) KEY(0,a) // for ASCII codes
561#define F(b) KEY(1,b) // for scancodes
562 char_u vim_code0;
563 char_u vim_code1;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100564} special_keys[] =
565{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200566 {K(B_UP_ARROW), 'k', 'u'},
567 {K(B_DOWN_ARROW), 'k', 'd'},
568 {K(B_LEFT_ARROW), 'k', 'l'},
569 {K(B_RIGHT_ARROW), 'k', 'r'},
570 {K(B_BACKSPACE), 'k', 'b'},
571 {K(B_INSERT), 'k', 'I'},
572 {K(B_DELETE), 'k', 'D'},
573 {K(B_HOME), 'k', 'h'},
574 {K(B_END), '@', '7'},
575 {K(B_PAGE_UP), 'k', 'P'}, // XK_Prior
576 {K(B_PAGE_DOWN), 'k', 'N'}, // XK_Next,
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100577
578#define FIRST_FUNCTION_KEY 11
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200579 {F(B_F1_KEY), 'k', '1'},
580 {F(B_F2_KEY), 'k', '2'},
581 {F(B_F3_KEY), 'k', '3'},
582 {F(B_F4_KEY), 'k', '4'},
583 {F(B_F5_KEY), 'k', '5'},
584 {F(B_F6_KEY), 'k', '6'},
585 {F(B_F7_KEY), 'k', '7'},
586 {F(B_F8_KEY), 'k', '8'},
587 {F(B_F9_KEY), 'k', '9'},
588 {F(B_F10_KEY), 'k', ';'},
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100589
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200590 {F(B_F11_KEY), 'F', '1'},
591 {F(B_F12_KEY), 'F', '2'},
592 // {XK_F13, 'F', '3'}, // would be print screen
593 // sysreq
594 {F(0x0F), 'F', '4'}, // scroll lock
595 {F(0x10), 'F', '5'}, // pause/break
596 // {XK_F16, 'F', '6'},
597 // {XK_F17, 'F', '7'},
598 // {XK_F18, 'F', '8'},
599 // {XK_F19, 'F', '9'},
600 // {XK_F20, 'F', 'A'},
601 // {XK_F21, 'F', 'B'},
602 // {XK_F22, 'F', 'C'},
603 // {XK_F23, 'F', 'D'},
604 // {XK_F24, 'F', 'E'},
605 // {XK_F25, 'F', 'F'},
606 // {XK_F26, 'F', 'G'},
607 // {XK_F27, 'F', 'H'},
608 // {XK_F28, 'F', 'I'},
609 // {XK_F29, 'F', 'J'},
610 // {XK_F30, 'F', 'K'},
611 // {XK_F31, 'F', 'L'},
612 // {XK_F32, 'F', 'M'},
613 // {XK_F33, 'F', 'N'},
614 // {XK_F34, 'F', 'O'},
615 // {XK_F35, 'F', 'P'}, // keysymdef.h defines up to F35
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100616
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200617 // {XK_Help, '%', '1'}, // XK_Help
618 {F(B_PRINT_KEY), '%', '9'},
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100619
620#if 0
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200621 // Keypad keys:
622 {F(0x48), 'k', 'l'}, // XK_KP_Left
623 {F(0x4A), 'k', 'r'}, // XK_KP_Right
624 {F(0x38), 'k', 'u'}, // XK_KP_Up
625 {F(0x59), 'k', 'd'}, // XK_KP_Down
626 {F(0x64), 'k', 'I'}, // XK_KP_Insert
627 {F(0x65), 'k', 'D'}, // XK_KP_Delete
628 {F(0x37), 'k', 'h'}, // XK_KP_Home
629 {F(0x58), '@', '7'}, // XK_KP_End
630 {F(0x39), 'k', 'P'}, // XK_KP_Prior
631 {F(0x60), 'k', 'N'}, // XK_KP_Next
632 {F(0x49), '&', '8'}, // XK_Undo, keypad 5
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100633#endif
634
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200635 // End of list marker:
636 {0, 0, 0}
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100637};
638
K.Takataeeec2542021-06-02 13:28:16 +0200639#define NUM_SPECIAL_KEYS ARRAY_LENGTH(special_keys)
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100640
641// ---------------- VimApp ----------------
642
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200643 static void
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100644docd(BPath &path)
645{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200646 mch_chdir((char *)path.Path());
647 // Do this to get the side effects of a :cd command
648 do_cmdline_cmd((char_u *)"cd .");
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100649}
650
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200651 static void
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100652drop_callback(void *cookie)
653{
654 // TODO here we could handle going to a specific position in the dropped
Bram Moolenaarbe7529e2020-08-13 21:05:39 +0200655 // file (see src/gui_mac.c, deleted in 8.2.1422)
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100656 // Update the screen display
Bram Moolenaara4d158b2022-08-14 14:17:45 +0100657 update_screen(UPD_NOT_VALID);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100658}
659
660 // Really handle dropped files and folders.
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200661 static void
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100662RefsReceived(BMessage *m, bool changedir)
663{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200664 uint32 type;
665 int32 count;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100666
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200667 m->PrintToStream();
668 switch (m->what) {
669 case B_REFS_RECEIVED:
670 case B_SIMPLE_DATA:
671 m->GetInfo("refs", &type, &count);
672 if (type != B_REF_TYPE)
673 goto bad;
674 break;
675 case B_ARGV_RECEIVED:
676 m->GetInfo("argv", &type, &count);
677 if (type != B_STRING_TYPE)
678 goto bad;
679 if (changedir) {
680 char *dirname;
681 if (m->FindString("cwd", (const char **) &dirname) == B_OK) {
682 chdir(dirname);
683 do_cmdline_cmd((char_u *)"cd .");
684 }
685 }
686 break;
687 default:
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100688bad:
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200689 /*fprintf(stderr, "bad!\n"); */
690 delete m;
691 return;
692 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100693
694#ifdef FEAT_VISUAL
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200695 reset_VIsual();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100696#endif
697
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200698 char_u **fnames;
699 fnames = (char_u **) alloc(count * sizeof(char_u *));
700 int fname_index = 0;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100701
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200702 switch (m->what) {
703 case B_REFS_RECEIVED:
704 case B_SIMPLE_DATA:
705 // fprintf(stderr, "case B_REFS_RECEIVED\n");
706 for (int i = 0; i < count; ++i)
707 {
708 entry_ref ref;
709 if (m->FindRef("refs", i, &ref) == B_OK) {
710 BEntry entry(&ref, false);
711 BPath path;
712 entry.GetPath(&path);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100713
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200714 // Change to parent directory?
715 if (changedir) {
716 BPath parentpath;
717 path.GetParent(&parentpath);
718 docd(parentpath);
719 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100720
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200721 // Is it a directory? If so, cd into it.
722 BDirectory bdir(&ref);
723 if (bdir.InitCheck() == B_OK) {
724 // don't cd if we already did it
725 if (!changedir)
726 docd(path);
727 } else {
728 mch_dirname(IObuff, IOSIZE);
729 char_u *fname = shorten_fname((char_u *)path.Path(), IObuff);
730 if (fname == NULL)
731 fname = (char_u *)path.Path();
732 fnames[fname_index++] = vim_strsave(fname);
733 // fprintf(stderr, "%s\n", fname);
734 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100735
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200736 // Only do it for the first file/dir
737 changedir = false;
738 }
739 }
740 break;
741 case B_ARGV_RECEIVED:
742 // fprintf(stderr, "case B_ARGV_RECEIVED\n");
743 for (int i = 1; i < count; ++i)
744 {
745 char *fname;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100746
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200747 if (m->FindString("argv", i, (const char **) &fname) == B_OK) {
748 fnames[fname_index++] = vim_strsave((char_u *)fname);
749 }
750 }
751 break;
752 default:
753 // fprintf(stderr, "case default\n");
754 break;
755 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100756
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200757 delete m;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100758
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200759 // Handle the drop, :edit to get to the file
760 if (fname_index > 0) {
761 handle_drop(fname_index, fnames, FALSE, drop_callback, NULL);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100762
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200763 setcursor();
764 out_flush();
765 } else {
766 vim_free(fnames);
767 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100768}
769
770VimApp::VimApp(const char *appsig):
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200771 BApplication(appsig),
772 fFilePanelSem(-1),
773 fFilePanel(NULL)
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100774{
775}
776
777VimApp::~VimApp()
778{
779}
780
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200781 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100782VimApp::ReadyToRun()
783{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200784 /*
785 * Apparently signals are inherited by the created thread -
786 * disable the most annoying ones.
787 */
788 signal(SIGINT, SIG_IGN);
789 signal(SIGQUIT, SIG_IGN);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100790}
791
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200792 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100793VimApp::ArgvReceived(int32 arg_argc, char **arg_argv)
794{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200795 if (!IsLaunching()) {
796 /*
797 * This can happen if we are set to Single or Exclusive
798 * Launch. Be nice and open the file(s).
799 */
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100800 if (gui.vimWindow)
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200801 gui.vimWindow->Minimize(false);
802 BMessage *m = CurrentMessage();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100803 DetachCurrentMessage();
804 SendRefs(m, true);
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200805 }
806}
807
808 void
809VimApp::RefsReceived(BMessage *m)
810{
811 // Horrible hack!!! XXX XXX XXX
812 // The real problem is that b_start_ffc is set too late for
813 // the initial empty buffer. As a result the window will be
814 // split instead of abandoned.
815 int limit = 15;
816 while (--limit >= 0 && (curbuf == NULL || curbuf->b_start_ffc == 0))
817 snooze(100000); // 0.1 s
818 if (gui.vimWindow)
819 gui.vimWindow->Minimize(false);
820 DetachCurrentMessage();
821 SendRefs(m, true);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100822}
823
824/*
825 * Pass a BMessage on to the main() thread.
826 * Caller must have detached the message.
827 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200828 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100829VimApp::SendRefs(BMessage *m, bool changedir)
830{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200831 VimRefsMsg rm;
832 rm.message = m;
833 rm.changedir = changedir;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100834
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200835 write_port(gui.vdcmp, VimMsg::Refs, &rm, sizeof(rm));
836 // calls ::RefsReceived
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100837}
838
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200839 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100840VimApp::MessageReceived(BMessage *m)
841{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200842 switch (m->what) {
843 case 'save':
844 {
845 entry_ref refDirectory;
846 m->FindRef("directory", &refDirectory);
847 fBrowsedPath.SetTo(&refDirectory);
848 BString strName;
849 m->FindString("name", &strName);
850 fBrowsedPath.Append(strName.String());
851 }
852 break;
853 case 'open':
854 {
855 entry_ref ref;
856 m->FindRef("refs", &ref);
857 fBrowsedPath.SetTo(&ref);
858 }
859 break;
860 case B_CANCEL:
861 {
862 BFilePanel *panel;
863 m->FindPointer("source", (void**)&panel);
864 if (fFilePanelSem != -1 && panel == fFilePanel)
865 {
866 delete_sem(fFilePanelSem);
867 fFilePanelSem = -1;
868 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100869
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200870 }
871 break;
872 default:
873 Inherited::MessageReceived(m);
874 break;
875 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100876}
877
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200878 bool
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100879VimApp::QuitRequested()
880{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200881 (void)Inherited::QuitRequested();
882 return false;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100883}
884
885// ---------------- VimWindow ----------------
886
887VimWindow::VimWindow():
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200888 BWindow(BRect(40, 40, 150, 150),
889 "Vim",
890 B_TITLED_WINDOW,
891 0,
892 B_CURRENT_WORKSPACE)
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100893
894{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200895 init();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100896}
897
898VimWindow::~VimWindow()
899{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200900 if (formView) {
901 RemoveChild(formView);
902 delete formView;
903 }
904 gui.vimWindow = NULL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100905}
906
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200907 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100908VimWindow::init()
909{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200910 // Attach the VimFormView
911 formView = new VimFormView(Bounds());
912 if (formView != NULL) {
913 AddChild(formView);
914 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100915}
916
917#if 0 // disabled in zeta patch
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200918 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100919VimWindow::DispatchMessage(BMessage *m, BHandler *h)
920{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200921 /*
922 * Route B_MOUSE_UP messages to MouseUp(), in
923 * a manner that should be compatible with the
924 * intended future system behaviour.
925 */
926 switch (m->what) {
927 case B_MOUSE_UP:
928 // if (!h) h = PreferredHandler();
929 // gcc isn't happy without this extra set of braces, complains about
930 // jump to case label crosses init of 'class BView * v'
931 // richard@whitequeen.com jul 99
932 {
933 BView *v = dynamic_cast<BView *>(h);
934 if (v) {
935 // m->PrintToStream();
936 BPoint where;
937 m->FindPoint("where", &where);
938 v->MouseUp(where);
939 } else {
940 Inherited::DispatchMessage(m, h);
941 }
942 }
943 break;
944 default:
945 Inherited::DispatchMessage(m, h);
946 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100947}
948#endif
949
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200950 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100951VimWindow::WindowActivated(bool active)
952{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200953 Inherited::WindowActivated(active);
954 // the textArea gets the keyboard action
955 if (active && gui.vimTextArea)
956 gui.vimTextArea->MakeFocus(true);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100957
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200958 struct VimFocusMsg fm;
959 fm.active = active;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100960
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200961 write_port(gui.vdcmp, VimMsg::Focus, &fm, sizeof(fm));
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100962}
963
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200964 bool
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100965VimWindow::QuitRequested()
966{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200967 struct VimKeyMsg km;
968 km.length = 5;
969 memcpy((char *)km.chars, "\033:qa\r", km.length);
970 km.csi_escape = false;
971 write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km));
972 return false;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100973}
974
975// ---------------- VimFormView ----------------
976
977VimFormView::VimFormView(BRect frame):
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200978 BView(frame, "VimFormView", B_FOLLOW_ALL_SIDES,
979 B_WILL_DRAW | B_FRAME_EVENTS),
980 menuBar(NULL),
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100981#ifdef FEAT_TOOLBAR
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200982 toolBar(NULL),
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100983#endif
984#ifdef FEAT_GUI_TABLINE
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200985// showingTabLine(false),
986 tabLine(NULL),
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100987#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200988 textArea(NULL)
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100989{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200990 init(frame);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100991}
992
993VimFormView::~VimFormView()
994{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200995 if (menuBar) {
996 RemoveChild(menuBar);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100997#ifdef never
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200998 // deleting the menuBar leads to SEGV on exit
999 // richard@whitequeen.com Jul 99
1000 delete menuBar;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001001#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001002 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001003
1004#ifdef FEAT_TOOLBAR
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001005 delete toolBar;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001006#endif
1007
1008#ifdef FEAT_GUI_TABLINE
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001009 delete tabLine;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001010#endif
1011
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001012 if (textArea) {
1013 RemoveChild(textArea);
1014 delete textArea;
1015 }
1016 gui.vimForm = NULL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001017}
1018
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001019 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001020VimFormView::init(BRect frame)
1021{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001022 menuBar = new BMenuBar(BRect(0,0,-MENUBAR_MARGIN,-MENUBAR_MARGIN),
1023 "VimMenuBar");
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001024
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001025 AddChild(menuBar);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001026
1027#ifdef FEAT_TOOLBAR
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001028 toolBar = new VimToolbar(BRect(0,0,0,0), "VimToolBar");
1029 toolBar->PrepareButtonBitmaps();
1030 AddChild(toolBar);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001031#endif
1032
1033#ifdef FEAT_GUI_TABLINE
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001034 tabLine = new VimTabLine(BRect(0,0,0,0));
1035// tabLine->PrepareButtonBitmaps();
1036 AddChild(tabLine);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001037#endif
1038
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001039 BRect remaining = frame;
1040 textArea = new VimTextAreaView(remaining);
1041 AddChild(textArea);
1042 // The textArea will be resized later when menus are added
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001043
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001044 gui.vimForm = this;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001045}
1046
1047#ifdef FEAT_TOOLBAR
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001048 float
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001049VimFormView::ToolbarHeight() const
1050{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001051 return toolBar ? toolBar->ToolbarHeight() : 0.;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001052}
1053#endif
1054
1055#ifdef FEAT_GUI_TABLINE
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001056 float
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001057VimFormView::TablineHeight() const
1058{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001059 return (tabLine && IsShowingTabLine()) ? tabLine->TablineHeight() : 0.;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001060}
1061#endif
1062
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001063 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001064VimFormView::AllAttached()
1065{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001066 /*
1067 * Apparently signals are inherited by the created thread -
1068 * disable the most annoying ones.
1069 */
1070 signal(SIGINT, SIG_IGN);
1071 signal(SIGQUIT, SIG_IGN);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001072
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001073 if (menuBar && textArea) {
1074 /*
1075 * Resize the textArea to fill the space left over by the menu.
1076 * This is somewhat futile since it will be done again once
1077 * menus are added to the menu bar.
1078 */
1079 BRect remaining = Bounds();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001080
1081#ifdef FEAT_MENU
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001082 remaining.top += MenuHeight();
1083 menuBar->ResizeTo(remaining.right, remaining.top);
1084 gui.menu_height = (int) MenuHeight();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001085#endif
1086
1087#ifdef FEAT_TOOLBAR
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001088 toolBar->MoveTo(remaining.left, remaining.top);
1089 toolBar->ResizeTo(remaining.right, ToolbarHeight());
1090 remaining.top += ToolbarHeight();
1091 gui.toolbar_height = ToolbarHeight();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001092#endif
1093
1094#ifdef FEAT_GUI_TABLINE
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001095 tabLine->MoveTo(remaining.left, remaining.top);
1096 tabLine->ResizeTo(remaining.right + 1, TablineHeight());
1097 remaining.top += TablineHeight();
1098 gui.tabline_height = TablineHeight();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001099#endif
1100
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001101 textArea->ResizeTo(remaining.Width(), remaining.Height());
1102 textArea->MoveTo(remaining.left, remaining.top);
1103 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001104
1105
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001106 Inherited::AllAttached();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001107}
1108
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001109 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001110VimFormView::FrameResized(float new_width, float new_height)
1111{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001112 struct VimResizeMsg sm;
1113 int adjust_h, adjust_w;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001114
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001115 new_width += 1; // adjust from width to number of pixels occupied
1116 new_height += 1;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001117
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001118 sm.width = (int) new_width;
1119 sm.height = (int) new_height;
1120 adjust_w = ((int)new_width - gui_get_base_width()) % gui.char_width;
1121 adjust_h = ((int)new_height - gui_get_base_height()) % gui.char_height;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001122
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001123 if (adjust_w > 0 || adjust_h > 0) {
1124 sm.width -= adjust_w;
1125 sm.height -= adjust_h;
1126 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001127
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001128 write_port(gui.vdcmp, VimMsg::Resize, &sm, sizeof(sm));
1129 // calls gui_resize_shell(new_width, new_height);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001130
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001131 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001132
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001133 /*
1134 * The area below the vertical scrollbar is erased to the colour
1135 * set with SetViewColor() automatically, because we had set
1136 * B_WILL_DRAW. Resizing the window tight around the vertical
1137 * scroll bar also helps to avoid debris.
1138 */
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001139}
1140
1141// ---------------- VimTextAreaView ----------------
1142
1143VimTextAreaView::VimTextAreaView(BRect frame):
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001144 BView(frame, "VimTextAreaView", B_FOLLOW_ALL_SIDES,
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001145#ifdef FEAT_MBYTE_IME
Bram Moolenaar80a8d382020-05-03 22:57:32 +02001146 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_INPUT_METHOD_AWARE
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001147#else
Bram Moolenaar80a8d382020-05-03 22:57:32 +02001148 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001149#endif
Bram Moolenaar80a8d382020-05-03 22:57:32 +02001150 ),
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001151 mouseDragEventCount(0)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001152{
1153#ifdef FEAT_MBYTE_IME
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001154 IMData.messenger = NULL;
1155 IMData.message = NULL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001156#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001157 init(frame);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001158}
1159
1160VimTextAreaView::~VimTextAreaView()
1161{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001162 gui.vimTextArea = NULL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001163}
1164
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001165 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001166VimTextAreaView::init(BRect frame)
1167{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001168 // set up global var for fast access
1169 gui.vimTextArea = this;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001170
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001171 /*
1172 * Tell the app server not to erase the view: we will
1173 * fill it in completely by ourselves.
1174 * (Does this really work? Even if not, it won't harm either.)
1175 */
1176 SetViewColor(B_TRANSPARENT_32_BIT);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001177#define PEN_WIDTH 1
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001178 SetPenSize(PEN_WIDTH);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001179#define W_WIDTH(curwin) 0
1180}
1181
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001182 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001183VimTextAreaView::Draw(BRect updateRect)
1184{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001185 /*
1186 * XXX Other ports call here:
1187 * out_flush(); * make sure all output has been processed *
1188 * but we can't do that, since it involves too much information
1189 * that is owned by other threads...
1190 */
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001191
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001192 /*
1193 * No need to use gui.vimWindow->Lock(): we are locked already.
1194 * However, it would not hurt.
1195 */
1196 rgb_color rgb = GUI_TO_RGB(gui.back_pixel);
1197 SetLowColor(rgb);
1198 FillRect(updateRect, B_SOLID_LOW);
1199 gui_redraw((int) updateRect.left, (int) updateRect.top,
1200 (int) (updateRect.Width() + PEN_WIDTH), (int) (updateRect.Height() + PEN_WIDTH));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001201
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001202 // Clear the border areas if needed
1203 SetLowColor(rgb);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001204
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001205 if (updateRect.left < FILL_X(0)) // left border
1206 FillRect(BRect(updateRect.left, updateRect.top,
1207 FILL_X(0)-PEN_WIDTH, updateRect.bottom), B_SOLID_LOW);
1208 if (updateRect.top < FILL_Y(0)) // top border
1209 FillRect(BRect(updateRect.left, updateRect.top,
1210 updateRect.right, FILL_Y(0)-PEN_WIDTH), B_SOLID_LOW);
1211 if (updateRect.right >= FILL_X(Columns)) // right border
1212 FillRect(BRect(FILL_X((int)Columns), updateRect.top,
1213 updateRect.right, updateRect.bottom), B_SOLID_LOW);
1214 if (updateRect.bottom >= FILL_Y(Rows)) // bottom border
1215 FillRect(BRect(updateRect.left, FILL_Y((int)Rows),
1216 updateRect.right, updateRect.bottom), B_SOLID_LOW);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001217
1218#ifdef FEAT_MBYTE_IME
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001219 DrawIMString();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001220#endif
1221}
1222
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001223 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001224VimTextAreaView::KeyDown(const char *bytes, int32 numBytes)
1225{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001226 struct VimKeyMsg km;
1227 char_u *dest = km.chars;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001228
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001229 bool canHaveVimModifiers = false;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001230
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001231 BMessage *msg = Window()->CurrentMessage();
1232 assert(msg);
1233 // msg->PrintToStream();
1234
1235 /*
1236 * Convert special keys to Vim codes.
1237 * I think it is better to do it in the window thread
1238 * so we use at least a little bit of the potential
1239 * of our 2 CPUs. Besides, due to the fantastic mapping
1240 * of special keys to UTF-8, we have quite some work to
1241 * do...
1242 * TODO: I'm not quite happy with detection of special
1243 * keys. Perhaps I should use scan codes after all...
1244 */
1245 if (numBytes > 1) {
1246 // This cannot be a special key
1247 if (numBytes > KEY_MSG_BUFSIZ)
1248 numBytes = KEY_MSG_BUFSIZ; // should never happen... ???
1249 km.length = numBytes;
1250 memcpy((char *)dest, bytes, numBytes);
1251 km.csi_escape = true;
1252 } else {
1253 int32 scancode = 0;
1254 msg->FindInt32("key", &scancode);
1255
1256 int32 beModifiers = 0;
1257 msg->FindInt32("modifiers", &beModifiers);
1258
1259 char_u string[3];
1260 int len = 0;
1261 km.length = 0;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001262
1263 /*
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001264 * For normal, printable ASCII characters, don't look them up
1265 * to check if they might be a special key. They aren't.
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001266 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001267 assert(B_BACKSPACE <= 0x20);
1268 assert(B_DELETE == 0x7F);
1269 if (((char_u)bytes[0] <= 0x20 || (char_u)bytes[0] == 0x7F) &&
1270 numBytes == 1) {
1271 /*
1272 * Due to the great nature of Be's mapping of special keys,
1273 * viz. into the range of the control characters,
1274 * we can only be sure it is *really* a special key if
1275 * if it is special without using ctrl. So, only if ctrl is
1276 * used, we need to check it unmodified.
1277 */
1278 if (beModifiers & B_CONTROL_KEY) {
1279 int index = keyMap->normal_map[scancode];
1280 int newNumBytes = keyMapChars[index];
1281 char_u *newBytes = (char_u *)&keyMapChars[index + 1];
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001282
1283 /*
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001284 * Check if still special without the control key.
1285 * This is needed for BACKSPACE: that key does produce
1286 * different values with modifiers (DEL).
1287 * Otherwise we could simply have checked for equality.
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001288 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001289 if (newNumBytes != 1 || (*newBytes > 0x20 &&
1290 *newBytes != 0x7F )) {
1291 goto notspecial;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001292 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001293 bytes = (char *)newBytes;
1294 }
1295 canHaveVimModifiers = true;
1296
1297 uint16 beoskey;
1298 int first, last;
1299
1300 /*
1301 * If numBytes == 0 that probably always indicates a special key.
1302 * (does not happen yet)
1303 */
1304 if (numBytes == 0 || bytes[0] == B_FUNCTION_KEY) {
1305 beoskey = F(scancode);
1306 first = FIRST_FUNCTION_KEY;
1307 last = NUM_SPECIAL_KEYS;
1308 } else if (*bytes == '\n' && scancode == 0x47) {
1309 // remap the (non-keypad) ENTER key from \n to \r.
1310 string[0] = '\r';
1311 len = 1;
1312 first = last = 0;
1313 } else {
1314 beoskey = K(bytes[0]);
1315 first = 0;
1316 last = FIRST_FUNCTION_KEY;
1317 }
1318
1319 for (int i = first; i < last; i++) {
1320 if (special_keys[i].BeKeys == beoskey) {
1321 string[0] = CSI;
1322 string[1] = special_keys[i].vim_code0;
1323 string[2] = special_keys[i].vim_code1;
1324 len = 3;
1325 }
1326 }
1327 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001328notspecial:
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001329 if (len == 0) {
1330 string[0] = bytes[0];
1331 len = 1;
1332 }
1333
1334 // Special keys (and a few others) may have modifiers
1335#if 0
1336 if (len == 3 ||
1337 bytes[0] == B_SPACE || bytes[0] == B_TAB ||
1338 bytes[0] == B_RETURN || bytes[0] == '\r' ||
1339 bytes[0] == B_ESCAPE)
1340#else
1341 if (canHaveVimModifiers)
1342#endif
1343 {
1344 int modifiers;
1345 modifiers = 0;
1346 if (beModifiers & B_SHIFT_KEY)
1347 modifiers |= MOD_MASK_SHIFT;
1348 if (beModifiers & B_CONTROL_KEY)
1349 modifiers |= MOD_MASK_CTRL;
1350 if (beModifiers & B_OPTION_KEY)
1351 modifiers |= MOD_MASK_ALT;
1352
1353 /*
1354 * For some keys a shift modifier is translated into another key
1355 * code. Do we need to handle the case where len != 1 and
1356 * string[0] != CSI? (Not for BeOS, since len == 3 implies
1357 * string[0] == CSI...)
1358 */
1359 int key;
1360 if (string[0] == CSI && len == 3)
1361 key = TO_SPECIAL(string[1], string[2]);
1362 else
1363 key = string[0];
1364 key = simplify_key(key, &modifiers);
1365 if (IS_SPECIAL(key))
1366 {
1367 string[0] = CSI;
1368 string[1] = K_SECOND(key);
1369 string[2] = K_THIRD(key);
1370 len = 3;
1371 }
1372 else
1373 {
1374 string[0] = key;
1375 len = 1;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001376 }
1377
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001378 if (modifiers)
1379 {
1380 *dest++ = CSI;
1381 *dest++ = KS_MODIFIER;
1382 *dest++ = modifiers;
1383 km.length = 3;
1384 }
1385 }
1386 memcpy((char *)dest, string, len);
1387 km.length += len;
1388 km.csi_escape = false;
1389 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001390
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001391 write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001392
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001393 /*
1394 * blank out the pointer if necessary
1395 */
1396 if (p_mh && !gui.pointer_hidden)
1397 {
1398 guiBlankMouse(true);
1399 gui.pointer_hidden = TRUE;
1400 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001401}
1402void
1403VimTextAreaView::guiSendMouseEvent(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001404 int button,
1405 int x,
1406 int y,
1407 int repeated_click,
1408 int_u modifiers)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001409{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001410 VimMouseMsg mm;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001411
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001412 mm.button = button;
1413 mm.x = x;
1414 mm.y = y;
1415 mm.repeated_click = repeated_click;
1416 mm.modifiers = modifiers;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001417
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001418 write_port(gui.vdcmp, VimMsg::Mouse, &mm, sizeof(mm));
1419 // calls gui_send_mouse_event()
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001420
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001421 /*
1422 * if our pointer is currently hidden, then we should show it.
1423 */
1424 if (gui.pointer_hidden)
1425 {
1426 guiBlankMouse(false);
1427 gui.pointer_hidden = FALSE;
1428 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001429}
1430
1431void
1432VimTextAreaView::guiMouseMoved(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001433 int x,
1434 int y)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001435{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001436 VimMouseMovedMsg mm;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001437
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001438 mm.x = x;
1439 mm.y = y;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001440
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001441 write_port(gui.vdcmp, VimMsg::MouseMoved, &mm, sizeof(mm));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001442
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001443 if (gui.pointer_hidden)
1444 {
1445 guiBlankMouse(false);
1446 gui.pointer_hidden = FALSE;
1447 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001448}
1449
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001450 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001451VimTextAreaView::guiBlankMouse(bool should_hide)
1452{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001453 if (should_hide) {
1454 // gui.vimApp->HideCursor();
1455 gui.vimApp->ObscureCursor();
1456 /*
1457 * ObscureCursor() would even be easier, but then
1458 * Vim's idea of mouse visibility does not necessarily
1459 * correspond to reality.
1460 */
1461 } else {
1462 // gui.vimApp->ShowCursor();
1463 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001464}
1465
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001466 int_u
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001467VimTextAreaView::mouseModifiersToVim(int32 beModifiers)
1468{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001469 int_u vim_modifiers = 0x0;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001470
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001471 if (beModifiers & B_SHIFT_KEY)
1472 vim_modifiers |= MOUSE_SHIFT;
1473 if (beModifiers & B_CONTROL_KEY)
1474 vim_modifiers |= MOUSE_CTRL;
1475 if (beModifiers & B_OPTION_KEY) // Alt or Meta key
1476 vim_modifiers |= MOUSE_ALT;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001477
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001478 return vim_modifiers;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001479}
1480
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001481 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001482VimTextAreaView::MouseDown(BPoint point)
1483{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001484 BMessage *m = Window()->CurrentMessage();
1485 assert(m);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001486
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001487 int32 buttons = 0;
1488 m->FindInt32("buttons", &buttons);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001489
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001490 int vimButton;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001491
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001492 if (buttons & B_PRIMARY_MOUSE_BUTTON)
1493 vimButton = MOUSE_LEFT;
1494 else if (buttons & B_SECONDARY_MOUSE_BUTTON)
1495 vimButton = MOUSE_RIGHT;
1496 else if (buttons & B_TERTIARY_MOUSE_BUTTON)
1497 vimButton = MOUSE_MIDDLE;
1498 else
1499 return; // Unknown button
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001500
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001501 vimMouseButton = 1; // don't care which one
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001502
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001503 // Handle multiple clicks
1504 int32 clicks = 0;
1505 m->FindInt32("clicks", &clicks);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001506
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001507 int32 modifiers = 0;
1508 m->FindInt32("modifiers", &modifiers);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001509
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001510 vimMouseModifiers = mouseModifiersToVim(modifiers);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001511
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001512 guiSendMouseEvent(vimButton, point.x, point.y,
1513 clicks > 1 /* = repeated_click*/, vimMouseModifiers);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001514}
1515
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001516 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001517VimTextAreaView::MouseUp(BPoint point)
1518{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001519 vimMouseButton = 0;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001520
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001521 BMessage *m = Window()->CurrentMessage();
1522 assert(m);
1523 // m->PrintToStream();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001524
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001525 int32 modifiers = 0;
1526 m->FindInt32("modifiers", &modifiers);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001527
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001528 vimMouseModifiers = mouseModifiersToVim(modifiers);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001529
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001530 guiSendMouseEvent(MOUSE_RELEASE, point.x, point.y,
1531 0 /* = repeated_click*/, vimMouseModifiers);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001532
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001533 Inherited::MouseUp(point);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001534}
1535
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001536 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001537VimTextAreaView::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
1538{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001539 /*
1540 * if our pointer is currently hidden, then we should show it.
1541 */
1542 if (gui.pointer_hidden)
1543 {
1544 guiBlankMouse(false);
1545 gui.pointer_hidden = FALSE;
1546 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001547
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001548 if (!vimMouseButton) { // could also check m->"buttons"
1549 guiMouseMoved(point.x, point.y);
1550 return;
1551 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001552
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001553 atomic_add(&mouseDragEventCount, 1);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001554
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001555 // Don't care much about "transit"
1556 guiSendMouseEvent(MOUSE_DRAG, point.x, point.y, 0, vimMouseModifiers);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001557}
1558
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001559 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001560VimTextAreaView::MessageReceived(BMessage *m)
1561{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001562 switch (m->what) {
1563 case 'menu':
1564 {
1565 VimMenuMsg mm;
1566 mm.guiMenu = NULL; // in case no pointer in msg
1567 m->FindPointer("VimMenu", (void **)&mm.guiMenu);
1568 write_port(gui.vdcmp, VimMsg::Menu, &mm, sizeof(mm));
1569 }
1570 break;
1571 case B_MOUSE_WHEEL_CHANGED:
1572 {
1573 VimScrollBar* scb = curwin->w_scrollbars[1].id;
1574 float small=0, big=0, dy=0;
1575 m->FindFloat("be:wheel_delta_y", &dy);
1576 scb->GetSteps(&small, &big);
1577 scb->SetValue(scb->Value()+small*dy*3);
1578 scb->ValueChanged(scb->Value());
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001579#if 0
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001580 scb = curwin->w_scrollbars[0].id;
1581 scb->GetSteps(&small, &big);
1582 scb->SetValue(scb->Value()+small*dy);
1583 scb->ValueChanged(scb->Value());
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001584#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001585 }
1586 break;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001587#ifdef FEAT_MBYTE_IME
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001588 case B_INPUT_METHOD_EVENT:
1589 {
1590 int32 opcode;
1591 m->FindInt32("be:opcode", &opcode);
1592 switch(opcode)
1593 {
1594 case B_INPUT_METHOD_STARTED:
1595 if (!IMData.messenger) delete IMData.messenger;
1596 IMData.messenger = new BMessenger();
1597 m->FindMessenger("be:reply_to", IMData.messenger);
1598 break;
1599 case B_INPUT_METHOD_CHANGED:
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001600 {
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001601 BString str;
1602 bool confirmed;
1603 if (IMData.message) *(IMData.message) = *m;
1604 else IMData.message = new BMessage(*m);
1605 DrawIMString();
1606 m->FindBool("be:confirmed", &confirmed);
1607 if (confirmed)
1608 {
1609 m->FindString("be:string", &str);
1610 char_u *chars = (char_u*)str.String();
1611 struct VimKeyMsg km;
1612 km.csi_escape = true;
1613 int clen;
1614 int i = 0;
1615 while (i < str.Length())
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001616 {
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001617 clen = utf_ptr2len(chars+i);
1618 memcpy(km.chars, chars+i, clen);
1619 km.length = clen;
1620 write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km));
1621 i += clen;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001622 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001623 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001624 }
1625 break;
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001626 case B_INPUT_METHOD_LOCATION_REQUEST:
1627 {
1628 BMessage msg(B_INPUT_METHOD_EVENT);
1629 msg.AddInt32("be:opcode", B_INPUT_METHOD_LOCATION_REQUEST);
1630 msg.AddPoint("be:location_reply", IMData.location);
1631 msg.AddFloat("be:height_reply", FILL_Y(1));
1632 IMData.messenger->SendMessage(&msg);
1633 }
1634 break;
1635 case B_INPUT_METHOD_STOPPED:
1636 delete IMData.messenger;
1637 delete IMData.message;
1638 IMData.messenger = NULL;
1639 IMData.message = NULL;
1640 break;
1641 }
1642 }
1643 // TODO: sz: break here???
1644#endif
1645 default:
1646 if (m->WasDropped()) {
1647 BWindow *w = Window();
1648 w->DetachCurrentMessage();
1649 w->Minimize(false);
1650 VimApp::SendRefs(m, (modifiers() & B_SHIFT_KEY) != 0);
1651 } else {
1652 Inherited::MessageReceived(m);
1653 }
1654 break;
1655 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001656}
1657
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001658 int
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001659VimTextAreaView::mchInitFont(char_u *name)
1660{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001661 VimFont *newFont = (VimFont *)gui_mch_get_font(name, 1);
1662 if (newFont != NOFONT) {
1663 gui.norm_font = (GuiFont)newFont;
1664 gui_mch_set_font((GuiFont)newFont);
1665 if (name && STRCMP(name, "*") != 0)
1666 hl_set_font_name(name);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001667
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001668 SetDrawingMode(B_OP_COPY);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001669
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001670 /*
1671 * Try to load other fonts for bold, italic, and bold-italic.
1672 * We should also try to work out what font to use for these when they are
1673 * not specified by X resources, but we don't yet.
1674 */
1675 return OK;
1676 }
1677 return FAIL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001678}
1679
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001680 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001681VimTextAreaView::mchDrawString(int row, int col, char_u *s, int len, int flags)
1682{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001683 /*
1684 * First we must erase the area, because DrawString won't do
1685 * that for us. XXX Most of the time this is a waste of effort
1686 * since the bachground has been erased already... DRAW_TRANSP
1687 * should be set when appropriate!!!
1688 * (Rectangles include the bottom and right edge)
1689 */
1690 if (!(flags & DRAW_TRANSP)) {
1691 int cells;
1692 cells = 0;
1693 for (int i=0; i<len; i++) {
1694 int cn = utf_ptr2cells((char_u *)(s+i));
1695 if (cn<4) cells += cn;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001696 }
1697
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001698 BRect r(FILL_X(col), FILL_Y(row),
1699 FILL_X(col + cells) - PEN_WIDTH, FILL_Y(row + 1) - PEN_WIDTH);
1700 FillRect(r, B_SOLID_LOW);
1701 }
1702
1703 BFont font;
1704 this->GetFont(&font);
1705 if (!font.IsFixed())
1706 {
1707 char* p = (char*)s;
1708 int32 clen, lastpos = 0;
1709 BPoint where;
1710 int cells;
1711 while ((p - (char*)s) < len) {
1712 clen = utf_ptr2len((u_char*)p);
1713 where.Set(TEXT_X(col+lastpos), TEXT_Y(row));
1714 DrawString(p, clen, where);
1715 if (flags & DRAW_BOLD) {
1716 where.x += 1.0;
1717 SetDrawingMode(B_OP_BLEND);
1718 DrawString(p, clen, where);
1719 SetDrawingMode(B_OP_COPY);
1720 }
1721 cells = utf_ptr2cells((char_u *)p);
1722 if (cells<4) lastpos += cells;
1723 else lastpos++;
1724 p += clen;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001725 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001726 }
1727 else
1728 {
1729 BPoint where(TEXT_X(col), TEXT_Y(row));
1730 DrawString((char*)s, len, where);
1731 if (flags & DRAW_BOLD) {
1732 where.x += 1.0;
1733 SetDrawingMode(B_OP_BLEND);
1734 DrawString((char*)s, len, where);
1735 SetDrawingMode(B_OP_COPY);
1736 }
1737 }
1738
1739 if (flags & DRAW_UNDERL) {
1740 int cells;
1741 cells = 0;
1742 for (int i=0; i<len; i++) {
1743 int cn = utf_ptr2cells((char_u *)(s+i));
1744 if (cn<4) cells += cn;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001745 }
1746
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001747 BPoint start(FILL_X(col), FILL_Y(row + 1) - PEN_WIDTH);
1748 BPoint end(FILL_X(col + cells) - PEN_WIDTH, start.y);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001749
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001750 StrokeLine(start, end);
1751 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001752}
1753
1754void
1755VimTextAreaView::mchClearBlock(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001756 int row1,
1757 int col1,
1758 int row2,
1759 int col2)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001760{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001761 BRect r(FILL_X(col1), FILL_Y(row1),
1762 FILL_X(col2 + 1) - PEN_WIDTH, FILL_Y(row2 + 1) - PEN_WIDTH);
1763 gui_mch_set_bg_color(gui.back_pixel);
1764 FillRect(r, B_SOLID_LOW);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001765}
1766
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001767 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001768VimTextAreaView::mchClearAll()
1769{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001770 gui_mch_set_bg_color(gui.back_pixel);
1771 FillRect(Bounds(), B_SOLID_LOW);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001772}
1773
1774/*
1775 * mchDeleteLines() Lock()s the window by itself.
1776 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001777 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001778VimTextAreaView::mchDeleteLines(int row, int num_lines)
1779{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001780 BRect source, dest;
1781 source.left = FILL_X(gui.scroll_region_left);
1782 source.top = FILL_Y(row + num_lines);
1783 source.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH;
1784 source.bottom = FILL_Y(gui.scroll_region_bot + 1) - PEN_WIDTH;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001785
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001786 dest.left = FILL_X(gui.scroll_region_left);
1787 dest.top = FILL_Y(row);
1788 dest.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH;
1789 dest.bottom = FILL_Y(gui.scroll_region_bot - num_lines + 1) - PEN_WIDTH;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001790
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001791 if (gui.vimWindow->Lock()) {
1792 // Clear one column more for when bold has spilled over
1793 CopyBits(source, dest);
1794 gui_clear_block(gui.scroll_region_bot - num_lines + 1,
1795 gui.scroll_region_left,
1796 gui.scroll_region_bot, gui.scroll_region_right);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001797
1798
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001799 gui.vimWindow->Unlock();
1800 /*
1801 * The Draw() callback will be called now if some of the source
1802 * bits were not in the visible region.
1803 */
1804 }
1805 // gui_x11_check_copy_area();
1806 // }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001807}
1808
1809/*
1810 * mchInsertLines() Lock()s the window by itself.
1811 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001812 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001813VimTextAreaView::mchInsertLines(int row, int num_lines)
1814{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001815 BRect source, dest;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001816
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001817 // XXX Attempt at a hack:
1818 gui.vimWindow->UpdateIfNeeded();
1819 source.left = FILL_X(gui.scroll_region_left);
1820 source.top = FILL_Y(row);
1821 source.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH;
1822 source.bottom = FILL_Y(gui.scroll_region_bot - num_lines + 1) - PEN_WIDTH;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001823
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001824 dest.left = FILL_X(gui.scroll_region_left);
1825 dest.top = FILL_Y(row + num_lines);
1826 dest.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH;
1827 dest.bottom = FILL_Y(gui.scroll_region_bot + 1) - PEN_WIDTH;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001828
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001829 if (gui.vimWindow->Lock()) {
1830 // Clear one column more for when bold has spilled over
1831 CopyBits(source, dest);
1832 gui_clear_block(row, gui.scroll_region_left,
1833 row + num_lines - 1, gui.scroll_region_right);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001834
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001835 gui.vimWindow->Unlock();
1836 /*
1837 * The Draw() callback will be called now if some of the source
1838 * bits were not in the visible region.
1839 * However, if we scroll too fast it can't keep up and the
1840 * update region gets messed up. This seems to be because copying
1841 * un-Draw()n bits does not generate Draw() calls for the copy...
1842 * I moved the hack to before the CopyBits() to reduce the
1843 * amount of additional waiting needed.
1844 */
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001845
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001846 // gui_x11_check_copy_area();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001847
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001848 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001849}
1850
1851#ifdef FEAT_MBYTE_IME
1852/*
1853 * DrawIMString draws string with IMData.message.
1854 */
1855void VimTextAreaView::DrawIMString(void)
1856{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001857 static const rgb_color r_highlight = {255, 152, 152, 255},
1858 b_highlight = {152, 203, 255, 255};
1859 BString str;
1860 const char* s;
1861 int len;
1862 BMessage* msg = IMData.message;
1863 if (!msg)
1864 return;
1865 gui_redraw_block(IMData.row, 0,
1866 IMData.row + IMData.count, W_WIDTH(curwin), GUI_MON_NOCLEAR);
1867 bool confirmed = false;
1868 msg->FindBool("be:confirmed", &confirmed);
1869 if (confirmed)
1870 return;
1871 rgb_color hcolor = HighColor(), lcolor = LowColor();
1872 msg->FindString("be:string", &str);
1873 s = str.String();
1874 len = str.Length();
1875 SetHighColor(0, 0, 0);
1876 IMData.row = gui.row;
1877 IMData.col = gui.col;
1878 int32 sel_start = 0, sel_end = 0;
1879 msg->FindInt32("be:selection", 0, &sel_start);
1880 msg->FindInt32("be:selection", 1, &sel_end);
1881 int clen, cn;
1882 BPoint pos(IMData.col, 0);
1883 BRect r;
1884 BPoint where;
1885 IMData.location = ConvertToScreen(
1886 BPoint(FILL_X(pos.x), FILL_Y(IMData.row + pos.y)));
1887 for (int i=0; i<len; i+=clen)
1888 {
1889 cn = utf_ptr2cells((char_u *)(s+i));
1890 clen = utf_ptr2len((char_u *)(s+i));
1891 if (pos.x + cn > W_WIDTH(curwin))
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001892 {
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001893 pos.y++;
1894 pos.x = 0;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001895 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001896 if (sel_start<=i && i<sel_end)
1897 {
1898 SetLowColor(r_highlight);
1899 IMData.location = ConvertToScreen(
1900 BPoint(FILL_X(pos.x), FILL_Y(IMData.row + pos.y)));
1901 }
1902 else
1903 {
1904 SetLowColor(b_highlight);
1905 }
1906 r.Set(FILL_X(pos.x), FILL_Y(IMData.row + pos.y),
1907 FILL_X(pos.x + cn) - PEN_WIDTH,
1908 FILL_Y(IMData.row + pos.y + 1) - PEN_WIDTH);
1909 FillRect(r, B_SOLID_LOW);
1910 where.Set(TEXT_X(pos.x), TEXT_Y(IMData.row + pos.y));
1911 DrawString((s+i), clen, where);
1912 pos.x += cn;
1913 }
1914 IMData.count = (int)pos.y;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001915
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001916 SetHighColor(hcolor);
1917 SetLowColor(lcolor);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001918}
1919#endif
1920// ---------------- VimScrollBar ----------------
1921
1922/*
1923 * BUG: XXX
1924 * It seems that BScrollBar determine their direction not from
1925 * "posture" but from if they are "tall" or "wide" in shape...
1926 *
1927 * Also, place them out of sight, because Vim enables them before
1928 * they are positioned.
1929 */
1930VimScrollBar::VimScrollBar(scrollbar_T *g, orientation posture):
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001931 BScrollBar(posture == B_HORIZONTAL ? BRect(-100,-100,-10,-90) :
1932 BRect(-100,-100,-90,-10),
1933 "vim scrollbar", (BView *)NULL,
1934 0.0, 10.0, posture),
1935 ignoreValue(-1),
1936 scrollEventCount(0)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001937{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001938 gsb = g;
1939 SetResizingMode(B_FOLLOW_NONE);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001940}
1941
1942VimScrollBar::~VimScrollBar()
1943{
1944}
1945
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001946 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001947VimScrollBar::ValueChanged(float newValue)
1948{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001949 if (ignoreValue >= 0.0 && newValue == ignoreValue) {
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001950 ignoreValue = -1;
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001951 return;
1952 }
1953 ignoreValue = -1;
1954 /*
1955 * We want to throttle the amount of scroll messages generated.
1956 * Normally I presume you won't get a new message before we've
1957 * handled the previous one, but because we're passing them on this
1958 * happens very quickly. So instead we keep a counter of how many
1959 * scroll events there are (or will be) in the VDCMP, and the
1960 * throttling happens at the receiving end.
1961 */
1962 atomic_add(&scrollEventCount, 1);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001963
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001964 struct VimScrollBarMsg sm;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001965
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001966 sm.sb = this;
1967 sm.value = (long) newValue;
1968 sm.stillDragging = TRUE;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001969
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001970 write_port(gui.vdcmp, VimMsg::ScrollBar, &sm, sizeof(sm));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001971
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001972 // calls gui_drag_scrollbar(sb, newValue, TRUE);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001973}
1974
1975/*
1976 * When the mouse goes up, report that scrolling has stopped.
1977 * MouseUp() is NOT called when the mouse-up occurs outside
1978 * the window, even though the thumb does move while the mouse
1979 * is outside... This has some funny effects... XXX
1980 * So we do special processing when the window de/activates.
1981 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001982 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001983VimScrollBar::MouseUp(BPoint where)
1984{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001985 // BMessage *m = Window()->CurrentMessage();
1986 // m->PrintToStream();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001987
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001988 atomic_add(&scrollEventCount, 1);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001989
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001990 struct VimScrollBarMsg sm;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001991
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001992 sm.sb = this;
1993 sm.value = (long) Value();
1994 sm.stillDragging = FALSE;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001995
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001996 write_port(gui.vdcmp, VimMsg::ScrollBar, &sm, sizeof(sm));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001997
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001998 // calls gui_drag_scrollbar(sb, newValue, FALSE);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001999
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002000 Inherited::MouseUp(where);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002001}
2002
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002003 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002004VimScrollBar::SetValue(float newValue)
2005{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002006 if (newValue == Value())
2007 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002008
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002009 ignoreValue = newValue;
2010 Inherited::SetValue(newValue);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002011}
2012
2013// ---------------- VimFont ----------------
2014
2015VimFont::VimFont(): BFont()
2016{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002017 init();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002018}
2019
2020VimFont::VimFont(const VimFont *rhs): BFont(rhs)
2021{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002022 init();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002023}
2024
2025VimFont::VimFont(const BFont *rhs): BFont(rhs)
2026{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002027 init();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002028}
2029
2030VimFont::VimFont(const VimFont &rhs): BFont(rhs)
2031{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002032 init();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002033}
2034
2035VimFont::~VimFont()
2036{
2037}
2038
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002039 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002040VimFont::init()
2041{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002042 next = NULL;
2043 refcount = 1;
2044 name = NULL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002045}
2046
2047// ---------------- VimDialog ----------------
2048
2049#if defined(FEAT_GUI_DIALOG)
2050
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002051const unsigned int kVimDialogButtonMsg = 'VMDB';
2052const unsigned int kVimDialogIconStripeWidth = 30;
2053const unsigned int kVimDialogButtonsSpacingX = 9;
2054const unsigned int kVimDialogButtonsSpacingY = 4;
2055const unsigned int kVimDialogSpacingX = 6;
2056const unsigned int kVimDialogSpacingY = 10;
2057const unsigned int kVimDialogMinimalWidth = 310;
2058const unsigned int kVimDialogMinimalHeight = 75;
2059const BRect kDefaultRect =
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002060BRect(0, 0, kVimDialogMinimalWidth, kVimDialogMinimalHeight);
2061
2062VimDialog::VimDialog(int type, const char *title, const char *message,
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002063 const char *buttons, int dfltbutton, const char *textfield, int ex_cmd)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002064: BWindow(kDefaultRect, title, B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL,
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002065 B_NOT_CLOSABLE | B_NOT_RESIZABLE |
2066 B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_ASYNCHRONOUS_CONTROLS)
2067 , fDialogSem(-1)
2068 , fDialogValue(dfltbutton)
2069 , fMessageView(NULL)
2070 , fInputControl(NULL)
2071 , fInputValue(textfield)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002072{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002073 // master view
2074 VimDialog::View* view = new VimDialog::View(Bounds());
2075 if (view == NULL)
2076 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002077
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002078 if (title == NULL)
2079 SetTitle("Vim " VIM_VERSION_MEDIUM);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002080
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002081 AddChild(view);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002082
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002083 // icon
2084 view->InitIcon(type);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002085
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002086 // buttons
2087 int32 which = 1;
2088 float maxButtonWidth = 0;
2089 float maxButtonHeight = 0;
2090 float buttonsWidth = 0;
2091 float buttonsHeight = 0;
2092 BString strButtons(buttons);
2093 strButtons.RemoveAll("&");
2094 do {
2095 int32 end = strButtons.FindFirst('\n');
2096 if (end != B_ERROR)
2097 strButtons.SetByteAt(end, '\0');
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002098
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002099 BButton *button = _CreateButton(which++, strButtons.String());
2100 view->AddChild(button);
2101 fButtonsList.AddItem(button);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002102
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002103 maxButtonWidth = max_c(maxButtonWidth, button->Bounds().Width());
2104 maxButtonHeight = max_c(maxButtonHeight, button->Bounds().Height());
2105 buttonsWidth += button->Bounds().Width();
2106 buttonsHeight += button->Bounds().Height();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002107
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002108 if (end == B_ERROR)
2109 break;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002110
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002111 strButtons.Remove(0, end + 1);
2112 } while (true);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002113
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002114 int32 buttonsCount = fButtonsList.CountItems();
2115 buttonsWidth += kVimDialogButtonsSpacingX * (buttonsCount - 1);
2116 buttonsHeight += kVimDialogButtonsSpacingY * (buttonsCount - 1);
2117 float dialogWidth = buttonsWidth + kVimDialogIconStripeWidth +
2118 kVimDialogSpacingX * 2;
2119 float dialogHeight = maxButtonHeight + kVimDialogSpacingY * 3;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002120
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002121 // Check 'v' flag in 'guioptions': vertical button placement.
2122 bool vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL) ||
2123 dialogWidth >= gui.vimWindow->Bounds().Width();
2124 if (vertical) {
2125 dialogWidth -= buttonsWidth;
2126 dialogWidth += maxButtonWidth;
2127 dialogHeight -= maxButtonHeight;
2128 dialogHeight += buttonsHeight;
2129 }
2130
2131 dialogWidth = max_c(dialogWidth, kVimDialogMinimalWidth);
2132
2133 // message view
2134 BRect rect(0, 0, dialogWidth, 0);
2135 rect.left += kVimDialogIconStripeWidth + 16 + kVimDialogSpacingX;
2136 rect.top += kVimDialogSpacingY;
2137 rect.right -= kVimDialogSpacingX;
2138 rect.bottom = rect.top;
2139 fMessageView = new BTextView(rect, "_tv_", rect.OffsetByCopy(B_ORIGIN),
2140 B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW);
2141
2142 fMessageView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
2143 rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR);
2144 fMessageView->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor);
2145 fMessageView->SetText(message);
2146 fMessageView->MakeEditable(false);
2147 fMessageView->MakeSelectable(false);
2148 fMessageView->SetWordWrap(true);
2149 AddChild(fMessageView);
2150
2151 float messageHeight = fMessageView->TextHeight(0, fMessageView->CountLines());
2152 fMessageView->ResizeBy(0, messageHeight);
2153 fMessageView->SetTextRect(BRect(0, 0, rect.Width(), messageHeight));
2154
2155 dialogHeight += messageHeight;
2156
2157 // input view
2158 if (fInputValue != NULL) {
2159 rect.top =
2160 rect.bottom += messageHeight + kVimDialogSpacingY;
2161 fInputControl = new BTextControl(rect, "_iv_", NULL, fInputValue, NULL,
2162 B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE | B_PULSE_NEEDED);
2163 fInputControl->TextView()->SetText(fInputValue);
2164 fInputControl->TextView()->SetWordWrap(false);
2165 AddChild(fInputControl);
2166
2167 float width = 0.f, height = 0.f;
2168 fInputControl->GetPreferredSize(&width, &height);
2169 fInputControl->MakeFocus(true);
2170
2171 dialogHeight += height + kVimDialogSpacingY * 1.5;
2172 }
2173
2174 dialogHeight = max_c(dialogHeight, kVimDialogMinimalHeight);
2175
2176 ResizeTo(dialogWidth, dialogHeight);
2177 MoveTo((gui.vimWindow->Bounds().Width() - dialogWidth) / 2,
2178 (gui.vimWindow->Bounds().Height() - dialogHeight) / 2);
2179
2180 // adjust layout of buttons
2181 float buttonWidth = max_c(maxButtonWidth, rect.Width() * 0.66);
2182 BPoint origin(dialogWidth, dialogHeight);
2183 origin.x -= kVimDialogSpacingX + (vertical ? buttonWidth : buttonsWidth);
2184 origin.y -= kVimDialogSpacingY + (vertical ? buttonsHeight : maxButtonHeight);
2185
2186 for (int32 i = 0 ; i < buttonsCount; i++) {
2187 BButton *button = (BButton*)fButtonsList.ItemAt(i);
2188 button->MoveTo(origin);
2189 if (vertical) {
2190 origin.y += button->Frame().Height() + kVimDialogButtonsSpacingY;
2191 button->ResizeTo(buttonWidth, button->Frame().Height());
2192 } else
2193 origin.x += button->Frame().Width() + kVimDialogButtonsSpacingX;
2194
2195 if (dfltbutton == i + 1) {
2196 button->MakeDefault(true);
2197 button->MakeFocus(fInputControl == NULL);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002198 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002199 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002200}
2201
2202VimDialog::~VimDialog()
2203{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002204 if (fDialogSem > B_OK)
2205 delete_sem(fDialogSem);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002206}
2207
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002208 int
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002209VimDialog::Go()
2210{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002211 fDialogSem = create_sem(0, "VimDialogSem");
2212 if (fDialogSem < B_OK) {
2213 Quit();
2214 return fDialogValue;
2215 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002216
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002217 Show();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002218
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002219 while (acquire_sem(fDialogSem) == B_INTERRUPTED);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002220
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002221 int retValue = fDialogValue;
2222 if (fInputValue != NULL)
2223 vim_strncpy((char_u*)fInputValue, (char_u*)fInputControl->Text(), IOSIZE - 1);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002224
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002225 if (Lock())
2226 Quit();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002227
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002228 return retValue;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002229}
2230
2231void VimDialog::MessageReceived(BMessage *msg)
2232{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002233 int32 which = 0;
2234 if (msg->what != kVimDialogButtonMsg ||
2235 msg->FindInt32("which", &which) != B_OK)
2236 return BWindow::MessageReceived(msg);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002237
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002238 fDialogValue = which;
2239 delete_sem(fDialogSem);
2240 fDialogSem = -1;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002241}
2242
2243BButton* VimDialog::_CreateButton(int32 which, const char* label)
2244{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002245 BMessage *message = new BMessage(kVimDialogButtonMsg);
2246 message->AddInt32("which", which);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002247
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002248 BRect rect(0, 0, 0, 0);
2249 BString name;
2250 name << "_b" << which << "_";
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002251
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002252 BButton* button = new BButton(rect, name.String(), label, message,
2253 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002254
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002255 float width = 0.f, height = 0.f;
2256 button->GetPreferredSize(&width, &height);
2257 button->ResizeTo(width, height);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002258
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002259 return button;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002260}
2261
2262VimDialog::View::View(BRect frame)
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002263 : BView(frame, "VimDialogView", B_FOLLOW_ALL_SIDES, B_WILL_DRAW),
2264 fIconBitmap(NULL)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002265{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002266 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002267}
2268
2269VimDialog::View::~View()
2270{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002271 delete fIconBitmap;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002272}
2273
2274void VimDialog::View::Draw(BRect updateRect)
2275{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002276 BRect stripeRect = Bounds();
2277 stripeRect.right = kVimDialogIconStripeWidth;
2278 SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT));
2279 FillRect(stripeRect);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002280
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002281 if (fIconBitmap == NULL)
2282 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002283
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002284 SetDrawingMode(B_OP_ALPHA);
2285 SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
2286 DrawBitmapAsync(fIconBitmap, BPoint(18, 6));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002287}
2288
2289void VimDialog::View::InitIcon(int32 type)
2290{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002291 if (type == VIM_GENERIC)
2292 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002293
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002294 BPath path;
2295 status_t status = find_directory(B_BEOS_SERVERS_DIRECTORY, &path);
2296 if (status != B_OK) {
2297 fprintf(stderr, "Cannot retrieve app info:%s\n", strerror(status));
2298 return;
2299 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002300
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002301 path.Append("app_server");
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002302
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002303 BFile file(path.Path(), O_RDONLY);
2304 if (file.InitCheck() != B_OK) {
2305 fprintf(stderr, "App file assignment failed:%s\n",
2306 strerror(file.InitCheck()));
2307 return;
2308 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002309
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002310 BResources resources(&file);
2311 if (resources.InitCheck() != B_OK) {
2312 fprintf(stderr, "App server resources assignment failed:%s\n",
2313 strerror(resources.InitCheck()));
2314 return;
2315 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002316
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002317 const char *name = "";
2318 switch(type) {
2319 case VIM_ERROR: name = "stop"; break;
2320 case VIM_WARNING: name = "warn"; break;
2321 case VIM_INFO: name = "info"; break;
2322 case VIM_QUESTION: name = "idea"; break;
2323 default: return;
2324 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002325
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002326 int32 iconSize = 32;
2327 fIconBitmap = new BBitmap(BRect(0, 0, iconSize - 1, iconSize - 1), 0, B_RGBA32);
2328 if (fIconBitmap == NULL || fIconBitmap->InitCheck() != B_OK) {
2329 fprintf(stderr, "Icon bitmap allocation failed:%s\n",
2330 (fIconBitmap == NULL) ? "null" : strerror(fIconBitmap->InitCheck()));
2331 return;
2332 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002333
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002334 size_t size = 0;
2335 const uint8* iconData = NULL;
2336 // try vector icon first?
2337 iconData = (const uint8*)resources.LoadResource(B_VECTOR_ICON_TYPE, name, &size);
2338 if (iconData != NULL && BIconUtils::GetVectorIcon(iconData, size, fIconBitmap) == B_OK)
2339 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002340
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002341 // try bitmap icon now
2342 iconData = (const uint8*)resources.LoadResource(B_LARGE_ICON_TYPE, name, &size);
2343 if (iconData == NULL) {
2344 fprintf(stderr, "Bitmap icon resource not found\n");
2345 delete fIconBitmap;
2346 fIconBitmap = NULL;
2347 return;
2348 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002349
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002350 if (fIconBitmap->ColorSpace() != B_CMAP8)
2351 BIconUtils::ConvertFromCMAP8(iconData, iconSize, iconSize, iconSize, fIconBitmap);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002352}
2353
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002354const unsigned int kVimDialogOKButtonMsg = 'FDOK';
2355const unsigned int kVimDialogCancelButtonMsg = 'FDCN';
2356const unsigned int kVimDialogSizeInputMsg = 'SICH';
2357const unsigned int kVimDialogFamilySelectMsg = 'MSFM';
2358const unsigned int kVimDialogStyleSelectMsg = 'MSST';
2359const unsigned int kVimDialogSizeSelectMsg = 'MSSZ';
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002360
2361VimSelectFontDialog::VimSelectFontDialog(font_family* family, font_style* style, float* size)
2362: BWindow(kDefaultRect, "Font Selection", B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL,
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002363 B_NOT_CLOSABLE | B_NOT_RESIZABLE |
2364 B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_ASYNCHRONOUS_CONTROLS)
2365 , fStatus(B_NO_INIT)
2366 , fDialogSem(-1)
2367 , fDialogValue(false)
2368 , fFamily(family)
2369 , fStyle(style)
2370 , fSize(size)
2371 , fFontSize(*size)
2372 , fPreview(0)
2373 , fFamiliesList(0)
2374 , fStylesList(0)
2375 , fSizesList(0)
2376 , fSizesInput(0)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002377{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002378 strncpy(fFontFamily, *family, B_FONT_FAMILY_LENGTH);
2379 strncpy(fFontStyle, *style, B_FONT_STYLE_LENGTH);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002380
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002381 // "client" area view
2382 BBox *clientBox = new BBox(Bounds(), B_EMPTY_STRING, B_FOLLOW_ALL_SIDES,
2383 B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP | B_PULSE_NEEDED,
2384 B_PLAIN_BORDER);
2385 AddChild(clientBox);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002386
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002387 // client view
2388 BRect RC = clientBox->Bounds();
2389 RC.InsetBy(kVimDialogSpacingX, kVimDialogSpacingY);
2390 BRect rc(RC.LeftTop(), RC.LeftTop());
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002391
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002392 // at first create all controls
2393 fPreview = new BStringView(rc, "preview", "DejaVu Sans Mono");
2394 clientBox->AddChild(fPreview);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002395
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002396 BBox* boxDivider = new BBox(rc, B_EMPTY_STRING,
2397 B_FOLLOW_NONE, B_WILL_DRAW, B_FANCY_BORDER);
2398 clientBox->AddChild(boxDivider);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002399
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002400 BStringView *labelFamily = new BStringView(rc, "labelFamily", "Family:");
2401 clientBox->AddChild(labelFamily);
2402 labelFamily->ResizeToPreferred();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002403
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002404 BStringView *labelStyle = new BStringView(rc, "labelStyle", "Style:");
2405 clientBox->AddChild(labelStyle);
2406 labelStyle->ResizeToPreferred();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002407
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002408 BStringView *labelSize = new BStringView(rc, "labelSize", "Size:");
2409 clientBox->AddChild(labelSize);
2410 labelSize->ResizeToPreferred();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002411
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002412 fFamiliesList = new BListView(rc, "listFamily",
2413 B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES);
2414 BScrollView *scrollFamilies = new BScrollView("scrollFamily",
2415 fFamiliesList, B_FOLLOW_LEFT_RIGHT, 0, false, true);
2416 clientBox->AddChild(scrollFamilies);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002417
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002418 fStylesList= new BListView(rc, "listStyles",
2419 B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES);
2420 BScrollView *scrollStyles = new BScrollView("scrollStyle",
2421 fStylesList, B_FOLLOW_LEFT_RIGHT, 0, false, true);
2422 clientBox->AddChild(scrollStyles);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002423
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002424 fSizesInput = new BTextControl(rc, "inputSize", NULL, "???",
2425 new BMessage(kVimDialogSizeInputMsg));
2426 clientBox->AddChild(fSizesInput);
2427 fSizesInput->ResizeToPreferred();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002428
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002429 fSizesList = new BListView(rc, "listSizes",
2430 B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES);
2431 BScrollView *scrollSizes = new BScrollView("scrollSize",
2432 fSizesList, B_FOLLOW_LEFT_RIGHT, 0, false, true);
2433 clientBox->AddChild(scrollSizes);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002434
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002435 BButton *buttonOK = new BButton(rc, "buttonOK", "OK",
2436 new BMessage(kVimDialogOKButtonMsg));
2437 clientBox->AddChild(buttonOK);
2438 buttonOK->ResizeToPreferred();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002439
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002440 BButton *buttonCancel = new BButton(rc, "buttonCancel", "Cancel",
2441 new BMessage(kVimDialogCancelButtonMsg));
2442 clientBox->AddChild(buttonCancel);
2443 buttonCancel->ResizeToPreferred();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002444
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002445 // layout controls
2446 float lineHeight = labelFamily->Bounds().Height();
2447 float previewHeight = lineHeight * 3;
2448 float offsetYLabels = previewHeight + kVimDialogSpacingY;
2449 float offsetYLists = offsetYLabels + lineHeight + kVimDialogSpacingY / 2;
2450 float offsetYSizes = offsetYLists + fSizesInput->Bounds().Height() + kVimDialogSpacingY / 2;
2451 float listsHeight = lineHeight * 9;
2452 float offsetYButtons = offsetYLists + listsHeight + kVimDialogSpacingY;
2453 float maxControlsHeight = offsetYButtons + buttonOK->Bounds().Height();
2454 float familiesWidth = labelFamily->Bounds().Width() * 5;
2455 float offsetXStyles = familiesWidth + kVimDialogSpacingX;
2456 float stylesWidth = labelStyle->Bounds().Width() * 4;
2457 float offsetXSizes = offsetXStyles + stylesWidth + kVimDialogSpacingX;
2458 float sizesWidth = labelSize->Bounds().Width() * 2;
2459 float maxControlsWidth = offsetXSizes + sizesWidth;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002460
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002461 ResizeTo(maxControlsWidth + kVimDialogSpacingX * 2,
2462 maxControlsHeight + kVimDialogSpacingY * 2);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002463
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002464 BRect rcVim = gui.vimWindow->Frame();
2465 MoveTo(rcVim.left + (rcVim.Width() - Frame().Width()) / 2,
2466 rcVim.top + (rcVim.Height() - Frame().Height()) / 2);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002467
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002468 fPreview->ResizeTo(maxControlsWidth, previewHeight);
2469 fPreview->SetAlignment(B_ALIGN_CENTER);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002470
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002471 boxDivider->MoveBy(0.f, previewHeight + kVimDialogSpacingY / 2);
2472 boxDivider->ResizeTo(maxControlsWidth, 1.f);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002473
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002474 labelFamily->MoveBy(0.f, offsetYLabels);
2475 labelStyle->MoveBy(offsetXStyles, offsetYLabels);
2476 labelSize->MoveBy(offsetXSizes, offsetYLabels);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002477
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002478 // text control alignment issues
2479 float insetX = fSizesInput->TextView()->Bounds().Width() - fSizesInput->Bounds().Width();
2480 float insetY = fSizesInput->TextView()->Bounds().Width() - fSizesInput->Bounds().Width();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002481
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002482 scrollFamilies->MoveBy(0.f, offsetYLists);
2483 scrollStyles->MoveBy(offsetXStyles, offsetYLists);
2484 fSizesInput->MoveBy(offsetXSizes + insetX / 2, offsetYLists + insetY / 2);
2485 scrollSizes->MoveBy(offsetXSizes, offsetYSizes);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002486
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002487 fSizesInput->SetAlignment(B_ALIGN_CENTER, B_ALIGN_CENTER);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002488
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002489 scrollFamilies->ResizeTo(familiesWidth, listsHeight);
2490 scrollStyles->ResizeTo(stylesWidth, listsHeight);
2491 fSizesInput->ResizeTo(sizesWidth, fSizesInput->Bounds().Height());
2492 scrollSizes->ResizeTo(sizesWidth,
2493 listsHeight - (offsetYSizes - offsetYLists));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002494
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002495 buttonOK->MoveBy(maxControlsWidth - buttonOK->Bounds().Width(), offsetYButtons);
2496 buttonCancel->MoveBy(maxControlsWidth - buttonOK->Bounds().Width()
2497 - buttonCancel->Bounds().Width() - kVimDialogSpacingX, offsetYButtons);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002498
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002499 // fill lists
2500 int selIndex = -1;
2501 int count = count_font_families();
2502 for (int i = 0; i < count; i++) {
2503 font_family family;
2504 if (get_font_family(i, &family ) == B_OK) {
2505 fFamiliesList->AddItem(new BStringItem((const char*)family));
2506 if (strncmp(family, fFontFamily, B_FONT_FAMILY_LENGTH) == 0)
2507 selIndex = i;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002508 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002509 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002510
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002511 if (selIndex >= 0) {
2512 fFamiliesList->Select(selIndex);
2513 fFamiliesList->ScrollToSelection();
2514 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002515
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002516 _UpdateFontStyles();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002517
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002518 selIndex = -1;
2519 for (int size = 8, index = 0; size <= 18; size++, index++) {
2520 BString str;
2521 str << size;
2522 fSizesList->AddItem(new BStringItem(str));
2523 if (size == fFontSize)
2524 selIndex = index;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002525
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002526 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002527
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002528 if (selIndex >= 0) {
2529 fSizesList->Select(selIndex);
2530 fSizesList->ScrollToSelection();
2531 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002532
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002533 fFamiliesList->SetSelectionMessage(new BMessage(kVimDialogFamilySelectMsg));
2534 fStylesList->SetSelectionMessage(new BMessage(kVimDialogStyleSelectMsg));
2535 fSizesList->SetSelectionMessage(new BMessage(kVimDialogSizeSelectMsg));
2536 fSizesInput->SetModificationMessage(new BMessage(kVimDialogSizeInputMsg));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002537
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002538 _UpdateSizeInputPreview();
2539 _UpdateFontPreview();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002540
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002541 fStatus = B_OK;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002542}
2543
2544VimSelectFontDialog::~VimSelectFontDialog()
2545{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002546 _CleanList(fFamiliesList);
2547 _CleanList(fStylesList);
2548 _CleanList(fSizesList);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002549
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002550 if (fDialogSem > B_OK)
2551 delete_sem(fDialogSem);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002552}
2553
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002554 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002555VimSelectFontDialog::_CleanList(BListView* list)
2556{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002557 while (0 < list->CountItems())
2558 delete (dynamic_cast<BStringItem*>(list->RemoveItem((int32)0)));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002559}
2560
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002561 bool
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002562VimSelectFontDialog::Go()
2563{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002564 if (fStatus != B_OK) {
2565 Quit();
2566 return NOFONT;
2567 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002568
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002569 fDialogSem = create_sem(0, "VimFontSelectDialogSem");
2570 if (fDialogSem < B_OK) {
2571 Quit();
2572 return fDialogValue;
2573 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002574
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002575 Show();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002576
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002577 while (acquire_sem(fDialogSem) == B_INTERRUPTED);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002578
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002579 bool retValue = fDialogValue;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002580
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002581 if (Lock())
2582 Quit();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002583
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002584 return retValue;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002585}
2586
2587
2588void VimSelectFontDialog::_UpdateFontStyles()
2589{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002590 _CleanList(fStylesList);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002591
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002592 int32 selIndex = -1;
2593 int32 count = count_font_styles(fFontFamily);
2594 for (int32 i = 0; i < count; i++) {
2595 font_style style;
2596 uint32 flags = 0;
2597 if (get_font_style(fFontFamily, i, &style, &flags) == B_OK) {
2598 fStylesList->AddItem(new BStringItem((const char*)style));
2599 if (strncmp(style, fFontStyle, B_FONT_STYLE_LENGTH) == 0)
2600 selIndex = i;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002601 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002602 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002603
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002604 if (selIndex >= 0) {
2605 fStylesList->Select(selIndex);
2606 fStylesList->ScrollToSelection();
2607 } else
2608 fStylesList->Select(0);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002609}
2610
2611
2612void VimSelectFontDialog::_UpdateSizeInputPreview()
2613{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002614 char buf[10] = {0};
2615 vim_snprintf(buf, sizeof(buf), (char*)"%.0f", fFontSize);
2616 fSizesInput->SetText(buf);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002617}
2618
2619
2620void VimSelectFontDialog::_UpdateFontPreview()
2621{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002622 BFont font;
2623 fPreview->GetFont(&font);
2624 font.SetSize(fFontSize);
2625 font.SetFamilyAndStyle(fFontFamily, fFontStyle);
2626 fPreview->SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002627
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002628 BString str;
2629 str << fFontFamily << " " << fFontStyle << ", " << (int)fFontSize << " pt.";
2630 fPreview->SetText(str);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002631}
2632
2633
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002634 bool
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002635VimSelectFontDialog::_UpdateFromListItem(BListView* list, char* text, int textSize)
2636{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002637 int32 index = list->CurrentSelection();
2638 if (index < 0)
2639 return false;
2640 BStringItem* item = (BStringItem*)list->ItemAt(index);
2641 if (item == NULL)
2642 return false;
2643 strncpy(text, item->Text(), textSize);
2644 return true;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002645}
2646
2647
2648void VimSelectFontDialog::MessageReceived(BMessage *msg)
2649{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002650 switch (msg->what) {
2651 case kVimDialogOKButtonMsg:
2652 strncpy(*fFamily, fFontFamily, B_FONT_FAMILY_LENGTH);
2653 strncpy(*fStyle, fFontStyle, B_FONT_STYLE_LENGTH);
2654 *fSize = fFontSize;
2655 fDialogValue = true;
2656 case kVimDialogCancelButtonMsg:
2657 delete_sem(fDialogSem);
2658 fDialogSem = -1;
2659 return;
2660 case B_KEY_UP:
2661 {
2662 int32 key = 0;
2663 if (msg->FindInt32("raw_char", &key) == B_OK
2664 && key == B_ESCAPE) {
2665 delete_sem(fDialogSem);
2666 fDialogSem = -1;
2667 }
2668 }
2669 break;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002670
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002671 case kVimDialogFamilySelectMsg:
2672 if (_UpdateFromListItem(fFamiliesList,
2673 fFontFamily, B_FONT_FAMILY_LENGTH)) {
2674 _UpdateFontStyles();
2675 _UpdateFontPreview();
2676 }
2677 break;
2678 case kVimDialogStyleSelectMsg:
2679 if (_UpdateFromListItem(fStylesList,
2680 fFontStyle, B_FONT_STYLE_LENGTH))
2681 _UpdateFontPreview();
2682 break;
2683 case kVimDialogSizeSelectMsg:
2684 {
2685 char buf[10] = {0};
2686 if (_UpdateFromListItem(fSizesList, buf, sizeof(buf))) {
2687 float size = atof(buf);
2688 if (size > 0.f) {
2689 fFontSize = size;
2690 _UpdateSizeInputPreview();
2691 _UpdateFontPreview();
2692 }
2693 }
2694 }
2695 break;
2696 case kVimDialogSizeInputMsg:
2697 {
2698 float size = atof(fSizesInput->Text());
2699 if (size > 0.f) {
2700 fFontSize = size;
2701 _UpdateFontPreview();
2702 }
2703 }
2704 break;
2705 default:
2706 break;
2707 }
2708 return BWindow::MessageReceived(msg);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002709}
2710
2711#endif // FEAT_GUI_DIALOG
2712
2713#ifdef FEAT_TOOLBAR
2714
2715// some forward declaration required by toolbar functions...
2716static BMessage * MenuMessage(vimmenu_T *menu);
2717
2718VimToolbar::VimToolbar(BRect frame, const char *name) :
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002719 BBox(frame, name, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_FRAME_EVENTS, B_PLAIN_BORDER)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002720{
2721}
2722
2723VimToolbar::~VimToolbar()
2724{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002725 int32 count = fButtonsList.CountItems();
2726 for (int32 i = 0; i < count; i++)
2727 delete (BPictureButton*)fButtonsList.ItemAt(i);
2728 fButtonsList.MakeEmpty();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002729
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002730 delete normalButtonsBitmap;
2731 delete grayedButtonsBitmap;
2732 normalButtonsBitmap = NULL;
2733 grayedButtonsBitmap = NULL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002734}
2735
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002736 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002737VimToolbar::AttachedToWindow()
2738{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002739 BBox::AttachedToWindow();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002740
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002741 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002742}
2743
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002744 float
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002745VimToolbar::ToolbarHeight() const
2746{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002747 float size = NULL == normalButtonsBitmap ? 18. : normalButtonsBitmap->Bounds().Height();
2748 return size + ToolbarMargin * 2 + ButtonMargin * 2 + 1;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002749}
2750
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002751 bool
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002752VimToolbar::ModifyBitmapToGrayed(BBitmap *bitmap)
2753{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002754 float height = bitmap->Bounds().Height();
2755 float width = bitmap->Bounds().Width();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002756
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002757 rgb_color *bits = (rgb_color*)bitmap->Bits();
2758 int32 pixels = bitmap->BitsLength() / 4;
2759 for (int32 i = 0; i < pixels; i++) {
2760 bits[i].red = bits[i].green =
2761 bits[i].blue = ((uint32)bits[i].red + bits[i].green + bits[i].blue) / 3;
2762 bits[i].alpha /= 4;
2763 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002764
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002765 return true;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002766}
2767
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002768 bool
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002769VimToolbar::PrepareButtonBitmaps()
2770{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002771 // first try to load potentially customized $VIRUNTIME/bitmaps/builtin-tools.png
2772 normalButtonsBitmap = LoadVimBitmap("builtin-tools.png");
2773 if (normalButtonsBitmap == NULL)
2774 // customized not found? dig application resources for "builtin-tools" one
2775 normalButtonsBitmap = BTranslationUtils::GetBitmap(B_PNG_FORMAT, "builtin-tools");
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002776
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002777 if (normalButtonsBitmap == NULL)
2778 return false;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002779
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002780 BMessage archive;
2781 normalButtonsBitmap->Archive(&archive);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002782
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002783 grayedButtonsBitmap = new BBitmap(&archive);
2784 if (grayedButtonsBitmap == NULL)
2785 return false;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002786
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002787 // modify grayed bitmap
2788 ModifyBitmapToGrayed(grayedButtonsBitmap);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002789
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002790 return true;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002791}
2792
2793BBitmap *VimToolbar::LoadVimBitmap(const char* fileName)
2794{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002795 BBitmap *bitmap = NULL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002796
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002797 int mustfree = 0;
2798 char_u* runtimePath = vim_getenv((char_u*)"VIMRUNTIME", &mustfree);
2799 if (runtimePath != NULL && fileName != NULL) {
2800 BString strPath((char*)runtimePath);
2801 strPath << "/bitmaps/" << fileName;
2802 bitmap = BTranslationUtils::GetBitmap(strPath.String());
2803 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002804
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002805 if (mustfree)
2806 vim_free(runtimePath);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002807
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002808 return bitmap;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002809}
2810
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002811 bool
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002812VimToolbar::GetPictureFromBitmap(BPicture *pictureTo, int32 index, BBitmap *bitmapFrom, bool pressed)
2813{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002814 float size = bitmapFrom->Bounds().Height() + 1.;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002815
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002816 BView view(BRect(0, 0, size, size), "", 0, 0);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002817
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002818 AddChild(&view);
2819 view.BeginPicture(pictureTo);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002820
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002821 view.SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
2822 view.FillRect(view.Bounds());
2823 view.SetDrawingMode(B_OP_OVER);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002824
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002825 BRect source(0, 0, size - 1, size - 1);
2826 BRect destination(source);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002827
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002828 source.OffsetBy(size * index, 0);
2829 destination.OffsetBy(ButtonMargin, ButtonMargin);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002830
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002831 view.DrawBitmap(bitmapFrom, source, destination);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002832
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002833 if (pressed) {
2834 rgb_color shineColor = ui_color(B_SHINE_COLOR);
2835 rgb_color shadowColor = ui_color(B_SHADOW_COLOR);
2836 size += ButtonMargin * 2 - 1;
2837 view.BeginLineArray(4);
2838 view.AddLine(BPoint(0, 0), BPoint(size, 0), shadowColor);
2839 view.AddLine(BPoint(size, 0), BPoint(size, size), shineColor);
2840 view.AddLine(BPoint(size, size), BPoint(0, size), shineColor);
2841 view.AddLine(BPoint(0, size), BPoint(0, 0), shadowColor);
2842 view.EndLineArray();
2843 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002844
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002845 view.EndPicture();
2846 RemoveChild(&view);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002847
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002848 return true;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002849}
2850
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002851 bool
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002852VimToolbar::AddButton(int32 index, vimmenu_T *menu)
2853{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002854 BPictureButton *button = NULL;
2855 if (!menu_is_separator(menu->name)) {
2856 float size = normalButtonsBitmap ?
2857 normalButtonsBitmap->Bounds().Height() + 1. + ButtonMargin * 2 : 18.;
2858 BRect frame(0, 0, size, size);
2859 BPicture pictureOn;
2860 BPicture pictureOff;
2861 BPicture pictureGray;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002862
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002863 if (menu->iconfile == NULL && menu->iconidx >= 0 && normalButtonsBitmap) {
2864 GetPictureFromBitmap(&pictureOn, menu->iconidx, normalButtonsBitmap, true);
2865 GetPictureFromBitmap(&pictureOff, menu->iconidx, normalButtonsBitmap, false);
2866 GetPictureFromBitmap(&pictureGray, menu->iconidx, grayedButtonsBitmap, false);
2867 } else {
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002868
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002869 char_u buffer[MAXPATHL] = {0};
2870 BBitmap *bitmap = NULL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002871
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002872 if (menu->iconfile) {
2873 gui_find_iconfile(menu->iconfile, buffer, (char*)"png");
2874 bitmap = BTranslationUtils::GetBitmap((char*)buffer);
2875 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002876
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002877 if (bitmap == NULL && gui_find_bitmap(menu->name, buffer, (char*)"png") == OK)
2878 bitmap = BTranslationUtils::GetBitmap((char*)buffer);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002879
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002880 if (bitmap == NULL)
2881 bitmap = new BBitmap(BRect(0, 0, size, size), B_RGB32);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002882
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002883 GetPictureFromBitmap(&pictureOn, 0, bitmap, true);
2884 GetPictureFromBitmap(&pictureOff, 0, bitmap, false);
2885 ModifyBitmapToGrayed(bitmap);
2886 GetPictureFromBitmap(&pictureGray, 0, bitmap, false);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002887
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002888 delete bitmap;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002889 }
2890
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002891 button = new BPictureButton(frame, (char*)menu->name,
2892 &pictureOff, &pictureOn, MenuMessage(menu));
2893
2894 button->SetDisabledOn(&pictureGray);
2895 button->SetDisabledOff(&pictureGray);
2896
2897 button->SetTarget(gui.vimTextArea);
2898
2899 AddChild(button);
2900
2901 menu->button = button;
2902 }
2903
2904 bool result = fButtonsList.AddItem(button, index);
2905 InvalidateLayout();
2906 return result;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002907}
2908
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002909 bool
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002910VimToolbar::RemoveButton(vimmenu_T *menu)
2911{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002912 if (menu->button) {
2913 if (fButtonsList.RemoveItem(menu->button)) {
2914 delete menu->button;
2915 menu->button = NULL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002916 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002917 }
2918 return true;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002919}
2920
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002921 bool
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002922VimToolbar::GrayButton(vimmenu_T *menu, int grey)
2923{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002924 if (menu->button) {
2925 int32 index = fButtonsList.IndexOf(menu->button);
2926 if (index >= 0)
2927 menu->button->SetEnabled(grey ? false : true);
2928 }
2929 return true;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002930}
2931
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002932 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002933VimToolbar::InvalidateLayout()
2934{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002935 int32 offset = ToolbarMargin;
2936 int32 count = fButtonsList.CountItems();
2937 for (int32 i = 0; i < count; i++) {
2938 BPictureButton *button = (BPictureButton *)fButtonsList.ItemAt(i);
2939 if (button) {
2940 button->MoveTo(offset, ToolbarMargin);
2941 offset += button->Bounds().Width() + ToolbarMargin;
2942 } else
2943 offset += ToolbarMargin * 3;
2944 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002945}
2946
2947#endif /*FEAT_TOOLBAR*/
2948
2949#if defined(FEAT_GUI_TABLINE)
2950
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002951 float
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002952VimTabLine::TablineHeight() const
2953{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002954// float size = NULL == normalButtonsBitmap ? 18. : normalButtonsBitmap->Bounds().Height();
2955// return size + ToolbarMargin * 2 + ButtonMargin * 2 + 1;
2956 return TabHeight(); // + ToolbarMargin;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002957}
2958
2959void
2960VimTabLine::MouseDown(BPoint point)
2961{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002962 if (!gui_mch_showing_tabline())
2963 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002964
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002965 BMessage *m = Window()->CurrentMessage();
2966 assert(m);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002967
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002968 int32 buttons = 0;
2969 m->FindInt32("buttons", &buttons);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002970
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002971 int32 clicks = 0;
2972 m->FindInt32("clicks", &clicks);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002973
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002974 int index = 0; // 0 means here - no tab found
2975 for (int i = 0; i < CountTabs(); i++) {
2976 if (TabFrame(i).Contains(point)) {
2977 index = i + 1; // indexes are 1-based
2978 break;
2979 }
2980 }
2981
2982 int event = -1;
2983
2984 if ((buttons & B_PRIMARY_MOUSE_BUTTON) && clicks > 1)
2985 // left button double click on - create new tab
2986 event = TABLINE_MENU_NEW;
2987
2988 else if (buttons & B_TERTIARY_MOUSE_BUTTON)
2989 // middle button click - close the pointed tab
2990 // or create new one in case empty space
2991 event = index > 0 ? TABLINE_MENU_CLOSE : TABLINE_MENU_NEW;
2992
2993 else if (buttons & B_SECONDARY_MOUSE_BUTTON) {
2994 // right button click - show context menu
2995 BPopUpMenu* popUpMenu = new BPopUpMenu("tabLineContextMenu", false, false);
2996 popUpMenu->AddItem(new BMenuItem(_("Close tabi R"), new BMessage(TABLINE_MENU_CLOSE)));
2997 popUpMenu->AddItem(new BMenuItem(_("New tab T"), new BMessage(TABLINE_MENU_NEW)));
2998 popUpMenu->AddItem(new BMenuItem(_("Open tab..."), new BMessage(TABLINE_MENU_OPEN)));
2999
3000 ConvertToScreen(&point);
3001 BMenuItem* item = popUpMenu->Go(point);
3002 if (item != NULL) {
3003 event = item->Command();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003004 }
3005
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003006 delete popUpMenu;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003007
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003008 } else {
3009 // default processing
3010 BTabView::MouseDown(point);
3011 return;
3012 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003013
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003014 if (event < 0)
3015 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003016
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003017 VimTablineMenuMsg tmm;
3018 tmm.index = index;
3019 tmm.event = event;
3020 write_port(gui.vdcmp, VimMsg::TablineMenu, &tmm, sizeof(tmm));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003021}
3022
3023void
3024VimTabLine::VimTab::Select(BView* owner)
3025{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003026 BTab::Select(owner);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003027
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003028 VimTabLine *tabLine = gui.vimForm->TabLine();
3029 if (tabLine != NULL) {
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003030
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003031 int32 i = 0;
3032 for (; i < tabLine->CountTabs(); i++)
3033 if (this == tabLine->TabAt(i))
3034 break;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003035
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003036// printf("%d:%d:%s\n", i, tabLine->CountTabs(), tabLine->TabAt(i)->Label());
3037 if (i < tabLine->CountTabs()) {
3038 VimTablineMsg tm;
3039 tm.index = i + 1;
3040 write_port(gui.vdcmp, VimMsg::Tabline, &tm, sizeof(tm));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003041 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003042 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003043}
3044
3045#endif // defined(FEAT_GUI_TABLINE)
3046
3047// ---------------- ----------------
3048
3049// some global variables
3050static char appsig[] = "application/x-vnd.Haiku-Vim-8";
3051key_map *keyMap;
3052char *keyMapChars;
3053int main_exitcode = 127;
3054
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003055 status_t
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003056gui_haiku_process_event(bigtime_t timeout)
3057{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003058 struct VimMsg vm;
3059 int32 what;
3060 ssize_t size;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003061
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003062 size = read_port_etc(gui.vdcmp, &what, &vm, sizeof(vm),
3063 B_TIMEOUT, timeout);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003064
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003065 if (size >= 0) {
3066 switch (what) {
3067 case VimMsg::Key:
3068 {
3069 char_u *string = vm.u.Key.chars;
3070 int len = vm.u.Key.length;
3071 if (len == 1 && string[0] == Ctrl_chr('C')) {
3072 trash_input_buf();
3073 got_int = TRUE;
3074 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003075
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003076 if (vm.u.Key.csi_escape)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003077#ifndef FEAT_MBYTE_IME
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003078 {
3079 int i;
3080 char_u buf[2];
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003081
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003082 for (i = 0; i < len; ++i)
3083 {
3084 add_to_input_buf(string + i, 1);
3085 if (string[i] == CSI)
3086 {
3087 // Turn CSI into K_CSI.
3088 buf[0] = KS_EXTRA;
3089 buf[1] = (int)KE_CSI;
3090 add_to_input_buf(buf, 2);
3091 }
3092 }
3093 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003094#else
Bram Moolenaar80a8d382020-05-03 22:57:32 +02003095 add_to_input_buf_csi(string, len);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003096#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003097 else
3098 add_to_input_buf(string, len);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003099 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003100 break;
3101 case VimMsg::Resize:
3102 gui_resize_shell(vm.u.NewSize.width, vm.u.NewSize.height);
3103 break;
3104 case VimMsg::ScrollBar:
3105 {
3106 /*
3107 * If loads of scroll messages queue up, use only the last
3108 * one. Always report when the scrollbar stops dragging.
3109 * This is not perfect yet anyway: these events are queued
3110 * yet again, this time in the keyboard input buffer.
3111 */
3112 int32 oldCount =
3113 atomic_add(&vm.u.Scroll.sb->scrollEventCount, -1);
3114 if (oldCount <= 1 || !vm.u.Scroll.stillDragging)
3115 gui_drag_scrollbar(vm.u.Scroll.sb->getGsb(),
3116 vm.u.Scroll.value, vm.u.Scroll.stillDragging);
3117 }
3118 break;
3119#if defined(FEAT_MENU)
3120 case VimMsg::Menu:
3121 gui_menu_cb(vm.u.Menu.guiMenu);
3122 break;
3123#endif
3124 case VimMsg::Mouse:
3125 {
3126 int32 oldCount;
3127 if (vm.u.Mouse.button == MOUSE_DRAG)
3128 oldCount =
3129 atomic_add(&gui.vimTextArea->mouseDragEventCount, -1);
3130 else
3131 oldCount = 0;
3132 if (oldCount <= 1)
3133 gui_send_mouse_event(vm.u.Mouse.button, vm.u.Mouse.x,
3134 vm.u.Mouse.y, vm.u.Mouse.repeated_click,
3135 vm.u.Mouse.modifiers);
3136 }
3137 break;
3138 case VimMsg::MouseMoved:
3139 {
3140 gui_mouse_moved(vm.u.MouseMoved.x, vm.u.MouseMoved.y);
3141 }
3142 break;
3143 case VimMsg::Focus:
3144 gui.in_focus = vm.u.Focus.active;
3145 // XXX Signal that scrollbar dragging has stopped?
3146 // This is needed because we don't get a MouseUp if
3147 // that happens while outside the window... :-(
3148 if (gui.dragged_sb) {
3149 gui.dragged_sb = SBAR_NONE;
3150 }
3151 // gui_update_cursor(TRUE, FALSE);
3152 break;
3153 case VimMsg::Refs:
3154 ::RefsReceived(vm.u.Refs.message, vm.u.Refs.changedir);
3155 break;
3156 case VimMsg::Tabline:
3157 send_tabline_event(vm.u.Tabline.index);
3158 break;
3159 case VimMsg::TablineMenu:
3160 send_tabline_menu_event(vm.u.TablineMenu.index, vm.u.TablineMenu.event);
3161 break;
3162 default:
3163 // unrecognised message, ignore it
3164 break;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003165 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003166 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003167
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003168 /*
3169 * If size < B_OK, it is an error code.
3170 */
3171 return size;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003172}
3173
3174/*
3175 * Here are some functions to protect access to ScreenLines[] and
3176 * LineOffset[]. These are used from the window thread to respond
3177 * to a Draw() callback. When that occurs, the window is already
3178 * locked by the system.
3179 *
3180 * Other code that needs to lock is any code that changes these
3181 * variables. Other read-only access, or access merely to the
3182 * contents of the screen buffer, need not be locked.
3183 *
3184 * If there is no window, don't call Lock() but do succeed.
3185 */
3186
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003187 int
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003188vim_lock_screen()
3189{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003190 return !gui.vimWindow || gui.vimWindow->Lock();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003191}
3192
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003193 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003194vim_unlock_screen()
3195{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003196 if (gui.vimWindow)
3197 gui.vimWindow->Unlock();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003198}
3199
3200#define RUN_BAPPLICATION_IN_NEW_THREAD 0
3201
3202#if RUN_BAPPLICATION_IN_NEW_THREAD
3203
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003204 int32
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003205run_vimapp(void *args)
3206{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003207 VimApp app(appsig);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003208
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003209 gui.vimApp = &app;
3210 app.Run(); // Run until Quit() called
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003211
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003212 return 0;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003213}
3214
3215#else
3216
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003217 int32
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003218call_main(void *args)
3219{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003220 struct MainArgs *ma = (MainArgs *)args;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003221
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003222 return main(ma->argc, ma->argv);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003223}
3224#endif
3225
3226/*
3227 * Parse the GUI related command-line arguments. Any arguments used are
3228 * deleted from argv, and *argc is decremented accordingly. This is called
3229 * when vim is started, whether or not the GUI has been started.
3230 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003231 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003232gui_mch_prepare(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003233 int *argc,
3234 char **argv)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003235{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003236 /*
3237 * We don't have any command line arguments for the BeOS GUI yet,
3238 * but this is an excellent place to create our Application object.
3239 */
3240 if (!gui.vimApp) {
3241 thread_info tinfo;
3242 get_thread_info(find_thread(NULL), &tinfo);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003243
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003244 // May need the port very early on to process RefsReceived()
3245 gui.vdcmp = create_port(B_MAX_PORT_COUNT, "vim VDCMP");
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003246
3247#if RUN_BAPPLICATION_IN_NEW_THREAD
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003248 thread_id tid = spawn_thread(run_vimapp, "vim VimApp",
3249 tinfo.priority, NULL);
3250 if (tid >= B_OK) {
3251 resume_thread(tid);
3252 } else {
3253 getout(1);
3254 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003255#else
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003256 MainArgs ma = { *argc, argv };
3257 thread_id tid = spawn_thread(call_main, "vim main()",
3258 tinfo.priority, &ma);
3259 if (tid >= B_OK) {
3260 VimApp app(appsig);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003261
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003262 gui.vimApp = &app;
3263 resume_thread(tid);
3264 /*
3265 * This is rather horrible.
3266 * call_main will call main() again...
3267 * There will be no infinite recursion since
3268 * gui.vimApp is set now.
3269 */
3270 app.Run(); // Run until Quit() called
3271 // fprintf(stderr, "app.Run() returned...\n");
3272 status_t dummy_exitcode;
3273 (void)wait_for_thread(tid, &dummy_exitcode);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003274
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003275 /*
3276 * This path should be the normal one taken to exit Vim.
3277 * The main() thread calls mch_exit() which calls
3278 * gui_mch_exit() which terminates its thread.
3279 */
3280 exit(main_exitcode);
3281 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003282#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003283 }
3284 // Don't fork() when starting the GUI. Spawned threads are not
3285 // duplicated with a fork(). The result is a mess.
3286 gui.dofork = FALSE;
3287 /*
3288 * XXX Try to determine whether we were started from
3289 * the Tracker or the terminal.
3290 * It would be nice to have this work, because the Tracker
3291 * follows symlinks, so even if you double-click on gvim,
3292 * when it is a link to vim it will still pass a command name
3293 * of vim...
3294 * We try here to see if stdin comes from /dev/null. If so,
3295 * (or if there is an error, which should never happen) start the GUI.
3296 * This does the wrong thing for vim - </dev/null, and we're
3297 * too early to see the command line parsing. Tough.
3298 * On the other hand, it starts the gui for vim file & which is nice.
3299 */
3300 if (!isatty(0)) {
3301 struct stat stat_stdin, stat_dev_null;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003302
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003303 if (fstat(0, &stat_stdin) == -1 ||
3304 stat("/dev/null", &stat_dev_null) == -1 ||
3305 (stat_stdin.st_dev == stat_dev_null.st_dev &&
3306 stat_stdin.st_ino == stat_dev_null.st_ino))
3307 gui.starting = TRUE;
3308 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003309}
3310
3311/*
3312 * Check if the GUI can be started. Called before gvimrc is sourced.
3313 * Return OK or FAIL.
3314 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003315 int
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003316gui_mch_init_check(void)
3317{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003318 return OK; // TODO: GUI can always be started?
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003319}
3320
3321/*
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003322 * Initialise the GUI. Create all the windows, set up all the call-backs
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003323 * etc.
3324 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003325 int
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003326gui_mch_init()
3327{
3328 display_errors();
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003329 gui.def_norm_pixel = RGB(0x00, 0x00, 0x00); // black
3330 gui.def_back_pixel = RGB(0xFF, 0xFF, 0xFF); // white
3331 gui.norm_pixel = gui.def_norm_pixel;
3332 gui.back_pixel = gui.def_back_pixel;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003333
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003334 gui.scrollbar_width = (int) B_V_SCROLL_BAR_WIDTH;
3335 gui.scrollbar_height = (int) B_H_SCROLL_BAR_HEIGHT;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003336#ifdef FEAT_MENU
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003337 gui.menu_height = 19; // initial guess -
3338 // correct for my default settings
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003339#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003340 gui.border_offset = 3; // coordinates are inside window borders
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003341
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003342 if (gui.vdcmp < B_OK)
3343 return FAIL;
3344 get_key_map(&keyMap, &keyMapChars);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003345
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003346 gui.vimWindow = new VimWindow(); // hidden and locked
3347 if (!gui.vimWindow)
3348 return FAIL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003349
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003350 gui.vimWindow->Run(); // Run() unlocks but does not show
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003351
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003352 // Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3353 // file)
3354 set_normal_colors();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003355
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003356 /*
3357 * Check that none of the colors are the same as the background color
3358 */
3359 gui_check_colors();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003360
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003361 // Get the colors for the highlight groups (gui_check_colors() might have
3362 // changed them)
3363 highlight_gui_started(); // re-init colors and fonts
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003364
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003365 gui_mch_new_colors(); // window must exist for this
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003366
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003367 return OK;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003368}
3369
3370/*
3371 * Called when the foreground or background color has been changed.
3372 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003373 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003374gui_mch_new_colors()
3375{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003376 rgb_color rgb = GUI_TO_RGB(gui.back_pixel);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003377
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003378 if (gui.vimWindow->Lock()) {
3379 gui.vimForm->SetViewColor(rgb);
3380 // Does this not have too much effect for those small rectangles?
3381 gui.vimForm->Invalidate();
3382 gui.vimWindow->Unlock();
3383 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003384}
3385
3386/*
3387 * Open the GUI window which was created by a call to gui_mch_init().
3388 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003389 int
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003390gui_mch_open()
3391{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003392 if (gui_win_x != -1 && gui_win_y != -1)
3393 gui_mch_set_winpos(gui_win_x, gui_win_y);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003394
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003395 // Actually open the window
3396 if (gui.vimWindow->Lock()) {
3397 gui.vimWindow->Show();
3398 gui.vimWindow->Unlock();
3399 return OK;
3400 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003401
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003402 return FAIL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003403}
3404
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003405 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003406gui_mch_exit(int vim_exitcode)
3407{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003408 if (gui.vimWindow) {
3409 thread_id tid = gui.vimWindow->Thread();
3410 gui.vimWindow->Lock();
3411 gui.vimWindow->Quit();
Bram Moolenaar8e7d6222020-12-18 19:49:56 +01003412 // Wait until it is truly gone
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003413 int32 exitcode;
3414 wait_for_thread(tid, &exitcode);
3415 }
3416 delete_port(gui.vdcmp);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003417#if !RUN_BAPPLICATION_IN_NEW_THREAD
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003418 /*
3419 * We are in the main() thread - quit the App thread and
3420 * quit ourselves (passing on the exitcode). Use a global since the
3421 * value from exit_thread() is only used if wait_for_thread() is
3422 * called in time (race condition).
3423 */
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003424#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003425 if (gui.vimApp) {
3426 VimTextAreaView::guiBlankMouse(false);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003427
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003428 main_exitcode = vim_exitcode;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003429#if RUN_BAPPLICATION_IN_NEW_THREAD
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003430 thread_id tid = gui.vimApp->Thread();
3431 int32 exitcode;
3432 gui.vimApp->Lock();
3433 gui.vimApp->Quit();
3434 gui.vimApp->Unlock();
3435 wait_for_thread(tid, &exitcode);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003436#else
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003437 gui.vimApp->Lock();
3438 gui.vimApp->Quit();
3439 gui.vimApp->Unlock();
3440 // suicide
3441 exit_thread(vim_exitcode);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003442#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003443 }
3444 // If we are somehow still here, let mch_exit() handle things.
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003445}
3446
3447/*
3448 * Get the position of the top left corner of the window.
3449 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003450 int
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003451gui_mch_get_winpos(int *x, int *y)
3452{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003453 if (gui.vimWindow->Lock()) {
3454 BRect r;
3455 r = gui.vimWindow->Frame();
3456 gui.vimWindow->Unlock();
3457 *x = (int)r.left;
3458 *y = (int)r.top;
3459 return OK;
3460 }
3461 else
3462 return FAIL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003463}
3464
3465/*
3466 * Set the position of the top left corner of the window to the given
3467 * coordinates.
3468 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003469 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003470gui_mch_set_winpos(int x, int y)
3471{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003472 if (gui.vimWindow->Lock()) {
3473 gui.vimWindow->MoveTo(x, y);
3474 gui.vimWindow->Unlock();
3475 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003476}
3477
3478/*
3479 * Set the size of the window to the given width and height in pixels.
3480 */
3481void
3482gui_mch_set_shellsize(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003483 int width,
3484 int height,
3485 int min_width,
3486 int min_height,
3487 int base_width,
3488 int base_height,
3489 int direction) // TODO: utilize?
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003490{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003491 /*
3492 * We are basically given the size of the VimForm, if I understand
3493 * correctly. Since it fills the window completely, this will also
3494 * be the size of the window.
3495 */
3496 if (gui.vimWindow->Lock()) {
3497 gui.vimWindow->ResizeTo(width - PEN_WIDTH, height - PEN_WIDTH);
3498
3499 // set size limits
3500 float minWidth, maxWidth, minHeight, maxHeight;
3501
3502 gui.vimWindow->GetSizeLimits(&minWidth, &maxWidth,
3503 &minHeight, &maxHeight);
3504 gui.vimWindow->SetSizeLimits(min_width, maxWidth,
3505 min_height, maxHeight);
3506
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003507 /*
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003508 * Set the resizing alignment depending on font size.
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003509 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003510 gui.vimWindow->SetWindowAlignment(
3511 B_PIXEL_ALIGNMENT, // window_alignment mode,
3512 1, // int32 h,
3513 0, // int32 hOffset = 0,
3514 gui.char_width, // int32 width = 0,
3515 base_width, // int32 widthOffset = 0,
3516 1, // int32 v = 0,
3517 0, // int32 vOffset = 0,
3518 gui.char_height, // int32 height = 0,
3519 base_height // int32 heightOffset = 0
3520 );
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003521
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003522 gui.vimWindow->Unlock();
3523 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003524}
3525
3526void
3527gui_mch_get_screen_dimensions(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003528 int *screen_w,
3529 int *screen_h)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003530{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003531 BRect frame;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003532
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003533 {
3534 BScreen screen(gui.vimWindow);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003535
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003536 if (screen.IsValid()) {
3537 frame = screen.Frame();
3538 } else {
3539 frame.right = 640;
3540 frame.bottom = 480;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003541 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003542 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003543
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003544 // XXX approximations...
3545 *screen_w = (int) frame.right - 2 * gui.scrollbar_width - 20;
3546 *screen_h = (int) frame.bottom - gui.scrollbar_height
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003547#ifdef FEAT_MENU
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003548 - gui.menu_height
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003549#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003550 - 30;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003551}
3552
3553void
3554gui_mch_set_text_area_pos(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003555 int x,
3556 int y,
3557 int w,
3558 int h)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003559{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003560 if (!gui.vimTextArea)
3561 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003562
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003563 if (gui.vimWindow->Lock()) {
3564 gui.vimTextArea->MoveTo(x, y);
3565 gui.vimTextArea->ResizeTo(w - PEN_WIDTH, h - PEN_WIDTH);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003566
Bram Moolenaarbeae4082020-04-23 15:41:49 +02003567#ifdef FEAT_GUI_TABLINE
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003568 if (gui.vimForm->TabLine() != NULL) {
3569 gui.vimForm->TabLine()->ResizeTo(w, gui.vimForm->TablineHeight());
3570 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003571#endif // FEAT_GUI_TABLINE
3572
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003573 gui.vimWindow->Unlock();
3574 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003575}
3576
3577
3578/*
3579 * Scrollbar stuff:
3580 */
3581
3582void
3583gui_mch_enable_scrollbar(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003584 scrollbar_T *sb,
3585 int flag)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003586{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003587 VimScrollBar *vsb = sb->id;
3588 if (gui.vimWindow->Lock()) {
3589 /*
3590 * This function is supposed to be idempotent, but Show()/Hide()
3591 * is not. Therefore we test if they are needed.
3592 */
3593 if (flag) {
3594 if (vsb->IsHidden()) {
3595 vsb->Show();
3596 }
3597 } else {
3598 if (!vsb->IsHidden()) {
3599 vsb->Hide();
3600 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003601 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003602 gui.vimWindow->Unlock();
3603 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003604}
3605
3606void
3607gui_mch_set_scrollbar_thumb(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003608 scrollbar_T *sb,
3609 int val,
3610 int size,
3611 int max)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003612{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003613 if (gui.vimWindow->Lock()) {
3614 VimScrollBar *s = sb->id;
3615 if (max == 0) {
3616 s->SetValue(0);
3617 s->SetRange(0.0, 0.0);
3618 } else {
3619 s->SetProportion((float)size / (max + 1.0));
3620 s->SetSteps(1.0, size > 5 ? size - 2 : size);
3621#ifndef SCROLL_PAST_END // really only defined in gui.c...
3622 max = max + 1 - size;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003623#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003624 if (max < s->Value()) {
3625 /*
3626 * If the new maximum is lower than the current value,
3627 * setting it would cause the value to be clipped and
3628 * therefore a ValueChanged() call.
3629 * We avoid this by setting the value first, because
3630 * it presumably is <= max.
3631 */
3632 s->SetValue(val);
3633 s->SetRange(0.0, max);
3634 } else {
3635 /*
3636 * In the other case, set the range first, since the
3637 * new value might be higher than the current max.
3638 */
3639 s->SetRange(0.0, max);
3640 s->SetValue(val);
3641 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003642 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003643 gui.vimWindow->Unlock();
3644 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003645}
3646
3647void
3648gui_mch_set_scrollbar_pos(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003649 scrollbar_T *sb,
3650 int x,
3651 int y,
3652 int w,
3653 int h)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003654{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003655 if (gui.vimWindow->Lock()) {
3656 BRect winb = gui.vimWindow->Bounds();
3657 float vsbx = x, vsby = y;
3658 VimScrollBar *vsb = sb->id;
3659 vsb->ResizeTo(w - PEN_WIDTH, h - PEN_WIDTH);
3660 if (winb.right-(x+w)<w) vsbx = winb.right - (w - PEN_WIDTH);
3661 vsb->MoveTo(vsbx, vsby);
3662 gui.vimWindow->Unlock();
3663 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003664}
3665
Bram Moolenaar203ec772020-07-17 20:43:43 +02003666 int
3667gui_mch_get_scrollbar_xpadding(void)
3668{
3669 // TODO: Calculate the padding for adjust scrollbar position when the
3670 // Window is maximized.
3671 return 0;
3672}
3673
3674 int
3675gui_mch_get_scrollbar_ypadding(void)
3676{
3677 // TODO: Calculate the padding for adjust scrollbar position when the
3678 // Window is maximized.
3679 return 0;
3680}
3681
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003682void
3683gui_mch_create_scrollbar(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003684 scrollbar_T *sb,
3685 int orient) // SBAR_VERT or SBAR_HORIZ
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003686{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003687 orientation posture =
3688 (orient == SBAR_HORIZ) ? B_HORIZONTAL : B_VERTICAL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003689
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003690 VimScrollBar *vsb = sb->id = new VimScrollBar(sb, posture);
3691 if (gui.vimWindow->Lock()) {
3692 vsb->SetTarget(gui.vimTextArea);
3693 vsb->Hide();
3694 gui.vimForm->AddChild(vsb);
3695 gui.vimWindow->Unlock();
3696 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003697}
3698
Bram Moolenaarbeae4082020-04-23 15:41:49 +02003699#if defined(FEAT_WINDOWS) || defined(FEAT_GUI_HAIKU) || defined(PROTO)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003700void
3701gui_mch_destroy_scrollbar(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003702 scrollbar_T *sb)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003703{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003704 if (gui.vimWindow->Lock()) {
3705 sb->id->RemoveSelf();
3706 delete sb->id;
3707 gui.vimWindow->Unlock();
3708 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003709}
3710#endif
3711
3712/*
3713 * Cursor does not flash
3714 */
3715 int
3716gui_mch_is_blink_off(void)
3717{
3718 return FALSE;
3719}
3720
3721/*
3722 * Cursor blink functions.
3723 *
3724 * This is a simple state machine:
3725 * BLINK_NONE not blinking at all
3726 * BLINK_OFF blinking, cursor is not shown
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003727 * BLINK_ON blinking, cursor is shown
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003728 */
3729
3730#define BLINK_NONE 0
3731#define BLINK_OFF 1
3732#define BLINK_ON 2
3733
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003734static int blink_state = BLINK_NONE;
3735static long_u blink_waittime = 700;
3736static long_u blink_ontime = 400;
3737static long_u blink_offtime = 250;
3738static int blink_timer = 0;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003739
3740void
3741gui_mch_set_blinking(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003742 long waittime,
3743 long on,
3744 long off)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003745{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003746 // TODO
3747 blink_waittime = waittime;
3748 blink_ontime = on;
3749 blink_offtime = off;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003750}
3751
3752/*
3753 * Stop the cursor blinking. Show the cursor if it wasn't shown.
3754 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003755 void
Bram Moolenaarbeae4082020-04-23 15:41:49 +02003756gui_mch_stop_blink(int may_call_gui_update_cursor)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003757{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003758 // TODO
3759 if (blink_timer != 0)
3760 {
3761 // XtRemoveTimeOut(blink_timer);
3762 blink_timer = 0;
3763 }
3764 if (blink_state == BLINK_OFF)
3765 gui_update_cursor(TRUE, FALSE);
3766 blink_state = BLINK_NONE;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003767}
3768
3769/*
3770 * Start the cursor blinking. If it was already blinking, this restarts the
3771 * waiting time and shows the cursor.
3772 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003773 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003774gui_mch_start_blink()
3775{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003776 // TODO
3777 if (blink_timer != 0)
3778 ;// XtRemoveTimeOut(blink_timer);
3779 // Only switch blinking on if none of the times is zero
3780 if (blink_waittime && blink_ontime && blink_offtime && gui.in_focus)
3781 {
3782 blink_timer = 1; // XtAppAddTimeOut(app_context, blink_waittime,
3783 blink_state = BLINK_ON;
3784 gui_update_cursor(TRUE, FALSE);
3785 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003786}
3787
3788/*
3789 * Initialise vim to use the font with the given name. Return FAIL if the font
3790 * could not be loaded, OK otherwise.
3791 */
3792int
3793gui_mch_init_font(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003794 char_u *font_name,
3795 int fontset)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003796{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003797 if (gui.vimWindow->Lock())
3798 {
3799 int rc = gui.vimTextArea->mchInitFont(font_name);
3800 gui.vimWindow->Unlock();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003801
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003802 return rc;
3803 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003804
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003805 return FAIL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003806}
3807
3808
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003809 int
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003810gui_mch_adjust_charsize()
3811{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003812 return FAIL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003813}
3814
3815
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003816 int
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003817gui_mch_font_dialog(font_family* family, font_style* style, float* size)
3818{
3819#if defined(FEAT_GUI_DIALOG)
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003820 // gui.vimWindow->Unlock();
3821 VimSelectFontDialog *dialog = new VimSelectFontDialog(family, style, size);
3822 return dialog->Go();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003823#else
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003824 return NOFONT;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003825#endif // FEAT_GUI_DIALOG
3826}
3827
3828
3829GuiFont
3830gui_mch_get_font(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003831 char_u *name,
3832 int giveErrorIfMissing)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003833{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003834 static VimFont *fontList = NULL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003835
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003836 if (!gui.in_use) // can't do this when GUI not running
3837 return NOFONT;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003838
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003839 // storage for locally modified name;
3840 const int buff_size = B_FONT_FAMILY_LENGTH + B_FONT_STYLE_LENGTH + 20;
3841 static char font_name[buff_size] = {0};
3842 font_family family = {0};
3843 font_style style = {0};
3844 float size = 0.f;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003845
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003846 if (name == 0 && be_fixed_font == 0) {
3847 if (giveErrorIfMissing)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00003848 semsg(_(e_unknown_font_str), name);
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003849 return NOFONT;
3850 }
3851
3852 bool useSelectGUI = false;
3853 if (name != NULL)
3854 if (STRCMP(name, "*") == 0) {
3855 useSelectGUI = true;
3856 STRNCPY(font_name, hl_get_font_name(), buff_size);
3857 } else
3858 STRNCPY(font_name, name, buff_size);
3859
3860 if (font_name[0] == 0) {
3861 be_fixed_font->GetFamilyAndStyle(&family, &style);
3862 size = be_fixed_font->Size();
3863 vim_snprintf(font_name, buff_size,
3864 (char*)"%s/%s/%.0f", family, style, size);
3865 }
3866
3867 // replace underscores with spaces
3868 char* end = 0;
3869 while (end = strchr((char *)font_name, '_'))
3870 *end = ' ';
3871
3872 // store the name before strtok corrupt the buffer ;-)
3873 static char buff[buff_size] = {0};
3874 STRNCPY(buff, font_name, buff_size);
3875 STRNCPY(family, strtok(buff, "/\0"), B_FONT_FAMILY_LENGTH);
3876 char* style_s = strtok(0, "/\0");
3877 if (style_s != 0)
3878 STRNCPY(style, style_s, B_FONT_STYLE_LENGTH);
3879 size = atof((style_s != 0) ? strtok(0, "/\0") : "0");
3880
3881 if (useSelectGUI) {
3882 if (gui_mch_font_dialog(&family, &style, &size) == NOFONT)
3883 return FAIL;
3884 // compose for further processing
3885 vim_snprintf(font_name, buff_size,
3886 (char*)"%s/%s/%.0f", family, style, size);
3887 hl_set_font_name((char_u*)font_name);
3888
3889 // Set guifont to the name of the selected font.
3890 char_u* new_p_guifont = (char_u*)alloc(STRLEN(font_name) + 1);
3891 if (new_p_guifont != NULL) {
3892 STRCPY(new_p_guifont, font_name);
3893 vim_free(p_guifont);
3894 p_guifont = new_p_guifont;
3895 // Replace spaces in the font name with underscores.
3896 for ( ; *new_p_guifont; ++new_p_guifont)
3897 if (*new_p_guifont == ' ')
3898 *new_p_guifont = '_';
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003899 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003900 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003901
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003902 VimFont *flp;
3903 for (flp = fontList; flp; flp = flp->next) {
3904 if (STRCMP(font_name, flp->name) == 0) {
3905 flp->refcount++;
3906 return (GuiFont)flp;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003907 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003908 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003909
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003910 VimFont *font = new VimFont();
3911 font->name = vim_strsave((char_u*)font_name);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003912
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003913 if (count_font_styles(family) <= 0) {
3914 if (giveErrorIfMissing)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00003915 semsg(_(e_unknown_font_str), font->name);
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003916 delete font;
3917 return NOFONT;
3918 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003919
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003920 // Remember font in the static list for later use
3921 font->next = fontList;
3922 fontList = font;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003923
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003924 font->SetFamilyAndStyle(family, style);
3925 if (size > 0.f)
3926 font->SetSize(size);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003927
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003928 font->SetSpacing(B_FIXED_SPACING);
3929 font->SetEncoding(B_UNICODE_UTF8);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003930
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003931 return (GuiFont)font;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003932}
3933
3934/*
3935 * Set the current text font.
3936 */
3937void
3938gui_mch_set_font(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003939 GuiFont font)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003940{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003941 if (gui.vimWindow->Lock()) {
3942 VimFont *vf = (VimFont *)font;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003943
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003944 gui.vimTextArea->SetFont(vf);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003945
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003946 gui.char_width = (int) vf->StringWidth("n");
3947 font_height fh;
3948 vf->GetHeight(&fh);
3949 gui.char_height = (int)(fh.ascent + 0.9999)
3950 + (int)(fh.descent + 0.9999) + (int)(fh.leading + 0.9999);
3951 gui.char_ascent = (int)(fh.ascent + 0.9999);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003952
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003953 gui.vimWindow->Unlock();
3954 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003955}
3956
3957// XXX TODO This is apparently never called...
3958void
3959gui_mch_free_font(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003960 GuiFont font)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003961{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003962 if (font == NOFONT)
3963 return;
3964 VimFont *f = (VimFont *)font;
3965 if (--f->refcount <= 0) {
3966 if (f->refcount < 0)
3967 fprintf(stderr, "VimFont: refcount < 0\n");
3968 delete f;
3969 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003970}
3971
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003972 char_u *
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003973gui_mch_get_fontname(GuiFont font, char_u *name)
3974{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003975 if (name == NULL)
3976 return NULL;
3977 return vim_strsave(name);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003978}
3979
3980/*
3981 * Adjust gui.char_height (after 'linespace' was changed).
3982 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003983 int
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003984gui_mch_adjust_charheight()
3985{
3986
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003987 // TODO: linespace support?
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003988
3989// #ifdef FEAT_XFONTSET
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003990// if (gui.fontset != NOFONTSET)
3991// {
3992// gui.char_height = fontset_height((XFontSet)gui.fontset) + p_linespace;
3993// gui.char_ascent = fontset_ascent((XFontSet)gui.fontset)
3994// + p_linespace / 2;
3995// }
3996// else
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003997// #endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003998 {
3999 VimFont *font = (VimFont *)gui.norm_font;
4000 font_height fh = {0};
4001 font->GetHeight(&fh);
4002 gui.char_height = (int)(fh.ascent + fh.descent + 0.5) + p_linespace;
4003 gui.char_ascent = (int)(fh.ascent + 0.5) + p_linespace / 2;
4004 }
4005 return OK;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004006}
4007
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004008 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004009gui_mch_getmouse(int *x, int *y)
4010{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004011 fprintf(stderr, "gui_mch_getmouse");
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004012
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004013 /*int rootx, rooty, winx, winy;
4014 Window root, child;
4015 unsigned int mask;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004016
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004017 if (gui.wid && XQueryPointer(gui.dpy, gui.wid, &root, &child,
4018 &rootx, &rooty, &winx, &winy, &mask)) {
4019 *x = winx;
4020 *y = winy;
4021 } else*/ {
4022 *x = -1;
4023 *y = -1;
4024 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004025}
4026
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004027 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004028gui_mch_mousehide(int hide)
4029{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004030 fprintf(stderr, "gui_mch_getmouse");
4031 // TODO
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004032}
4033
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004034 static int
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004035hex_digit(int c)
4036{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004037 if (isdigit(c))
4038 return c - '0';
4039 c = TOLOWER_ASC(c);
4040 if (c >= 'a' && c <= 'f')
4041 return c - 'a' + 10;
4042 return -1000;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004043}
4044
4045/*
4046 * This function has been lifted from gui_w32.c and extended a bit.
4047 *
4048 * Return the Pixel value (color) for the given color name.
4049 * Return INVALCOLOR for error.
4050 */
4051guicolor_T
4052gui_mch_get_color(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004053 char_u *name)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004054{
Drew Vogele30d1022021-10-24 20:35:07 +01004055 return gui_get_color_cmn(name);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004056}
4057
4058/*
4059 * Set the current text foreground color.
4060 */
4061void
4062gui_mch_set_fg_color(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004063 guicolor_T color)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004064{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004065 rgb_color rgb = GUI_TO_RGB(color);
4066 if (gui.vimWindow->Lock()) {
4067 gui.vimTextArea->SetHighColor(rgb);
4068 gui.vimWindow->Unlock();
4069 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004070}
4071
4072/*
4073 * Set the current text background color.
4074 */
4075void
4076gui_mch_set_bg_color(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004077 guicolor_T color)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004078{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004079 rgb_color rgb = GUI_TO_RGB(color);
4080 if (gui.vimWindow->Lock()) {
4081 gui.vimTextArea->SetLowColor(rgb);
4082 gui.vimWindow->Unlock();
4083 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004084}
4085
4086/*
4087 * Set the current text special color.
4088 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004089 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004090gui_mch_set_sp_color(guicolor_T color)
4091{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004092 // prev_sp_color = color;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004093}
4094
4095void
4096gui_mch_draw_string(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004097 int row,
4098 int col,
4099 char_u *s,
4100 int len,
4101 int flags)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004102{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004103 if (gui.vimWindow->Lock()) {
4104 gui.vimTextArea->mchDrawString(row, col, s, len, flags);
4105 gui.vimWindow->Unlock();
4106 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004107}
4108
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004109 guicolor_T
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004110gui_mch_get_rgb_color(int r, int g, int b)
4111{
4112 return gui_get_rgb_color_cmn(r, g, b);
4113}
4114
4115
4116// Return OK if the key with the termcap name "name" is supported.
4117int
4118gui_mch_haskey(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004119 char_u *name)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004120{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004121 int i;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004122
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004123 for (i = 0; special_keys[i].BeKeys != 0; i++)
4124 if (name[0] == special_keys[i].vim_code0 &&
4125 name[1] == special_keys[i].vim_code1)
4126 return OK;
4127 return FAIL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004128}
4129
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004130 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004131gui_mch_beep()
4132{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004133 ::beep();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004134}
4135
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004136 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004137gui_mch_flash(int msec)
4138{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004139 // Do a visual beep by reversing the foreground and background colors
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004140
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004141 if (gui.vimWindow->Lock()) {
4142 BRect rect = gui.vimTextArea->Bounds();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004143
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004144 gui.vimTextArea->SetDrawingMode(B_OP_INVERT);
4145 gui.vimTextArea->FillRect(rect);
4146 gui.vimTextArea->Sync();
4147 snooze(msec * 1000); // wait for a few msec
4148 gui.vimTextArea->FillRect(rect);
4149 gui.vimTextArea->SetDrawingMode(B_OP_COPY);
4150 gui.vimTextArea->Flush();
4151 gui.vimWindow->Unlock();
4152 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004153}
4154
4155/*
4156 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4157 */
4158void
4159gui_mch_invert_rectangle(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004160 int r,
4161 int c,
4162 int nr,
4163 int nc)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004164{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004165 BRect rect;
4166 rect.left = FILL_X(c);
4167 rect.top = FILL_Y(r);
4168 rect.right = rect.left + nc * gui.char_width - PEN_WIDTH;
4169 rect.bottom = rect.top + nr * gui.char_height - PEN_WIDTH;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004170
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004171 if (gui.vimWindow->Lock()) {
4172 gui.vimTextArea->SetDrawingMode(B_OP_INVERT);
4173 gui.vimTextArea->FillRect(rect);
4174 gui.vimTextArea->SetDrawingMode(B_OP_COPY);
4175 gui.vimWindow->Unlock();
4176 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004177}
4178
4179/*
4180 * Iconify the GUI window.
4181 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004182 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004183gui_mch_iconify()
4184{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004185 if (gui.vimWindow->Lock()) {
4186 gui.vimWindow->Minimize(true);
4187 gui.vimWindow->Unlock();
4188 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004189}
4190
4191#if defined(FEAT_EVAL) || defined(PROTO)
4192/*
4193 * Bring the Vim window to the foreground.
4194 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004195 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004196gui_mch_set_foreground(void)
4197{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004198 // TODO
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004199}
4200#endif
4201
4202/*
4203 * Set the window title
4204 */
4205void
4206gui_mch_settitle(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004207 char_u *title,
4208 char_u *icon)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004209{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004210 if (gui.vimWindow->Lock()) {
4211 gui.vimWindow->SetTitle((char *)title);
4212 gui.vimWindow->Unlock();
4213 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004214}
4215
4216/*
4217 * Draw a cursor without focus.
4218 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004219 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004220gui_mch_draw_hollow_cursor(guicolor_T color)
4221{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004222 gui_mch_set_fg_color(color);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004223
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004224 BRect r;
4225 r.left = FILL_X(gui.col);
4226 r.top = FILL_Y(gui.row);
4227 int cells = utf_off2cells(LineOffset[gui.row] + gui.col, 100); // TODO-TODO
4228 if (cells>=4) cells = 1;
4229 r.right = r.left + cells*gui.char_width - PEN_WIDTH;
4230 r.bottom = r.top + gui.char_height - PEN_WIDTH;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004231
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004232 if (gui.vimWindow->Lock()) {
4233 gui.vimTextArea->StrokeRect(r);
4234 gui.vimWindow->Unlock();
4235 // gui_mch_flush();
4236 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004237}
4238
4239/*
4240 * Draw part of a cursor, only w pixels wide, and h pixels high.
4241 */
4242void
4243gui_mch_draw_part_cursor(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004244 int w,
4245 int h,
4246 guicolor_T color)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004247{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004248 gui_mch_set_fg_color(color);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004249
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004250 BRect r;
4251 r.left =
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004252#ifdef FEAT_RIGHTLEFT
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004253 // vertical line should be on the right of current point
4254 CURSOR_BAR_RIGHT ? FILL_X(gui.col + 1) - w :
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004255#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004256 FILL_X(gui.col);
4257 r.right = r.left + w - PEN_WIDTH;
4258 r.bottom = FILL_Y(gui.row + 1) - PEN_WIDTH;
4259 r.top = r.bottom - h + PEN_WIDTH;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004260
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004261 if (gui.vimWindow->Lock()) {
4262 gui.vimTextArea->FillRect(r);
4263 gui.vimWindow->Unlock();
4264 // gui_mch_flush();
4265 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004266}
4267
4268/*
4269 * Catch up with any queued events. This may put keyboard input into the
4270 * input buffer, call resize call-backs, trigger timers etc. If there is
4271 * nothing in the event queue (& no timers pending), then we return
4272 * immediately.
4273 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004274 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004275gui_mch_update()
4276{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004277 gui_mch_flush();
4278 while (port_count(gui.vdcmp) > 0 &&
4279 !vim_is_input_buf_full() &&
4280 gui_haiku_process_event(0) >= B_OK)
4281 /* nothing */ ;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004282}
4283
4284/*
4285 * GUI input routine called by gui_wait_for_chars(). Waits for a character
4286 * from the keyboard.
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004287 * wtime == -1 Wait forever.
4288 * wtime == 0 This should never happen.
4289 * wtime > 0 Wait wtime milliseconds for a character.
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004290 * Returns OK if a character was found to be available within the given time,
4291 * or FAIL otherwise.
4292 */
4293int
4294gui_mch_wait_for_chars(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004295 int wtime)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004296{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004297 int focus;
Bram Moolenaar80a8d382020-05-03 22:57:32 +02004298 bigtime_t until, timeout;
4299 status_t st;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004300
Bram Moolenaar80a8d382020-05-03 22:57:32 +02004301 if (wtime >= 0)
4302 {
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004303 timeout = wtime * 1000;
4304 until = system_time() + timeout;
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004305 }
Bram Moolenaar80a8d382020-05-03 22:57:32 +02004306 else
4307 timeout = B_INFINITE_TIMEOUT;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004308
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004309 focus = gui.in_focus;
4310 for (;;)
4311 {
4312 // Stop or start blinking when focus changes
4313 if (gui.in_focus != focus)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004314 {
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004315 if (gui.in_focus)
4316 gui_mch_start_blink();
4317 else
4318 gui_mch_stop_blink(TRUE);
4319 focus = gui.in_focus;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004320 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004321
4322 gui_mch_flush();
Bram Moolenaar80a8d382020-05-03 22:57:32 +02004323
4324#ifdef MESSAGE_QUEUE
4325# ifdef FEAT_TIMERS
4326 did_add_timer = FALSE;
4327# endif
4328 parse_queued_messages();
4329# ifdef FEAT_TIMERS
4330 if (did_add_timer)
4331 // Need to recompute the waiting time.
4332 break;
4333# endif
4334# ifdef FEAT_JOB_CHANNEL
4335 if (has_any_channel())
4336 {
4337 if (wtime < 0 || timeout > 20000)
4338 timeout = 20000;
4339 }
4340 else if (wtime < 0)
4341 timeout = B_INFINITE_TIMEOUT;
4342# endif
4343#endif
4344
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004345 /*
4346 * Don't use gui_mch_update() because then we will spin-lock until a
4347 * char arrives, instead we use gui_haiku_process_event() to hang until
4348 * an event arrives. No need to check for input_buf_full because we
4349 * are returning as soon as it contains a single char.
4350 */
4351 st = gui_haiku_process_event(timeout);
4352
4353 if (input_available())
4354 return OK;
4355 if (st < B_OK) // includes B_TIMED_OUT
4356 return FAIL;
4357
4358 /*
4359 * Calculate how much longer we're willing to wait for the
4360 * next event.
4361 */
Bram Moolenaar80a8d382020-05-03 22:57:32 +02004362 if (wtime >= 0)
4363 {
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004364 timeout = until - system_time();
4365 if (timeout < 0)
4366 break;
4367 }
4368 }
4369 return FAIL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004370
4371}
4372
4373/*
4374 * Output routines.
4375 */
4376
4377/*
4378 * Flush any output to the screen. This is typically called before
4379 * the app goes to sleep.
4380 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004381 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004382gui_mch_flush()
4383{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004384 // does this need to lock the window? Apparently not but be safe.
4385 if (gui.vimWindow->Lock()) {
4386 gui.vimWindow->Flush();
4387 gui.vimWindow->Unlock();
4388 }
4389 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004390}
4391
4392/*
4393 * Clear a rectangular region of the screen from text pos (row1, col1) to
4394 * (row2, col2) inclusive.
4395 */
4396void
4397gui_mch_clear_block(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004398 int row1,
4399 int col1,
4400 int row2,
4401 int col2)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004402{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004403 if (gui.vimWindow->Lock()) {
4404 gui.vimTextArea->mchClearBlock(row1, col1, row2, col2);
4405 gui.vimWindow->Unlock();
4406 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004407}
4408
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004409 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004410gui_mch_clear_all()
4411{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004412 if (gui.vimWindow->Lock()) {
4413 gui.vimTextArea->mchClearAll();
4414 gui.vimWindow->Unlock();
4415 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004416}
4417
4418/*
4419 * Delete the given number of lines from the given row, scrolling up any
4420 * text further down within the scroll region.
4421 */
4422void
4423gui_mch_delete_lines(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004424 int row,
4425 int num_lines)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004426{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004427 gui.vimTextArea->mchDeleteLines(row, num_lines);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004428}
4429
4430/*
4431 * Insert the given number of lines before the given row, scrolling down any
4432 * following text within the scroll region.
4433 */
4434void
4435gui_mch_insert_lines(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004436 int row,
4437 int num_lines)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004438{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004439 gui.vimTextArea->mchInsertLines(row, num_lines);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004440}
4441
4442#if defined(FEAT_MENU) || defined(PROTO)
4443/*
4444 * Menu stuff.
4445 */
4446
4447void
4448gui_mch_enable_menu(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004449 int flag)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004450{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004451 if (gui.vimWindow->Lock())
4452 {
4453 BMenuBar *menubar = gui.vimForm->MenuBar();
4454 menubar->SetEnabled(flag);
4455 gui.vimWindow->Unlock();
4456 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004457}
4458
4459void
4460gui_mch_set_menu_pos(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004461 int x,
4462 int y,
4463 int w,
4464 int h)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004465{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004466 // It will be in the right place anyway
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004467}
4468
4469/*
4470 * Add a sub menu to the menu bar.
4471 */
4472void
4473gui_mch_add_menu(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004474 vimmenu_T *menu,
4475 int idx)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004476{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004477 vimmenu_T *parent = menu->parent;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004478
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004479 // popup menu - just create it unattached
4480 if (menu_is_popup(menu->name) && parent == NULL) {
4481 BPopUpMenu* popUpMenu = new BPopUpMenu((const char*)menu->name, false, false);
4482 menu->submenu_id = popUpMenu;
4483 menu->id = NULL;
4484 return;
4485 }
4486
4487 if (!menu_is_menubar(menu->name)
4488 || (parent != NULL && parent->submenu_id == NULL))
4489 return;
4490
4491 if (gui.vimWindow->Lock())
4492 {
4493 // Major re-write of the menu code, it was failing with memory corruption when
4494 // we started loading multiple files (the Buffer menu)
4495 //
4496 // Note we don't use the preference values yet, all are inserted into the
4497 // menubar on a first come-first served basis...
4498 //
4499 // richard@whitequeen.com jul 99
4500
4501 BMenu *tmp;
4502
4503 if ( parent )
4504 tmp = parent->submenu_id;
4505 else
4506 tmp = gui.vimForm->MenuBar();
4507 // make sure we don't try and add the same menu twice. The Buffers menu tries to
4508 // do this and Be starts to crash...
4509
4510 if ( ! tmp->FindItem((const char *) menu->dname)) {
4511
4512 BMenu *bmenu = new BMenu((char *)menu->dname);
4513
4514 menu->submenu_id = bmenu;
4515
4516 // when we add a BMenu to another Menu, it creates the interconnecting BMenuItem
4517 tmp->AddItem(bmenu);
4518
Dominique Pelleb49dfd02023-04-14 21:54:25 +01004519 // Now it's safe to query the menu for the associated MenuItem...
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004520 menu->id = tmp->FindItem((const char *) menu->dname);
4521
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004522 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004523 gui.vimWindow->Unlock();
4524 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004525}
4526
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004527 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004528gui_mch_toggle_tearoffs(int enable)
4529{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004530 // no tearoff menus
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004531}
4532
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004533 static BMessage *
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004534MenuMessage(vimmenu_T *menu)
4535{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004536 BMessage *m = new BMessage('menu');
4537 m->AddPointer("VimMenu", (void *)menu);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004538
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004539 return m;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004540}
4541
4542/*
4543 * Add a menu item to a menu
4544 */
4545void
4546gui_mch_add_menu_item(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004547 vimmenu_T *menu,
4548 int idx)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004549{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004550 int mnemonic = 0;
4551 vimmenu_T *parent = menu->parent;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004552
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004553 // TODO: use menu->actext
4554 // This is difficult, since on Be, an accelerator must be a single char
4555 // and a lot of Vim ones are the standard VI commands.
4556 //
4557 // Punt for Now...
4558 // richard@whiequeen.com jul 99
4559 if (gui.vimWindow->Lock())
4560 {
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004561#ifdef FEAT_TOOLBAR
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004562 if (menu_is_toolbar(parent->name)) {
4563 VimToolbar *toolbar = gui.vimForm->ToolBar();
4564 if (toolbar != NULL) {
4565 toolbar->AddButton(idx, menu);
4566 }
4567 } else
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004568#endif
4569
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004570 if (parent->submenu_id != NULL || menu_is_popup(parent->name)) {
4571 if (menu_is_separator(menu->name)) {
4572 BSeparatorItem *item = new BSeparatorItem();
4573 parent->submenu_id->AddItem(item);
4574 menu->id = item;
4575 menu->submenu_id = NULL;
4576 }
4577 else {
4578 BMenuItem *item = new BMenuItem((char *)menu->dname,
4579 MenuMessage(menu));
4580 item->SetTarget(gui.vimTextArea);
4581 item->SetTrigger((char) menu->mnemonic);
4582 parent->submenu_id->AddItem(item);
4583 menu->id = item;
4584 menu->submenu_id = NULL;
4585 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004586 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004587 gui.vimWindow->Unlock();
4588 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004589}
4590
4591/*
4592 * Destroy the machine specific menu widget.
4593 */
4594void
4595gui_mch_destroy_menu(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004596 vimmenu_T *menu)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004597{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004598 if (gui.vimWindow->Lock())
4599 {
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004600#ifdef FEAT_TOOLBAR
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004601 if (menu->parent && menu_is_toolbar(menu->parent->name)) {
4602 VimToolbar *toolbar = gui.vimForm->ToolBar();
4603 if (toolbar != NULL) {
4604 toolbar->RemoveButton(menu);
4605 }
4606 } else
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004607#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004608 {
4609 assert(menu->submenu_id == NULL || menu->submenu_id->CountItems() == 0);
4610 /*
4611 * Detach this menu from its parent, so that it is not deleted
4612 * twice once we get to delete that parent.
4613 * Deleting a BMenuItem also deletes the associated BMenu, if any
4614 * (which does not have any items anymore since they were
4615 * removed and deleted before).
4616 */
4617 BMenu *bmenu = menu->id->Menu();
4618 if (bmenu)
4619 {
4620 bmenu->RemoveItem(menu->id);
4621 /*
4622 * If we removed the last item from the menu bar,
4623 * resize it out of sight.
4624 */
4625 if (bmenu == gui.vimForm->MenuBar() && bmenu->CountItems() == 0)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004626 {
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004627 bmenu->ResizeTo(-MENUBAR_MARGIN, -MENUBAR_MARGIN);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004628 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004629 }
4630 delete menu->id;
4631 menu->id = NULL;
4632 menu->submenu_id = NULL;
4633
4634 gui.menu_height = (int) gui.vimForm->MenuHeight();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004635 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004636 gui.vimWindow->Unlock();
4637 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004638}
4639
4640/*
4641 * Make a menu either grey or not grey.
4642 */
4643void
4644gui_mch_menu_grey(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004645 vimmenu_T *menu,
4646 int grey)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004647{
4648#ifdef FEAT_TOOLBAR
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004649 if (menu->parent && menu_is_toolbar(menu->parent->name)) {
4650 if (gui.vimWindow->Lock()) {
4651 VimToolbar *toolbar = gui.vimForm->ToolBar();
4652 if (toolbar != NULL) {
4653 toolbar->GrayButton(menu, grey);
4654 }
4655 gui.vimWindow->Unlock();
4656 }
4657 } else
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004658#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004659 if (menu->id != NULL)
4660 menu->id->SetEnabled(!grey);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004661}
4662
4663/*
4664 * Make menu item hidden or not hidden
4665 */
4666void
4667gui_mch_menu_hidden(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004668 vimmenu_T *menu,
4669 int hidden)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004670{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004671 if (menu->id != NULL)
4672 menu->id->SetEnabled(!hidden);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004673}
4674
4675/*
4676 * This is called after setting all the menus to grey/hidden or not.
4677 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004678 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004679gui_mch_draw_menubar()
4680{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004681 // Nothing to do in BeOS
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004682}
4683
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004684 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004685gui_mch_show_popupmenu(vimmenu_T *menu)
4686{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004687 if (!menu_is_popup(menu->name) || menu->submenu_id == NULL)
4688 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004689
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004690 BPopUpMenu* popupMenu = dynamic_cast<BPopUpMenu*>(menu->submenu_id);
4691 if (popupMenu == NULL)
4692 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004693
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004694 BPoint point;
4695 if (gui.vimWindow->Lock()) {
4696 uint32 buttons = 0;
4697 gui.vimTextArea->GetMouse(&point, &buttons);
4698 gui.vimTextArea->ConvertToScreen(&point);
4699 gui.vimWindow->Unlock();
4700 }
4701 popupMenu->Go(point, true);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004702}
4703
4704#endif // FEAT_MENU
4705
4706// Mouse stuff
4707
4708#ifdef FEAT_CLIPBOARD
4709/*
4710 * Clipboard stuff, for cutting and pasting text to other windows.
4711 */
4712char textplain[] = "text/plain";
4713char vimselectiontype[] = "application/x-vnd.Rhialto-Vim-selectiontype";
4714
4715/*
4716 * Get the current selection and put it in the clipboard register.
4717 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004718 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004719clip_mch_request_selection(Clipboard_T *cbd)
4720{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004721 if (be_clipboard->Lock())
4722 {
4723 BMessage *m = be_clipboard->Data();
4724 // m->PrintToStream();
4725
4726 char_u *string = NULL;
4727 ssize_t stringlen = -1;
4728
4729 if (m->FindData(textplain, B_MIME_TYPE,
4730 (const void **)&string, &stringlen) == B_OK
4731 || m->FindString("text", (const char **)&string) == B_OK)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004732 {
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004733 if (stringlen == -1)
4734 stringlen = STRLEN(string);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004735
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004736 int type;
4737 char *seltype;
4738 ssize_t seltypelen;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004739
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004740 /*
4741 * Try to get the special vim selection type first
4742 */
4743 if (m->FindData(vimselectiontype, B_MIME_TYPE,
4744 (const void **)&seltype, &seltypelen) == B_OK)
4745 {
4746 switch (*seltype)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004747 {
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004748 default:
4749 case 'L': type = MLINE; break;
4750 case 'C': type = MCHAR; break;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004751#ifdef FEAT_VISUAL
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004752 case 'B': type = MBLOCK; break;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004753#endif
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004754 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004755 }
4756 else
4757 {
4758 // Otherwise use heuristic as documented
4759 type = memchr(string, stringlen, '\n') ? MLINE : MCHAR;
4760 }
4761 clip_yank_selection(type, string, (long)stringlen, cbd);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004762 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004763 be_clipboard->Unlock();
4764 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004765}
4766/*
4767 * Make vim the owner of the current selection.
4768 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004769 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004770clip_mch_lose_selection(Clipboard_T *cbd)
4771{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004772 // Nothing needs to be done here
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004773}
4774
4775/*
4776 * Make vim the owner of the current selection. Return OK upon success.
4777 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004778 int
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004779clip_mch_own_selection(Clipboard_T *cbd)
4780{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004781 /*
4782 * Never actually own the clipboard. If another application sets the
4783 * clipboard, we don't want to think that we still own it.
4784 */
4785 return FAIL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004786}
4787
4788/*
4789 * Send the current selection to the clipboard.
4790 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004791 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004792clip_mch_set_selection(Clipboard_T *cbd)
4793{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004794 if (be_clipboard->Lock())
4795 {
4796 be_clipboard->Clear();
4797 BMessage *m = be_clipboard->Data();
4798 assert(m);
4799
4800 // If the '*' register isn't already filled in, fill it in now
4801 cbd->owned = TRUE;
4802 clip_get_selection(cbd);
4803 cbd->owned = FALSE;
4804
4805 char_u *str = NULL;
4806 long_u count;
4807 int type;
4808
4809 type = clip_convert_selection(&str, &count, cbd);
4810
4811 if (type < 0)
4812 return;
4813
4814 m->AddData(textplain, B_MIME_TYPE, (void *)str, count);
4815
4816 // Add type of selection
4817 char vtype;
4818 switch (type)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004819 {
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004820 default:
4821 case MLINE: vtype = 'L'; break;
4822 case MCHAR: vtype = 'C'; break;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004823#ifdef FEAT_VISUAL
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004824 case MBLOCK: vtype = 'B'; break;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004825#endif
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004826 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004827 m->AddData(vimselectiontype, B_MIME_TYPE, (void *)&vtype, 1);
4828
4829 vim_free(str);
4830
4831 be_clipboard->Commit();
4832 be_clipboard->Unlock();
4833 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004834}
4835
4836#endif // FEAT_CLIPBOARD
4837
4838#ifdef FEAT_BROWSE
4839/*
4840 * Pop open a file browser and return the file selected, in allocated memory,
4841 * or NULL if Cancel is hit.
4842 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
4843 * title - Title message for the file browser dialog.
4844 * dflt - Default name of file.
4845 * ext - Default extension to be added to files without extensions.
4846 * initdir - directory in which to open the browser (NULL = current dir)
4847 * filter - Filter for matched files to choose from.
4848 * Has a format like this:
4849 * "C Files (*.c)\0*.c\0"
4850 * "All Files\0*.*\0\0"
4851 * If these two strings were concatenated, then a choice of two file
4852 * filters will be selectable to the user. Then only matching files will
4853 * be shown in the browser. If NULL, the default allows all files.
4854 *
4855 * *NOTE* - the filter string must be terminated with TWO nulls.
4856 */
4857char_u *
4858gui_mch_browse(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004859 int saving,
4860 char_u *title,
4861 char_u *dflt,
4862 char_u *ext,
4863 char_u *initdir,
4864 char_u *filter)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004865{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004866 gui.vimApp->fFilePanel = new BFilePanel((saving == TRUE) ? B_SAVE_PANEL : B_OPEN_PANEL,
4867 NULL, NULL, 0, false,
4868 new BMessage((saving == TRUE) ? 'save' : 'open'), NULL, true);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004869
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004870 gui.vimApp->fBrowsedPath.Unset();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004871
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004872 gui.vimApp->fFilePanel->Window()->SetTitle((char*)title);
4873 gui.vimApp->fFilePanel->SetPanelDirectory((const char*)initdir);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004874
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004875 gui.vimApp->fFilePanel->Show();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004876
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004877 gui.vimApp->fFilePanelSem = create_sem(0, "FilePanelSem");
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004878
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004879 while (acquire_sem(gui.vimApp->fFilePanelSem) == B_INTERRUPTED);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004880
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004881 char_u *fileName = NULL;
4882 status_t result = gui.vimApp->fBrowsedPath.InitCheck();
4883 if (result == B_OK) {
4884 fileName = vim_strsave((char_u*)gui.vimApp->fBrowsedPath.Path());
4885 } else
4886 if (result != B_NO_INIT) {
4887 fprintf(stderr, "gui_mch_browse: BPath error: %#08x (%s)\n",
4888 result, strerror(result));
4889 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004890
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004891 delete gui.vimApp->fFilePanel;
4892 gui.vimApp->fFilePanel = NULL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004893
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004894 return fileName;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004895}
4896#endif // FEAT_BROWSE
4897
4898
4899#if defined(FEAT_GUI_DIALOG)
4900
4901/*
4902 * Create a dialog dynamically from the parameter strings.
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004903 * type = type of dialog (question, alert, etc.)
4904 * title = dialog title. may be NULL for default title.
4905 * message = text to display. Dialog sizes to accommodate it.
4906 * buttons = '\n' separated list of button captions, default first.
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004907 * dfltbutton = number of default button.
4908 *
4909 * This routine returns 1 if the first button is pressed,
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004910 * 2 for the second, etc.
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004911 *
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004912 * 0 indicates Esc was pressed.
4913 * -1 for unexpected error
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004914 *
4915 * If stubbing out this fn, return 1.
4916 */
4917
4918int
4919gui_mch_dialog(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004920 int type,
4921 char_u *title,
4922 char_u *message,
4923 char_u *buttons,
4924 int dfltbutton,
4925 char_u *textfield,
4926 int ex_cmd)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004927{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004928 VimDialog *dialog = new VimDialog(type, (char*)title, (char*)message,
4929 (char*)buttons, dfltbutton, (char*)textfield, ex_cmd);
4930 return dialog->Go();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004931}
4932
4933#endif // FEAT_GUI_DIALOG
4934
4935
4936/*
4937 * Return the RGB value of a pixel as long.
4938 */
4939 guicolor_T
4940gui_mch_get_rgb(guicolor_T pixel)
4941{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004942 rgb_color rgb = GUI_TO_RGB(pixel);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004943
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004944 return ((rgb.red & 0xff) << 16) + ((rgb.green & 0xff) << 8)
4945 + (rgb.blue & 0xff);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004946}
4947
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004948 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004949gui_mch_setmouse(int x, int y)
4950{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004951 TRACE();
4952 // TODO
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004953}
4954
4955#ifdef FEAT_MBYTE_IME
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004956 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004957im_set_position(int row, int col)
4958{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004959 if (gui.vimWindow->Lock())
4960 {
4961 gui.vimTextArea->DrawIMString();
4962 gui.vimWindow->Unlock();
4963 }
4964 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004965}
4966#endif
4967
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004968 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004969gui_mch_show_toolbar(int showit)
4970{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004971 VimToolbar *toolbar = gui.vimForm->ToolBar();
4972 gui.toolbar_height = (toolbar && showit) ? toolbar->ToolbarHeight() : 0.;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004973}
4974
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004975 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004976gui_mch_set_toolbar_pos(int x, int y, int w, int h)
4977{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004978 VimToolbar *toolbar = gui.vimForm->ToolBar();
4979 if (toolbar != NULL) {
4980 if (gui.vimWindow->Lock()) {
4981 toolbar->MoveTo(x, y);
4982 toolbar->ResizeTo(w - 1, h - 1);
4983 gui.vimWindow->Unlock();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004984 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004985 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004986}
4987
4988#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
4989
4990/*
4991 * Show or hide the tabline.
4992 */
4993 void
4994gui_mch_show_tabline(int showit)
4995{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004996 VimTabLine *tabLine = gui.vimForm->TabLine();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004997
4998 if (tabLine == NULL)
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004999 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005000
5001 if (!showit != !gui.vimForm->IsShowingTabLine()) {
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005002 gui.vimForm->SetShowingTabLine(showit != 0);
5003 gui.tabline_height = gui.vimForm->TablineHeight();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005004 }
5005}
5006
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005007 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005008gui_mch_set_tabline_pos(int x, int y, int w, int h)
5009{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005010 VimTabLine *tabLine = gui.vimForm->TabLine();
5011 if (tabLine != NULL) {
5012 if (gui.vimWindow->Lock()) {
5013 tabLine->MoveTo(x, y);
5014 tabLine->ResizeTo(w - 1, h - 1);
5015 gui.vimWindow->Unlock();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005016 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005017 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005018}
5019
5020/*
5021 * Return TRUE when tabline is displayed.
5022 */
5023 int
5024gui_mch_showing_tabline()
5025{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005026 VimTabLine *tabLine = gui.vimForm->TabLine();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005027 return tabLine != NULL && gui.vimForm->IsShowingTabLine();
5028}
5029
5030/*
5031 * Update the labels of the tabline.
5032 */
5033 void
5034gui_mch_update_tabline()
5035{
5036 tabpage_T *tp;
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005037 int nr = 0;
5038 int curtabidx = 0;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005039
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005040 VimTabLine *tabLine = gui.vimForm->TabLine();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005041
5042 if (tabLine == NULL)
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005043 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005044
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005045 gui.vimWindow->Lock();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005046
5047 // Add a label for each tab page. They all contain the same text area.
5048 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr) {
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005049 if (tp == curtab)
5050 curtabidx = nr;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005051
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005052 BTab* tab = tabLine->TabAt(nr);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005053
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005054 if (tab == NULL) {
5055 tab = new VimTabLine::VimTab();
5056 tabLine->AddTab(NULL, tab);
5057 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005058
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005059 get_tabline_label(tp, FALSE);
5060 tab->SetLabel((const char*)NameBuff);
5061 tabLine->Invalidate();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005062 }
5063
5064 // Remove any old labels.
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005065 while (nr < tabLine->CountTabs())
5066 tabLine->RemoveTab(nr);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005067
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005068 if (tabLine->Selection() != curtabidx)
5069 tabLine->Select(curtabidx);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005070
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005071 gui.vimWindow->Unlock();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005072}
5073
5074/*
5075 * Set the current tab to "nr". First tab is 1.
5076 */
5077 void
5078gui_mch_set_curtab(int nr)
5079{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005080 VimTabLine *tabLine = gui.vimForm->TabLine();
5081 if (tabLine == NULL)
5082 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005083
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005084 gui.vimWindow->Lock();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005085
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005086 if (tabLine->Selection() != nr -1)
5087 tabLine->Select(nr -1);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005088
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005089 gui.vimWindow->Unlock();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005090}
5091
5092#endif // FEAT_GUI_TABLINE