blob: 60926f9be2de2a6b54a7fb40e8d02062959a81ed [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"
78#include "globals.h"
79#include "proto.h"
80#include "version.h"
81
Bram Moolenaarb52575f2020-04-24 22:16:13 +020082} // extern "C"
Bram Moolenaarb3f74062020-02-26 16:16:53 +010083
84// ---------------- start of header part ----------------
85
86//#include <Alert.h>
87#include <Application.h>
88#include <Beep.h>
89#include <Bitmap.h>
90#include <Box.h>
91#include <Button.h>
92#include <Clipboard.h>
93#include <Debug.h>
94//#include <Directory.h>
95//#include <Entry.h>
96#include <File.h>
97#include <FilePanel.h>
98#include <FindDirectory.h>
99//#include <Font.h>
100#include <IconUtils.h>
101#include <Input.h>
102#include <ListView.h>
103#include <MenuBar.h>
104#include <MenuItem.h>
105//#include <MessageQueue.h>
106//#include <OS.h>
107#include <Path.h>
108#include <PictureButton.h>
109#include <PopUpMenu.h>
110//#include <Region.h>
111#include <Resources.h>
112//#include <Roster.h>
113#include <Screen.h>
114#include <ScrollBar.h>
115#include <ScrollView.h>
116#include <String.h>
117#include <StringView.h>
118//#include <SupportDefs.h>
119#include <TabView.h>
120#include <TextControl.h>
121#include <TextView.h>
122#include <TranslationUtils.h>
123#include <TranslatorFormats.h>
124#include <View.h>
125#include <Window.h>
126
127class VimApp;
128class VimFormView;
129class VimTextAreaView;
130class VimWindow;
131class VimToolbar;
132class VimTabLine;
133
134extern key_map *keyMap;
135extern char *keyMapChars;
136
137extern int main(int argc, char **argv);
138
139#ifndef B_MAX_PORT_COUNT
140#define B_MAX_PORT_COUNT 255
141#endif
142
143// VimApp seems comparable to the X "vimShell"
144class VimApp: public BApplication
145{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200146 typedef BApplication Inherited;
147 public:
148 VimApp(const char *appsig);
149 ~VimApp();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100150
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200151 // callbacks:
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100152#if 0
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200153 virtual void DispatchMessage(BMessage *m, BHandler *h)
154 {
155 m->PrintToStream();
156 Inherited::DispatchMessage(m, h);
157 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100158#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200159 virtual void ReadyToRun();
160 virtual void ArgvReceived(int32 argc, char **argv);
161 virtual void RefsReceived(BMessage *m);
162 virtual bool QuitRequested();
163 virtual void MessageReceived(BMessage *m);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100164
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200165 static void SendRefs(BMessage *m, bool changedir);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100166
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200167 sem_id fFilePanelSem;
168 BFilePanel* fFilePanel;
169 BPath fBrowsedPath;
170 private:
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100171};
172
173class VimWindow: public BWindow
174{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200175 typedef BWindow Inherited;
176 public:
177 VimWindow();
178 ~VimWindow();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100179
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200180 // virtual void DispatchMessage(BMessage *m, BHandler *h);
181 virtual void WindowActivated(bool active);
182 virtual bool QuitRequested();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100183
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200184 VimFormView *formView;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100185
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200186 private:
187 void init();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100188
189};
190
191class VimFormView: public BView
192{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200193 typedef BView Inherited;
194 public:
195 VimFormView(BRect frame);
196 ~VimFormView();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100197
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200198 // callbacks:
199 virtual void AllAttached();
200 virtual void FrameResized(float new_width, float new_height);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100201
202#define MENUBAR_MARGIN 1
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200203 float MenuHeight() const
204 { return menuBar ? menuBar->Frame().Height() + MENUBAR_MARGIN: 0; }
205 BMenuBar *MenuBar() const
206 { return menuBar; }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100207
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200208 private:
209 void init(BRect);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100210
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200211 BMenuBar *menuBar;
212 VimTextAreaView *textArea;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100213
214#ifdef FEAT_TOOLBAR
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200215 public:
216 float ToolbarHeight() const;
217 VimToolbar *ToolBar() const
218 { return toolBar; }
219 private:
220 VimToolbar *toolBar;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100221#endif
222
223#ifdef FEAT_GUI_TABLINE
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200224 public:
225 VimTabLine *TabLine() const { return tabLine; }
226 bool IsShowingTabLine() const { return showingTabLine; }
227 void SetShowingTabLine(bool showing) { showingTabLine = showing; }
228 float TablineHeight() const;
229 private:
230 VimTabLine *tabLine;
231 int showingTabLine;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100232#endif
233};
234
235class VimTextAreaView: public BView
236{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200237 typedef BView Inherited;
238 public:
239 VimTextAreaView(BRect frame);
240 ~VimTextAreaView();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100241
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200242 // callbacks:
243 virtual void Draw(BRect updateRect);
244 virtual void KeyDown(const char *bytes, int32 numBytes);
245 virtual void MouseDown(BPoint point);
246 virtual void MouseUp(BPoint point);
247 virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *message);
248 virtual void MessageReceived(BMessage *m);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100249
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200250 // own functions:
251 int mchInitFont(char_u *name);
252 void mchDrawString(int row, int col, char_u *s, int len, int flags);
253 void mchClearBlock(int row1, int col1, int row2, int col2);
254 void mchClearAll();
255 void mchDeleteLines(int row, int num_lines);
256 void mchInsertLines(int row, int num_lines);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100257
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200258 static void guiSendMouseEvent(int button, int x, int y, int repeated_click, int_u modifiers);
259 static void guiMouseMoved(int x, int y);
260 static void guiBlankMouse(bool should_hide);
261 static int_u mouseModifiersToVim(int32 beModifiers);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100262
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200263 int32 mouseDragEventCount;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100264
265#ifdef FEAT_MBYTE_IME
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200266 void DrawIMString(void);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100267#endif
268
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200269 private:
270 void init(BRect);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100271
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200272 int_u vimMouseButton;
273 int_u vimMouseModifiers;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100274
275#ifdef FEAT_MBYTE_IME
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200276 struct {
277 BMessenger* messenger;
278 BMessage* message;
279 BPoint location;
280 int row;
281 int col;
282 int count;
283 } IMData;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100284#endif
285};
286
287class VimScrollBar: public BScrollBar
288{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200289 typedef BScrollBar Inherited;
290 public:
291 VimScrollBar(scrollbar_T *gsb, orientation posture);
292 ~VimScrollBar();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100293
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200294 virtual void ValueChanged(float newValue);
295 virtual void MouseUp(BPoint where);
296 void SetValue(float newval);
297 scrollbar_T *getGsb()
298 { return gsb; }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100299
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200300 int32 scrollEventCount;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100301
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200302 private:
303 scrollbar_T *gsb;
304 float ignoreValue;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100305};
306
307
308#ifdef FEAT_TOOLBAR
309
310class VimToolbar : public BBox
311{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200312 static BBitmap *normalButtonsBitmap;
313 static BBitmap *grayedButtonsBitmap;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100314
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200315 BBitmap *LoadVimBitmap(const char* fileName);
316 bool GetPictureFromBitmap(BPicture *pictureTo, int32 index, BBitmap *bitmapFrom, bool pressed);
317 bool ModifyBitmapToGrayed(BBitmap *bitmap);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100318
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200319 BList fButtonsList;
320 void InvalidateLayout();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100321
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200322 public:
323 VimToolbar(BRect frame, const char * name);
324 ~VimToolbar();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100325
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200326 bool PrepareButtonBitmaps();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100327
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200328 bool AddButton(int32 index, vimmenu_T *menu);
329 bool RemoveButton(vimmenu_T *menu);
330 bool GrayButton(vimmenu_T *menu, int grey);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100331
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200332 float ToolbarHeight() const;
333 virtual void AttachedToWindow();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100334};
335
336BBitmap *VimToolbar::normalButtonsBitmap = NULL;
337BBitmap *VimToolbar::grayedButtonsBitmap = NULL;
338
339const float ToolbarMargin = 3.;
340const float ButtonMargin = 3.;
341
342#endif //FEAT_TOOLBAR
343
344#ifdef FEAT_GUI_TABLINE
345
346class VimTabLine : public BTabView
347{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200348 public:
349 class VimTab : public BTab {
350 public:
351 VimTab() : BTab(new BView(BRect(), "-Empty-", 0, 0)) {}
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100352
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200353 virtual void Select(BView* owner);
354 };
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100355
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200356 VimTabLine(BRect r) : BTabView(r, "vimTabLine", B_WIDTH_FROM_LABEL,
357 B_FOLLOW_LEFT | B_FOLLOW_TOP | B_FOLLOW_RIGHT, B_WILL_DRAW | B_FRAME_EVENTS) {}
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100358
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200359 float TablineHeight() const;
360 virtual void MouseDown(BPoint point);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100361};
362
363#endif //FEAT_GUI_TABLINE
364
365
366// For caching the fonts that are used;
367// Vim seems rather sloppy in this regard.
368class VimFont: public BFont
369{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200370 typedef BFont Inherited;
371 public:
372 VimFont();
373 VimFont(const VimFont *rhs);
374 VimFont(const BFont *rhs);
375 VimFont(const VimFont &rhs);
376 ~VimFont();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100377
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200378 VimFont *next;
379 int refcount;
380 char_u *name;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100381
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200382 private:
383 void init();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100384};
385
386#if defined(FEAT_GUI_DIALOG)
387
388class VimDialog : public BWindow
389{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200390 typedef BWindow Inherited;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100391
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200392 BButton* _CreateButton(int32 which, const char* label);
393
394 public:
395
396 class View : public BView {
397 typedef BView Inherited;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100398
399 public:
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200400 View(BRect frame);
401 ~View();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100402
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200403 virtual void Draw(BRect updateRect);
404 void InitIcon(int32 type);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100405
406 private:
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200407 BBitmap* fIconBitmap;
408 };
409
410 VimDialog(int type, const char *title, const char *message,
411 const char *buttons, int dfltbutton, const char *textfield,
412 int ex_cmd);
413 ~VimDialog();
414
415 int Go();
416
417 virtual void MessageReceived(BMessage *msg);
418
419 private:
420 sem_id fDialogSem;
421 int fDialogValue;
422 BList fButtonsList;
423 BTextView* fMessageView;
424 BTextControl* fInputControl;
425 const char* fInputValue;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100426};
427
428class VimSelectFontDialog : public BWindow
429{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200430 typedef BWindow Inherited;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100431
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200432 void _CleanList(BListView* list);
433 void _UpdateFontStyles();
434 void _UpdateSizeInputPreview();
435 void _UpdateFontPreview();
436 bool _UpdateFromListItem(BListView* list, char* text, int textSize);
437 public:
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100438
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200439 VimSelectFontDialog(font_family* family, font_style* style, float* size);
440 ~VimSelectFontDialog();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100441
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200442 bool Go();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100443
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200444 virtual void MessageReceived(BMessage *msg);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100445
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200446 private:
447 status_t fStatus;
448 sem_id fDialogSem;
449 bool fDialogValue;
450 font_family* fFamily;
451 font_style* fStyle;
452 float* fSize;
453 font_family fFontFamily;
454 font_style fFontStyle;
455 float fFontSize;
456 BStringView* fPreview;
457 BListView* fFamiliesList;
458 BListView* fStylesList;
459 BListView* fSizesList;
460 BTextControl* fSizesInput;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100461};
462
463#endif // FEAT_GUI_DIALOG
464
465// ---------------- end of GUI classes ----------------
466
467struct MainArgs {
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200468 int argc;
469 char **argv;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100470};
471
472// These messages are copied through the VDCMP.
473// Therefore they ought not to have anything fancy.
474// They must be of POD type (Plain Old Data)
475// as the C++ standard calls them.
476
477#define KEY_MSG_BUFSIZ 7
478#if KEY_MSG_BUFSIZ < MAX_KEY_CODE_LEN
479#error Increase KEY_MSG_BUFSIZ!
480#endif
481
482struct VimKeyMsg {
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200483 char_u length;
484 char_u chars[KEY_MSG_BUFSIZ]; // contains Vim encoding
485 bool csi_escape;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100486};
487
488struct VimResizeMsg {
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200489 int width;
490 int height;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100491};
492
493struct VimScrollBarMsg {
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200494 VimScrollBar *sb;
495 long value;
496 int stillDragging;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100497};
498
499struct VimMenuMsg {
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200500 vimmenu_T *guiMenu;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100501};
502
503struct VimMouseMsg {
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200504 int button;
505 int x;
506 int y;
507 int repeated_click;
508 int_u modifiers;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100509};
510
511struct VimMouseMovedMsg {
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200512 int x;
513 int y;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100514};
515
516struct VimFocusMsg {
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200517 bool active;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100518};
519
520struct VimRefsMsg {
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200521 BMessage *message;
522 bool changedir;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100523};
524
525struct VimTablineMsg {
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200526 int index;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100527};
528
529struct VimTablineMenuMsg {
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200530 int index;
531 int event;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100532};
533
534struct VimMsg {
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200535 enum VimMsgType {
536 Key, Resize, ScrollBar, Menu, Mouse, MouseMoved, Focus, Refs, Tabline, TablineMenu
537 };
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100538
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200539 union {
540 struct VimKeyMsg Key;
541 struct VimResizeMsg NewSize;
542 struct VimScrollBarMsg Scroll;
543 struct VimMenuMsg Menu;
544 struct VimMouseMsg Mouse;
545 struct VimMouseMovedMsg MouseMoved;
546 struct VimFocusMsg Focus;
547 struct VimRefsMsg Refs;
548 struct VimTablineMsg Tabline;
549 struct VimTablineMenuMsg TablineMenu;
550 } u;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100551};
552
553#define RGB(r, g, b) ((char_u)(r) << 16 | (char_u)(g) << 8 | (char_u)(b) << 0)
Bram Moolenaar9e175142020-04-30 22:51:01 +0200554#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 +0100555
556// ---------------- end of header part ----------------
557
558static struct specialkey
559{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200560 uint16 BeKeys;
561#define KEY(a,b) ((a)<<8|(b))
562#define K(a) KEY(0,a) // for ASCII codes
563#define F(b) KEY(1,b) // for scancodes
564 char_u vim_code0;
565 char_u vim_code1;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100566} special_keys[] =
567{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200568 {K(B_UP_ARROW), 'k', 'u'},
569 {K(B_DOWN_ARROW), 'k', 'd'},
570 {K(B_LEFT_ARROW), 'k', 'l'},
571 {K(B_RIGHT_ARROW), 'k', 'r'},
572 {K(B_BACKSPACE), 'k', 'b'},
573 {K(B_INSERT), 'k', 'I'},
574 {K(B_DELETE), 'k', 'D'},
575 {K(B_HOME), 'k', 'h'},
576 {K(B_END), '@', '7'},
577 {K(B_PAGE_UP), 'k', 'P'}, // XK_Prior
578 {K(B_PAGE_DOWN), 'k', 'N'}, // XK_Next,
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100579
580#define FIRST_FUNCTION_KEY 11
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200581 {F(B_F1_KEY), 'k', '1'},
582 {F(B_F2_KEY), 'k', '2'},
583 {F(B_F3_KEY), 'k', '3'},
584 {F(B_F4_KEY), 'k', '4'},
585 {F(B_F5_KEY), 'k', '5'},
586 {F(B_F6_KEY), 'k', '6'},
587 {F(B_F7_KEY), 'k', '7'},
588 {F(B_F8_KEY), 'k', '8'},
589 {F(B_F9_KEY), 'k', '9'},
590 {F(B_F10_KEY), 'k', ';'},
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100591
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200592 {F(B_F11_KEY), 'F', '1'},
593 {F(B_F12_KEY), 'F', '2'},
594 // {XK_F13, 'F', '3'}, // would be print screen
595 // sysreq
596 {F(0x0F), 'F', '4'}, // scroll lock
597 {F(0x10), 'F', '5'}, // pause/break
598 // {XK_F16, 'F', '6'},
599 // {XK_F17, 'F', '7'},
600 // {XK_F18, 'F', '8'},
601 // {XK_F19, 'F', '9'},
602 // {XK_F20, 'F', 'A'},
603 // {XK_F21, 'F', 'B'},
604 // {XK_F22, 'F', 'C'},
605 // {XK_F23, 'F', 'D'},
606 // {XK_F24, 'F', 'E'},
607 // {XK_F25, 'F', 'F'},
608 // {XK_F26, 'F', 'G'},
609 // {XK_F27, 'F', 'H'},
610 // {XK_F28, 'F', 'I'},
611 // {XK_F29, 'F', 'J'},
612 // {XK_F30, 'F', 'K'},
613 // {XK_F31, 'F', 'L'},
614 // {XK_F32, 'F', 'M'},
615 // {XK_F33, 'F', 'N'},
616 // {XK_F34, 'F', 'O'},
617 // {XK_F35, 'F', 'P'}, // keysymdef.h defines up to F35
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100618
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200619 // {XK_Help, '%', '1'}, // XK_Help
620 {F(B_PRINT_KEY), '%', '9'},
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100621
622#if 0
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200623 // Keypad keys:
624 {F(0x48), 'k', 'l'}, // XK_KP_Left
625 {F(0x4A), 'k', 'r'}, // XK_KP_Right
626 {F(0x38), 'k', 'u'}, // XK_KP_Up
627 {F(0x59), 'k', 'd'}, // XK_KP_Down
628 {F(0x64), 'k', 'I'}, // XK_KP_Insert
629 {F(0x65), 'k', 'D'}, // XK_KP_Delete
630 {F(0x37), 'k', 'h'}, // XK_KP_Home
631 {F(0x58), '@', '7'}, // XK_KP_End
632 {F(0x39), 'k', 'P'}, // XK_KP_Prior
633 {F(0x60), 'k', 'N'}, // XK_KP_Next
634 {F(0x49), '&', '8'}, // XK_Undo, keypad 5
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100635#endif
636
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200637 // End of list marker:
638 {0, 0, 0}
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100639};
640
641#define NUM_SPECIAL_KEYS (sizeof(special_keys)/sizeof(special_keys[0]))
642
643// ---------------- VimApp ----------------
644
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200645 static void
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100646docd(BPath &path)
647{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200648 mch_chdir((char *)path.Path());
649 // Do this to get the side effects of a :cd command
650 do_cmdline_cmd((char_u *)"cd .");
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100651}
652
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200653 static void
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100654drop_callback(void *cookie)
655{
656 // TODO here we could handle going to a specific position in the dropped
657 // file (see src/gui_mac.c)
658 // Update the screen display
659 update_screen(NOT_VALID);
660}
661
662 // Really handle dropped files and folders.
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200663 static void
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100664RefsReceived(BMessage *m, bool changedir)
665{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200666 uint32 type;
667 int32 count;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100668
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200669 m->PrintToStream();
670 switch (m->what) {
671 case B_REFS_RECEIVED:
672 case B_SIMPLE_DATA:
673 m->GetInfo("refs", &type, &count);
674 if (type != B_REF_TYPE)
675 goto bad;
676 break;
677 case B_ARGV_RECEIVED:
678 m->GetInfo("argv", &type, &count);
679 if (type != B_STRING_TYPE)
680 goto bad;
681 if (changedir) {
682 char *dirname;
683 if (m->FindString("cwd", (const char **) &dirname) == B_OK) {
684 chdir(dirname);
685 do_cmdline_cmd((char_u *)"cd .");
686 }
687 }
688 break;
689 default:
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100690bad:
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200691 /*fprintf(stderr, "bad!\n"); */
692 delete m;
693 return;
694 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100695
696#ifdef FEAT_VISUAL
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200697 reset_VIsual();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100698#endif
699
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200700 char_u **fnames;
701 fnames = (char_u **) alloc(count * sizeof(char_u *));
702 int fname_index = 0;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100703
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200704 switch (m->what) {
705 case B_REFS_RECEIVED:
706 case B_SIMPLE_DATA:
707 // fprintf(stderr, "case B_REFS_RECEIVED\n");
708 for (int i = 0; i < count; ++i)
709 {
710 entry_ref ref;
711 if (m->FindRef("refs", i, &ref) == B_OK) {
712 BEntry entry(&ref, false);
713 BPath path;
714 entry.GetPath(&path);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100715
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200716 // Change to parent directory?
717 if (changedir) {
718 BPath parentpath;
719 path.GetParent(&parentpath);
720 docd(parentpath);
721 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100722
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200723 // Is it a directory? If so, cd into it.
724 BDirectory bdir(&ref);
725 if (bdir.InitCheck() == B_OK) {
726 // don't cd if we already did it
727 if (!changedir)
728 docd(path);
729 } else {
730 mch_dirname(IObuff, IOSIZE);
731 char_u *fname = shorten_fname((char_u *)path.Path(), IObuff);
732 if (fname == NULL)
733 fname = (char_u *)path.Path();
734 fnames[fname_index++] = vim_strsave(fname);
735 // fprintf(stderr, "%s\n", fname);
736 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100737
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200738 // Only do it for the first file/dir
739 changedir = false;
740 }
741 }
742 break;
743 case B_ARGV_RECEIVED:
744 // fprintf(stderr, "case B_ARGV_RECEIVED\n");
745 for (int i = 1; i < count; ++i)
746 {
747 char *fname;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100748
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200749 if (m->FindString("argv", i, (const char **) &fname) == B_OK) {
750 fnames[fname_index++] = vim_strsave((char_u *)fname);
751 }
752 }
753 break;
754 default:
755 // fprintf(stderr, "case default\n");
756 break;
757 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100758
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200759 delete m;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100760
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200761 // Handle the drop, :edit to get to the file
762 if (fname_index > 0) {
763 handle_drop(fname_index, fnames, FALSE, drop_callback, NULL);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100764
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200765 setcursor();
766 out_flush();
767 } else {
768 vim_free(fnames);
769 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100770}
771
772VimApp::VimApp(const char *appsig):
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200773 BApplication(appsig),
774 fFilePanelSem(-1),
775 fFilePanel(NULL)
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100776{
777}
778
779VimApp::~VimApp()
780{
781}
782
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200783 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100784VimApp::ReadyToRun()
785{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200786 /*
787 * Apparently signals are inherited by the created thread -
788 * disable the most annoying ones.
789 */
790 signal(SIGINT, SIG_IGN);
791 signal(SIGQUIT, SIG_IGN);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100792}
793
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200794 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100795VimApp::ArgvReceived(int32 arg_argc, char **arg_argv)
796{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200797 if (!IsLaunching()) {
798 /*
799 * This can happen if we are set to Single or Exclusive
800 * Launch. Be nice and open the file(s).
801 */
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100802 if (gui.vimWindow)
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200803 gui.vimWindow->Minimize(false);
804 BMessage *m = CurrentMessage();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100805 DetachCurrentMessage();
806 SendRefs(m, true);
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200807 }
808}
809
810 void
811VimApp::RefsReceived(BMessage *m)
812{
813 // Horrible hack!!! XXX XXX XXX
814 // The real problem is that b_start_ffc is set too late for
815 // the initial empty buffer. As a result the window will be
816 // split instead of abandoned.
817 int limit = 15;
818 while (--limit >= 0 && (curbuf == NULL || curbuf->b_start_ffc == 0))
819 snooze(100000); // 0.1 s
820 if (gui.vimWindow)
821 gui.vimWindow->Minimize(false);
822 DetachCurrentMessage();
823 SendRefs(m, true);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100824}
825
826/*
827 * Pass a BMessage on to the main() thread.
828 * Caller must have detached the message.
829 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200830 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100831VimApp::SendRefs(BMessage *m, bool changedir)
832{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200833 VimRefsMsg rm;
834 rm.message = m;
835 rm.changedir = changedir;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100836
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200837 write_port(gui.vdcmp, VimMsg::Refs, &rm, sizeof(rm));
838 // calls ::RefsReceived
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100839}
840
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200841 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100842VimApp::MessageReceived(BMessage *m)
843{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200844 switch (m->what) {
845 case 'save':
846 {
847 entry_ref refDirectory;
848 m->FindRef("directory", &refDirectory);
849 fBrowsedPath.SetTo(&refDirectory);
850 BString strName;
851 m->FindString("name", &strName);
852 fBrowsedPath.Append(strName.String());
853 }
854 break;
855 case 'open':
856 {
857 entry_ref ref;
858 m->FindRef("refs", &ref);
859 fBrowsedPath.SetTo(&ref);
860 }
861 break;
862 case B_CANCEL:
863 {
864 BFilePanel *panel;
865 m->FindPointer("source", (void**)&panel);
866 if (fFilePanelSem != -1 && panel == fFilePanel)
867 {
868 delete_sem(fFilePanelSem);
869 fFilePanelSem = -1;
870 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100871
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200872 }
873 break;
874 default:
875 Inherited::MessageReceived(m);
876 break;
877 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100878}
879
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200880 bool
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100881VimApp::QuitRequested()
882{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200883 (void)Inherited::QuitRequested();
884 return false;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100885}
886
887// ---------------- VimWindow ----------------
888
889VimWindow::VimWindow():
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200890 BWindow(BRect(40, 40, 150, 150),
891 "Vim",
892 B_TITLED_WINDOW,
893 0,
894 B_CURRENT_WORKSPACE)
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100895
896{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200897 init();
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100898}
899
900VimWindow::~VimWindow()
901{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200902 if (formView) {
903 RemoveChild(formView);
904 delete formView;
905 }
906 gui.vimWindow = NULL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100907}
908
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200909 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100910VimWindow::init()
911{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200912 // Attach the VimFormView
913 formView = new VimFormView(Bounds());
914 if (formView != NULL) {
915 AddChild(formView);
916 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100917}
918
919#if 0 // disabled in zeta patch
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200920 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100921VimWindow::DispatchMessage(BMessage *m, BHandler *h)
922{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200923 /*
924 * Route B_MOUSE_UP messages to MouseUp(), in
925 * a manner that should be compatible with the
926 * intended future system behaviour.
927 */
928 switch (m->what) {
929 case B_MOUSE_UP:
930 // if (!h) h = PreferredHandler();
931 // gcc isn't happy without this extra set of braces, complains about
932 // jump to case label crosses init of 'class BView * v'
933 // richard@whitequeen.com jul 99
934 {
935 BView *v = dynamic_cast<BView *>(h);
936 if (v) {
937 // m->PrintToStream();
938 BPoint where;
939 m->FindPoint("where", &where);
940 v->MouseUp(where);
941 } else {
942 Inherited::DispatchMessage(m, h);
943 }
944 }
945 break;
946 default:
947 Inherited::DispatchMessage(m, h);
948 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100949}
950#endif
951
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200952 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100953VimWindow::WindowActivated(bool active)
954{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200955 Inherited::WindowActivated(active);
956 // the textArea gets the keyboard action
957 if (active && gui.vimTextArea)
958 gui.vimTextArea->MakeFocus(true);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100959
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200960 struct VimFocusMsg fm;
961 fm.active = active;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100962
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200963 write_port(gui.vdcmp, VimMsg::Focus, &fm, sizeof(fm));
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100964}
965
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200966 bool
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100967VimWindow::QuitRequested()
968{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200969 struct VimKeyMsg km;
970 km.length = 5;
971 memcpy((char *)km.chars, "\033:qa\r", km.length);
972 km.csi_escape = false;
973 write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km));
974 return false;
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100975}
976
977// ---------------- VimFormView ----------------
978
979VimFormView::VimFormView(BRect frame):
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200980 BView(frame, "VimFormView", B_FOLLOW_ALL_SIDES,
981 B_WILL_DRAW | B_FRAME_EVENTS),
982 menuBar(NULL),
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100983#ifdef FEAT_TOOLBAR
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200984 toolBar(NULL),
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100985#endif
986#ifdef FEAT_GUI_TABLINE
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200987// showingTabLine(false),
988 tabLine(NULL),
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100989#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200990 textArea(NULL)
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100991{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200992 init(frame);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100993}
994
995VimFormView::~VimFormView()
996{
Bram Moolenaarb52575f2020-04-24 22:16:13 +0200997 if (menuBar) {
998 RemoveChild(menuBar);
Bram Moolenaarb3f74062020-02-26 16:16:53 +0100999#ifdef never
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001000 // deleting the menuBar leads to SEGV on exit
1001 // richard@whitequeen.com Jul 99
1002 delete menuBar;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001003#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001004 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001005
1006#ifdef FEAT_TOOLBAR
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001007 delete toolBar;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001008#endif
1009
1010#ifdef FEAT_GUI_TABLINE
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001011 delete tabLine;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001012#endif
1013
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001014 if (textArea) {
1015 RemoveChild(textArea);
1016 delete textArea;
1017 }
1018 gui.vimForm = NULL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001019}
1020
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001021 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001022VimFormView::init(BRect frame)
1023{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001024 menuBar = new BMenuBar(BRect(0,0,-MENUBAR_MARGIN,-MENUBAR_MARGIN),
1025 "VimMenuBar");
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001026
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001027 AddChild(menuBar);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001028
1029#ifdef FEAT_TOOLBAR
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001030 toolBar = new VimToolbar(BRect(0,0,0,0), "VimToolBar");
1031 toolBar->PrepareButtonBitmaps();
1032 AddChild(toolBar);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001033#endif
1034
1035#ifdef FEAT_GUI_TABLINE
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001036 tabLine = new VimTabLine(BRect(0,0,0,0));
1037// tabLine->PrepareButtonBitmaps();
1038 AddChild(tabLine);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001039#endif
1040
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001041 BRect remaining = frame;
1042 textArea = new VimTextAreaView(remaining);
1043 AddChild(textArea);
1044 // The textArea will be resized later when menus are added
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001045
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001046 gui.vimForm = this;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001047}
1048
1049#ifdef FEAT_TOOLBAR
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001050 float
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001051VimFormView::ToolbarHeight() const
1052{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001053 return toolBar ? toolBar->ToolbarHeight() : 0.;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001054}
1055#endif
1056
1057#ifdef FEAT_GUI_TABLINE
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001058 float
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001059VimFormView::TablineHeight() const
1060{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001061 return (tabLine && IsShowingTabLine()) ? tabLine->TablineHeight() : 0.;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001062}
1063#endif
1064
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001065 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001066VimFormView::AllAttached()
1067{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001068 /*
1069 * Apparently signals are inherited by the created thread -
1070 * disable the most annoying ones.
1071 */
1072 signal(SIGINT, SIG_IGN);
1073 signal(SIGQUIT, SIG_IGN);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001074
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001075 if (menuBar && textArea) {
1076 /*
1077 * Resize the textArea to fill the space left over by the menu.
1078 * This is somewhat futile since it will be done again once
1079 * menus are added to the menu bar.
1080 */
1081 BRect remaining = Bounds();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001082
1083#ifdef FEAT_MENU
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001084 remaining.top += MenuHeight();
1085 menuBar->ResizeTo(remaining.right, remaining.top);
1086 gui.menu_height = (int) MenuHeight();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001087#endif
1088
1089#ifdef FEAT_TOOLBAR
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001090 toolBar->MoveTo(remaining.left, remaining.top);
1091 toolBar->ResizeTo(remaining.right, ToolbarHeight());
1092 remaining.top += ToolbarHeight();
1093 gui.toolbar_height = ToolbarHeight();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001094#endif
1095
1096#ifdef FEAT_GUI_TABLINE
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001097 tabLine->MoveTo(remaining.left, remaining.top);
1098 tabLine->ResizeTo(remaining.right + 1, TablineHeight());
1099 remaining.top += TablineHeight();
1100 gui.tabline_height = TablineHeight();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001101#endif
1102
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001103 textArea->ResizeTo(remaining.Width(), remaining.Height());
1104 textArea->MoveTo(remaining.left, remaining.top);
1105 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001106
1107
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001108 Inherited::AllAttached();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001109}
1110
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001111 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001112VimFormView::FrameResized(float new_width, float new_height)
1113{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001114 struct VimResizeMsg sm;
1115 int adjust_h, adjust_w;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001116
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001117 new_width += 1; // adjust from width to number of pixels occupied
1118 new_height += 1;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001119
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001120 sm.width = (int) new_width;
1121 sm.height = (int) new_height;
1122 adjust_w = ((int)new_width - gui_get_base_width()) % gui.char_width;
1123 adjust_h = ((int)new_height - gui_get_base_height()) % gui.char_height;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001124
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001125 if (adjust_w > 0 || adjust_h > 0) {
1126 sm.width -= adjust_w;
1127 sm.height -= adjust_h;
1128 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001129
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001130 write_port(gui.vdcmp, VimMsg::Resize, &sm, sizeof(sm));
1131 // calls gui_resize_shell(new_width, new_height);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001132
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001133 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001134
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001135 /*
1136 * The area below the vertical scrollbar is erased to the colour
1137 * set with SetViewColor() automatically, because we had set
1138 * B_WILL_DRAW. Resizing the window tight around the vertical
1139 * scroll bar also helps to avoid debris.
1140 */
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001141}
1142
1143// ---------------- VimTextAreaView ----------------
1144
1145VimTextAreaView::VimTextAreaView(BRect frame):
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001146 BView(frame, "VimTextAreaView", B_FOLLOW_ALL_SIDES,
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001147#ifdef FEAT_MBYTE_IME
Bram Moolenaar80a8d382020-05-03 22:57:32 +02001148 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_INPUT_METHOD_AWARE
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001149#else
Bram Moolenaar80a8d382020-05-03 22:57:32 +02001150 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001151#endif
Bram Moolenaar80a8d382020-05-03 22:57:32 +02001152 ),
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001153 mouseDragEventCount(0)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001154{
1155#ifdef FEAT_MBYTE_IME
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001156 IMData.messenger = NULL;
1157 IMData.message = NULL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001158#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001159 init(frame);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001160}
1161
1162VimTextAreaView::~VimTextAreaView()
1163{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001164 gui.vimTextArea = NULL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001165}
1166
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001167 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001168VimTextAreaView::init(BRect frame)
1169{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001170 // set up global var for fast access
1171 gui.vimTextArea = this;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001172
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001173 /*
1174 * Tell the app server not to erase the view: we will
1175 * fill it in completely by ourselves.
1176 * (Does this really work? Even if not, it won't harm either.)
1177 */
1178 SetViewColor(B_TRANSPARENT_32_BIT);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001179#define PEN_WIDTH 1
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001180 SetPenSize(PEN_WIDTH);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001181#define W_WIDTH(curwin) 0
1182}
1183
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001184 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001185VimTextAreaView::Draw(BRect updateRect)
1186{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001187 /*
1188 * XXX Other ports call here:
1189 * out_flush(); * make sure all output has been processed *
1190 * but we can't do that, since it involves too much information
1191 * that is owned by other threads...
1192 */
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001193
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001194 /*
1195 * No need to use gui.vimWindow->Lock(): we are locked already.
1196 * However, it would not hurt.
1197 */
1198 rgb_color rgb = GUI_TO_RGB(gui.back_pixel);
1199 SetLowColor(rgb);
1200 FillRect(updateRect, B_SOLID_LOW);
1201 gui_redraw((int) updateRect.left, (int) updateRect.top,
1202 (int) (updateRect.Width() + PEN_WIDTH), (int) (updateRect.Height() + PEN_WIDTH));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001203
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001204 // Clear the border areas if needed
1205 SetLowColor(rgb);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001206
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001207 if (updateRect.left < FILL_X(0)) // left border
1208 FillRect(BRect(updateRect.left, updateRect.top,
1209 FILL_X(0)-PEN_WIDTH, updateRect.bottom), B_SOLID_LOW);
1210 if (updateRect.top < FILL_Y(0)) // top border
1211 FillRect(BRect(updateRect.left, updateRect.top,
1212 updateRect.right, FILL_Y(0)-PEN_WIDTH), B_SOLID_LOW);
1213 if (updateRect.right >= FILL_X(Columns)) // right border
1214 FillRect(BRect(FILL_X((int)Columns), updateRect.top,
1215 updateRect.right, updateRect.bottom), B_SOLID_LOW);
1216 if (updateRect.bottom >= FILL_Y(Rows)) // bottom border
1217 FillRect(BRect(updateRect.left, FILL_Y((int)Rows),
1218 updateRect.right, updateRect.bottom), B_SOLID_LOW);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001219
1220#ifdef FEAT_MBYTE_IME
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001221 DrawIMString();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001222#endif
1223}
1224
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001225 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001226VimTextAreaView::KeyDown(const char *bytes, int32 numBytes)
1227{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001228 struct VimKeyMsg km;
1229 char_u *dest = km.chars;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001230
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001231 bool canHaveVimModifiers = false;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001232
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001233 BMessage *msg = Window()->CurrentMessage();
1234 assert(msg);
1235 // msg->PrintToStream();
1236
1237 /*
1238 * Convert special keys to Vim codes.
1239 * I think it is better to do it in the window thread
1240 * so we use at least a little bit of the potential
1241 * of our 2 CPUs. Besides, due to the fantastic mapping
1242 * of special keys to UTF-8, we have quite some work to
1243 * do...
1244 * TODO: I'm not quite happy with detection of special
1245 * keys. Perhaps I should use scan codes after all...
1246 */
1247 if (numBytes > 1) {
1248 // This cannot be a special key
1249 if (numBytes > KEY_MSG_BUFSIZ)
1250 numBytes = KEY_MSG_BUFSIZ; // should never happen... ???
1251 km.length = numBytes;
1252 memcpy((char *)dest, bytes, numBytes);
1253 km.csi_escape = true;
1254 } else {
1255 int32 scancode = 0;
1256 msg->FindInt32("key", &scancode);
1257
1258 int32 beModifiers = 0;
1259 msg->FindInt32("modifiers", &beModifiers);
1260
1261 char_u string[3];
1262 int len = 0;
1263 km.length = 0;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001264
1265 /*
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001266 * For normal, printable ASCII characters, don't look them up
1267 * to check if they might be a special key. They aren't.
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001268 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001269 assert(B_BACKSPACE <= 0x20);
1270 assert(B_DELETE == 0x7F);
1271 if (((char_u)bytes[0] <= 0x20 || (char_u)bytes[0] == 0x7F) &&
1272 numBytes == 1) {
1273 /*
1274 * Due to the great nature of Be's mapping of special keys,
1275 * viz. into the range of the control characters,
1276 * we can only be sure it is *really* a special key if
1277 * if it is special without using ctrl. So, only if ctrl is
1278 * used, we need to check it unmodified.
1279 */
1280 if (beModifiers & B_CONTROL_KEY) {
1281 int index = keyMap->normal_map[scancode];
1282 int newNumBytes = keyMapChars[index];
1283 char_u *newBytes = (char_u *)&keyMapChars[index + 1];
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001284
1285 /*
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001286 * Check if still special without the control key.
1287 * This is needed for BACKSPACE: that key does produce
1288 * different values with modifiers (DEL).
1289 * Otherwise we could simply have checked for equality.
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001290 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001291 if (newNumBytes != 1 || (*newBytes > 0x20 &&
1292 *newBytes != 0x7F )) {
1293 goto notspecial;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001294 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001295 bytes = (char *)newBytes;
1296 }
1297 canHaveVimModifiers = true;
1298
1299 uint16 beoskey;
1300 int first, last;
1301
1302 /*
1303 * If numBytes == 0 that probably always indicates a special key.
1304 * (does not happen yet)
1305 */
1306 if (numBytes == 0 || bytes[0] == B_FUNCTION_KEY) {
1307 beoskey = F(scancode);
1308 first = FIRST_FUNCTION_KEY;
1309 last = NUM_SPECIAL_KEYS;
1310 } else if (*bytes == '\n' && scancode == 0x47) {
1311 // remap the (non-keypad) ENTER key from \n to \r.
1312 string[0] = '\r';
1313 len = 1;
1314 first = last = 0;
1315 } else {
1316 beoskey = K(bytes[0]);
1317 first = 0;
1318 last = FIRST_FUNCTION_KEY;
1319 }
1320
1321 for (int i = first; i < last; i++) {
1322 if (special_keys[i].BeKeys == beoskey) {
1323 string[0] = CSI;
1324 string[1] = special_keys[i].vim_code0;
1325 string[2] = special_keys[i].vim_code1;
1326 len = 3;
1327 }
1328 }
1329 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001330notspecial:
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001331 if (len == 0) {
1332 string[0] = bytes[0];
1333 len = 1;
1334 }
1335
1336 // Special keys (and a few others) may have modifiers
1337#if 0
1338 if (len == 3 ||
1339 bytes[0] == B_SPACE || bytes[0] == B_TAB ||
1340 bytes[0] == B_RETURN || bytes[0] == '\r' ||
1341 bytes[0] == B_ESCAPE)
1342#else
1343 if (canHaveVimModifiers)
1344#endif
1345 {
1346 int modifiers;
1347 modifiers = 0;
1348 if (beModifiers & B_SHIFT_KEY)
1349 modifiers |= MOD_MASK_SHIFT;
1350 if (beModifiers & B_CONTROL_KEY)
1351 modifiers |= MOD_MASK_CTRL;
1352 if (beModifiers & B_OPTION_KEY)
1353 modifiers |= MOD_MASK_ALT;
1354
1355 /*
1356 * For some keys a shift modifier is translated into another key
1357 * code. Do we need to handle the case where len != 1 and
1358 * string[0] != CSI? (Not for BeOS, since len == 3 implies
1359 * string[0] == CSI...)
1360 */
1361 int key;
1362 if (string[0] == CSI && len == 3)
1363 key = TO_SPECIAL(string[1], string[2]);
1364 else
1365 key = string[0];
1366 key = simplify_key(key, &modifiers);
1367 if (IS_SPECIAL(key))
1368 {
1369 string[0] = CSI;
1370 string[1] = K_SECOND(key);
1371 string[2] = K_THIRD(key);
1372 len = 3;
1373 }
1374 else
1375 {
1376 string[0] = key;
1377 len = 1;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001378 }
1379
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001380 if (modifiers)
1381 {
1382 *dest++ = CSI;
1383 *dest++ = KS_MODIFIER;
1384 *dest++ = modifiers;
1385 km.length = 3;
1386 }
1387 }
1388 memcpy((char *)dest, string, len);
1389 km.length += len;
1390 km.csi_escape = false;
1391 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001392
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001393 write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001394
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001395 /*
1396 * blank out the pointer if necessary
1397 */
1398 if (p_mh && !gui.pointer_hidden)
1399 {
1400 guiBlankMouse(true);
1401 gui.pointer_hidden = TRUE;
1402 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001403}
1404void
1405VimTextAreaView::guiSendMouseEvent(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001406 int button,
1407 int x,
1408 int y,
1409 int repeated_click,
1410 int_u modifiers)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001411{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001412 VimMouseMsg mm;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001413
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001414 mm.button = button;
1415 mm.x = x;
1416 mm.y = y;
1417 mm.repeated_click = repeated_click;
1418 mm.modifiers = modifiers;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001419
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001420 write_port(gui.vdcmp, VimMsg::Mouse, &mm, sizeof(mm));
1421 // calls gui_send_mouse_event()
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001422
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001423 /*
1424 * if our pointer is currently hidden, then we should show it.
1425 */
1426 if (gui.pointer_hidden)
1427 {
1428 guiBlankMouse(false);
1429 gui.pointer_hidden = FALSE;
1430 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001431}
1432
1433void
1434VimTextAreaView::guiMouseMoved(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001435 int x,
1436 int y)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001437{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001438 VimMouseMovedMsg mm;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001439
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001440 mm.x = x;
1441 mm.y = y;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001442
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001443 write_port(gui.vdcmp, VimMsg::MouseMoved, &mm, sizeof(mm));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001444
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001445 if (gui.pointer_hidden)
1446 {
1447 guiBlankMouse(false);
1448 gui.pointer_hidden = FALSE;
1449 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001450}
1451
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001452 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001453VimTextAreaView::guiBlankMouse(bool should_hide)
1454{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001455 if (should_hide) {
1456 // gui.vimApp->HideCursor();
1457 gui.vimApp->ObscureCursor();
1458 /*
1459 * ObscureCursor() would even be easier, but then
1460 * Vim's idea of mouse visibility does not necessarily
1461 * correspond to reality.
1462 */
1463 } else {
1464 // gui.vimApp->ShowCursor();
1465 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001466}
1467
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001468 int_u
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001469VimTextAreaView::mouseModifiersToVim(int32 beModifiers)
1470{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001471 int_u vim_modifiers = 0x0;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001472
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001473 if (beModifiers & B_SHIFT_KEY)
1474 vim_modifiers |= MOUSE_SHIFT;
1475 if (beModifiers & B_CONTROL_KEY)
1476 vim_modifiers |= MOUSE_CTRL;
1477 if (beModifiers & B_OPTION_KEY) // Alt or Meta key
1478 vim_modifiers |= MOUSE_ALT;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001479
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001480 return vim_modifiers;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001481}
1482
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001483 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001484VimTextAreaView::MouseDown(BPoint point)
1485{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001486 BMessage *m = Window()->CurrentMessage();
1487 assert(m);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001488
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001489 int32 buttons = 0;
1490 m->FindInt32("buttons", &buttons);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001491
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001492 int vimButton;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001493
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001494 if (buttons & B_PRIMARY_MOUSE_BUTTON)
1495 vimButton = MOUSE_LEFT;
1496 else if (buttons & B_SECONDARY_MOUSE_BUTTON)
1497 vimButton = MOUSE_RIGHT;
1498 else if (buttons & B_TERTIARY_MOUSE_BUTTON)
1499 vimButton = MOUSE_MIDDLE;
1500 else
1501 return; // Unknown button
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001502
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001503 vimMouseButton = 1; // don't care which one
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001504
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001505 // Handle multiple clicks
1506 int32 clicks = 0;
1507 m->FindInt32("clicks", &clicks);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001508
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001509 int32 modifiers = 0;
1510 m->FindInt32("modifiers", &modifiers);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001511
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001512 vimMouseModifiers = mouseModifiersToVim(modifiers);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001513
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001514 guiSendMouseEvent(vimButton, point.x, point.y,
1515 clicks > 1 /* = repeated_click*/, vimMouseModifiers);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001516}
1517
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001518 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001519VimTextAreaView::MouseUp(BPoint point)
1520{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001521 vimMouseButton = 0;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001522
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001523 BMessage *m = Window()->CurrentMessage();
1524 assert(m);
1525 // m->PrintToStream();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001526
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001527 int32 modifiers = 0;
1528 m->FindInt32("modifiers", &modifiers);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001529
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001530 vimMouseModifiers = mouseModifiersToVim(modifiers);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001531
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001532 guiSendMouseEvent(MOUSE_RELEASE, point.x, point.y,
1533 0 /* = repeated_click*/, vimMouseModifiers);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001534
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001535 Inherited::MouseUp(point);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001536}
1537
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001538 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001539VimTextAreaView::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
1540{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001541 /*
1542 * if our pointer is currently hidden, then we should show it.
1543 */
1544 if (gui.pointer_hidden)
1545 {
1546 guiBlankMouse(false);
1547 gui.pointer_hidden = FALSE;
1548 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001549
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001550 if (!vimMouseButton) { // could also check m->"buttons"
1551 guiMouseMoved(point.x, point.y);
1552 return;
1553 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001554
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001555 atomic_add(&mouseDragEventCount, 1);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001556
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001557 // Don't care much about "transit"
1558 guiSendMouseEvent(MOUSE_DRAG, point.x, point.y, 0, vimMouseModifiers);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001559}
1560
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001561 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001562VimTextAreaView::MessageReceived(BMessage *m)
1563{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001564 switch (m->what) {
1565 case 'menu':
1566 {
1567 VimMenuMsg mm;
1568 mm.guiMenu = NULL; // in case no pointer in msg
1569 m->FindPointer("VimMenu", (void **)&mm.guiMenu);
1570 write_port(gui.vdcmp, VimMsg::Menu, &mm, sizeof(mm));
1571 }
1572 break;
1573 case B_MOUSE_WHEEL_CHANGED:
1574 {
1575 VimScrollBar* scb = curwin->w_scrollbars[1].id;
1576 float small=0, big=0, dy=0;
1577 m->FindFloat("be:wheel_delta_y", &dy);
1578 scb->GetSteps(&small, &big);
1579 scb->SetValue(scb->Value()+small*dy*3);
1580 scb->ValueChanged(scb->Value());
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001581#if 0
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001582 scb = curwin->w_scrollbars[0].id;
1583 scb->GetSteps(&small, &big);
1584 scb->SetValue(scb->Value()+small*dy);
1585 scb->ValueChanged(scb->Value());
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001586#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001587 }
1588 break;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001589#ifdef FEAT_MBYTE_IME
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001590 case B_INPUT_METHOD_EVENT:
1591 {
1592 int32 opcode;
1593 m->FindInt32("be:opcode", &opcode);
1594 switch(opcode)
1595 {
1596 case B_INPUT_METHOD_STARTED:
1597 if (!IMData.messenger) delete IMData.messenger;
1598 IMData.messenger = new BMessenger();
1599 m->FindMessenger("be:reply_to", IMData.messenger);
1600 break;
1601 case B_INPUT_METHOD_CHANGED:
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001602 {
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001603 BString str;
1604 bool confirmed;
1605 if (IMData.message) *(IMData.message) = *m;
1606 else IMData.message = new BMessage(*m);
1607 DrawIMString();
1608 m->FindBool("be:confirmed", &confirmed);
1609 if (confirmed)
1610 {
1611 m->FindString("be:string", &str);
1612 char_u *chars = (char_u*)str.String();
1613 struct VimKeyMsg km;
1614 km.csi_escape = true;
1615 int clen;
1616 int i = 0;
1617 while (i < str.Length())
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001618 {
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001619 clen = utf_ptr2len(chars+i);
1620 memcpy(km.chars, chars+i, clen);
1621 km.length = clen;
1622 write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km));
1623 i += clen;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001624 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001625 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001626 }
1627 break;
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001628 case B_INPUT_METHOD_LOCATION_REQUEST:
1629 {
1630 BMessage msg(B_INPUT_METHOD_EVENT);
1631 msg.AddInt32("be:opcode", B_INPUT_METHOD_LOCATION_REQUEST);
1632 msg.AddPoint("be:location_reply", IMData.location);
1633 msg.AddFloat("be:height_reply", FILL_Y(1));
1634 IMData.messenger->SendMessage(&msg);
1635 }
1636 break;
1637 case B_INPUT_METHOD_STOPPED:
1638 delete IMData.messenger;
1639 delete IMData.message;
1640 IMData.messenger = NULL;
1641 IMData.message = NULL;
1642 break;
1643 }
1644 }
1645 // TODO: sz: break here???
1646#endif
1647 default:
1648 if (m->WasDropped()) {
1649 BWindow *w = Window();
1650 w->DetachCurrentMessage();
1651 w->Minimize(false);
1652 VimApp::SendRefs(m, (modifiers() & B_SHIFT_KEY) != 0);
1653 } else {
1654 Inherited::MessageReceived(m);
1655 }
1656 break;
1657 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001658}
1659
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001660 int
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001661VimTextAreaView::mchInitFont(char_u *name)
1662{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001663 VimFont *newFont = (VimFont *)gui_mch_get_font(name, 1);
1664 if (newFont != NOFONT) {
1665 gui.norm_font = (GuiFont)newFont;
1666 gui_mch_set_font((GuiFont)newFont);
1667 if (name && STRCMP(name, "*") != 0)
1668 hl_set_font_name(name);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001669
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001670 SetDrawingMode(B_OP_COPY);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001671
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001672 /*
1673 * Try to load other fonts for bold, italic, and bold-italic.
1674 * We should also try to work out what font to use for these when they are
1675 * not specified by X resources, but we don't yet.
1676 */
1677 return OK;
1678 }
1679 return FAIL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001680}
1681
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001682 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001683VimTextAreaView::mchDrawString(int row, int col, char_u *s, int len, int flags)
1684{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001685 /*
1686 * First we must erase the area, because DrawString won't do
1687 * that for us. XXX Most of the time this is a waste of effort
1688 * since the bachground has been erased already... DRAW_TRANSP
1689 * should be set when appropriate!!!
1690 * (Rectangles include the bottom and right edge)
1691 */
1692 if (!(flags & DRAW_TRANSP)) {
1693 int cells;
1694 cells = 0;
1695 for (int i=0; i<len; i++) {
1696 int cn = utf_ptr2cells((char_u *)(s+i));
1697 if (cn<4) cells += cn;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001698 }
1699
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001700 BRect r(FILL_X(col), FILL_Y(row),
1701 FILL_X(col + cells) - PEN_WIDTH, FILL_Y(row + 1) - PEN_WIDTH);
1702 FillRect(r, B_SOLID_LOW);
1703 }
1704
1705 BFont font;
1706 this->GetFont(&font);
1707 if (!font.IsFixed())
1708 {
1709 char* p = (char*)s;
1710 int32 clen, lastpos = 0;
1711 BPoint where;
1712 int cells;
1713 while ((p - (char*)s) < len) {
1714 clen = utf_ptr2len((u_char*)p);
1715 where.Set(TEXT_X(col+lastpos), TEXT_Y(row));
1716 DrawString(p, clen, where);
1717 if (flags & DRAW_BOLD) {
1718 where.x += 1.0;
1719 SetDrawingMode(B_OP_BLEND);
1720 DrawString(p, clen, where);
1721 SetDrawingMode(B_OP_COPY);
1722 }
1723 cells = utf_ptr2cells((char_u *)p);
1724 if (cells<4) lastpos += cells;
1725 else lastpos++;
1726 p += clen;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001727 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001728 }
1729 else
1730 {
1731 BPoint where(TEXT_X(col), TEXT_Y(row));
1732 DrawString((char*)s, len, where);
1733 if (flags & DRAW_BOLD) {
1734 where.x += 1.0;
1735 SetDrawingMode(B_OP_BLEND);
1736 DrawString((char*)s, len, where);
1737 SetDrawingMode(B_OP_COPY);
1738 }
1739 }
1740
1741 if (flags & DRAW_UNDERL) {
1742 int cells;
1743 cells = 0;
1744 for (int i=0; i<len; i++) {
1745 int cn = utf_ptr2cells((char_u *)(s+i));
1746 if (cn<4) cells += cn;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001747 }
1748
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001749 BPoint start(FILL_X(col), FILL_Y(row + 1) - PEN_WIDTH);
1750 BPoint end(FILL_X(col + cells) - PEN_WIDTH, start.y);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001751
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001752 StrokeLine(start, end);
1753 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001754}
1755
1756void
1757VimTextAreaView::mchClearBlock(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001758 int row1,
1759 int col1,
1760 int row2,
1761 int col2)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001762{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001763 BRect r(FILL_X(col1), FILL_Y(row1),
1764 FILL_X(col2 + 1) - PEN_WIDTH, FILL_Y(row2 + 1) - PEN_WIDTH);
1765 gui_mch_set_bg_color(gui.back_pixel);
1766 FillRect(r, B_SOLID_LOW);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001767}
1768
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001769 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001770VimTextAreaView::mchClearAll()
1771{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001772 gui_mch_set_bg_color(gui.back_pixel);
1773 FillRect(Bounds(), B_SOLID_LOW);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001774}
1775
1776/*
1777 * mchDeleteLines() Lock()s the window by itself.
1778 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001779 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001780VimTextAreaView::mchDeleteLines(int row, int num_lines)
1781{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001782 BRect source, dest;
1783 source.left = FILL_X(gui.scroll_region_left);
1784 source.top = FILL_Y(row + num_lines);
1785 source.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH;
1786 source.bottom = FILL_Y(gui.scroll_region_bot + 1) - PEN_WIDTH;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001787
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001788 dest.left = FILL_X(gui.scroll_region_left);
1789 dest.top = FILL_Y(row);
1790 dest.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH;
1791 dest.bottom = FILL_Y(gui.scroll_region_bot - num_lines + 1) - PEN_WIDTH;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001792
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001793 if (gui.vimWindow->Lock()) {
1794 // Clear one column more for when bold has spilled over
1795 CopyBits(source, dest);
1796 gui_clear_block(gui.scroll_region_bot - num_lines + 1,
1797 gui.scroll_region_left,
1798 gui.scroll_region_bot, gui.scroll_region_right);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001799
1800
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001801 gui.vimWindow->Unlock();
1802 /*
1803 * The Draw() callback will be called now if some of the source
1804 * bits were not in the visible region.
1805 */
1806 }
1807 // gui_x11_check_copy_area();
1808 // }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001809}
1810
1811/*
1812 * mchInsertLines() Lock()s the window by itself.
1813 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001814 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001815VimTextAreaView::mchInsertLines(int row, int num_lines)
1816{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001817 BRect source, dest;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001818
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001819 // XXX Attempt at a hack:
1820 gui.vimWindow->UpdateIfNeeded();
1821 source.left = FILL_X(gui.scroll_region_left);
1822 source.top = FILL_Y(row);
1823 source.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH;
1824 source.bottom = FILL_Y(gui.scroll_region_bot - num_lines + 1) - PEN_WIDTH;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001825
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001826 dest.left = FILL_X(gui.scroll_region_left);
1827 dest.top = FILL_Y(row + num_lines);
1828 dest.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH;
1829 dest.bottom = FILL_Y(gui.scroll_region_bot + 1) - PEN_WIDTH;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001830
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001831 if (gui.vimWindow->Lock()) {
1832 // Clear one column more for when bold has spilled over
1833 CopyBits(source, dest);
1834 gui_clear_block(row, gui.scroll_region_left,
1835 row + num_lines - 1, gui.scroll_region_right);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001836
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001837 gui.vimWindow->Unlock();
1838 /*
1839 * The Draw() callback will be called now if some of the source
1840 * bits were not in the visible region.
1841 * However, if we scroll too fast it can't keep up and the
1842 * update region gets messed up. This seems to be because copying
1843 * un-Draw()n bits does not generate Draw() calls for the copy...
1844 * I moved the hack to before the CopyBits() to reduce the
1845 * amount of additional waiting needed.
1846 */
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001847
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001848 // gui_x11_check_copy_area();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001849
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001850 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001851}
1852
1853#ifdef FEAT_MBYTE_IME
1854/*
1855 * DrawIMString draws string with IMData.message.
1856 */
1857void VimTextAreaView::DrawIMString(void)
1858{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001859 static const rgb_color r_highlight = {255, 152, 152, 255},
1860 b_highlight = {152, 203, 255, 255};
1861 BString str;
1862 const char* s;
1863 int len;
1864 BMessage* msg = IMData.message;
1865 if (!msg)
1866 return;
1867 gui_redraw_block(IMData.row, 0,
1868 IMData.row + IMData.count, W_WIDTH(curwin), GUI_MON_NOCLEAR);
1869 bool confirmed = false;
1870 msg->FindBool("be:confirmed", &confirmed);
1871 if (confirmed)
1872 return;
1873 rgb_color hcolor = HighColor(), lcolor = LowColor();
1874 msg->FindString("be:string", &str);
1875 s = str.String();
1876 len = str.Length();
1877 SetHighColor(0, 0, 0);
1878 IMData.row = gui.row;
1879 IMData.col = gui.col;
1880 int32 sel_start = 0, sel_end = 0;
1881 msg->FindInt32("be:selection", 0, &sel_start);
1882 msg->FindInt32("be:selection", 1, &sel_end);
1883 int clen, cn;
1884 BPoint pos(IMData.col, 0);
1885 BRect r;
1886 BPoint where;
1887 IMData.location = ConvertToScreen(
1888 BPoint(FILL_X(pos.x), FILL_Y(IMData.row + pos.y)));
1889 for (int i=0; i<len; i+=clen)
1890 {
1891 cn = utf_ptr2cells((char_u *)(s+i));
1892 clen = utf_ptr2len((char_u *)(s+i));
1893 if (pos.x + cn > W_WIDTH(curwin))
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001894 {
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001895 pos.y++;
1896 pos.x = 0;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001897 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001898 if (sel_start<=i && i<sel_end)
1899 {
1900 SetLowColor(r_highlight);
1901 IMData.location = ConvertToScreen(
1902 BPoint(FILL_X(pos.x), FILL_Y(IMData.row + pos.y)));
1903 }
1904 else
1905 {
1906 SetLowColor(b_highlight);
1907 }
1908 r.Set(FILL_X(pos.x), FILL_Y(IMData.row + pos.y),
1909 FILL_X(pos.x + cn) - PEN_WIDTH,
1910 FILL_Y(IMData.row + pos.y + 1) - PEN_WIDTH);
1911 FillRect(r, B_SOLID_LOW);
1912 where.Set(TEXT_X(pos.x), TEXT_Y(IMData.row + pos.y));
1913 DrawString((s+i), clen, where);
1914 pos.x += cn;
1915 }
1916 IMData.count = (int)pos.y;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001917
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001918 SetHighColor(hcolor);
1919 SetLowColor(lcolor);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001920}
1921#endif
1922// ---------------- VimScrollBar ----------------
1923
1924/*
1925 * BUG: XXX
1926 * It seems that BScrollBar determine their direction not from
1927 * "posture" but from if they are "tall" or "wide" in shape...
1928 *
1929 * Also, place them out of sight, because Vim enables them before
1930 * they are positioned.
1931 */
1932VimScrollBar::VimScrollBar(scrollbar_T *g, orientation posture):
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001933 BScrollBar(posture == B_HORIZONTAL ? BRect(-100,-100,-10,-90) :
1934 BRect(-100,-100,-90,-10),
1935 "vim scrollbar", (BView *)NULL,
1936 0.0, 10.0, posture),
1937 ignoreValue(-1),
1938 scrollEventCount(0)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001939{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001940 gsb = g;
1941 SetResizingMode(B_FOLLOW_NONE);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001942}
1943
1944VimScrollBar::~VimScrollBar()
1945{
1946}
1947
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001948 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001949VimScrollBar::ValueChanged(float newValue)
1950{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001951 if (ignoreValue >= 0.0 && newValue == ignoreValue) {
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001952 ignoreValue = -1;
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001953 return;
1954 }
1955 ignoreValue = -1;
1956 /*
1957 * We want to throttle the amount of scroll messages generated.
1958 * Normally I presume you won't get a new message before we've
1959 * handled the previous one, but because we're passing them on this
1960 * happens very quickly. So instead we keep a counter of how many
1961 * scroll events there are (or will be) in the VDCMP, and the
1962 * throttling happens at the receiving end.
1963 */
1964 atomic_add(&scrollEventCount, 1);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001965
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001966 struct VimScrollBarMsg sm;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001967
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001968 sm.sb = this;
1969 sm.value = (long) newValue;
1970 sm.stillDragging = TRUE;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001971
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001972 write_port(gui.vdcmp, VimMsg::ScrollBar, &sm, sizeof(sm));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001973
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001974 // calls gui_drag_scrollbar(sb, newValue, TRUE);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001975}
1976
1977/*
1978 * When the mouse goes up, report that scrolling has stopped.
1979 * MouseUp() is NOT called when the mouse-up occurs outside
1980 * the window, even though the thumb does move while the mouse
1981 * is outside... This has some funny effects... XXX
1982 * So we do special processing when the window de/activates.
1983 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001984 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001985VimScrollBar::MouseUp(BPoint where)
1986{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001987 // BMessage *m = Window()->CurrentMessage();
1988 // m->PrintToStream();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001989
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001990 atomic_add(&scrollEventCount, 1);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001991
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001992 struct VimScrollBarMsg sm;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001993
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001994 sm.sb = this;
1995 sm.value = (long) Value();
1996 sm.stillDragging = FALSE;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001997
Bram Moolenaarb52575f2020-04-24 22:16:13 +02001998 write_port(gui.vdcmp, VimMsg::ScrollBar, &sm, sizeof(sm));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01001999
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002000 // calls gui_drag_scrollbar(sb, newValue, FALSE);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002001
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002002 Inherited::MouseUp(where);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002003}
2004
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002005 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002006VimScrollBar::SetValue(float newValue)
2007{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002008 if (newValue == Value())
2009 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002010
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002011 ignoreValue = newValue;
2012 Inherited::SetValue(newValue);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002013}
2014
2015// ---------------- VimFont ----------------
2016
2017VimFont::VimFont(): BFont()
2018{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002019 init();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002020}
2021
2022VimFont::VimFont(const VimFont *rhs): BFont(rhs)
2023{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002024 init();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002025}
2026
2027VimFont::VimFont(const BFont *rhs): BFont(rhs)
2028{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002029 init();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002030}
2031
2032VimFont::VimFont(const VimFont &rhs): BFont(rhs)
2033{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002034 init();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002035}
2036
2037VimFont::~VimFont()
2038{
2039}
2040
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002041 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002042VimFont::init()
2043{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002044 next = NULL;
2045 refcount = 1;
2046 name = NULL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002047}
2048
2049// ---------------- VimDialog ----------------
2050
2051#if defined(FEAT_GUI_DIALOG)
2052
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002053const unsigned int kVimDialogButtonMsg = 'VMDB';
2054const unsigned int kVimDialogIconStripeWidth = 30;
2055const unsigned int kVimDialogButtonsSpacingX = 9;
2056const unsigned int kVimDialogButtonsSpacingY = 4;
2057const unsigned int kVimDialogSpacingX = 6;
2058const unsigned int kVimDialogSpacingY = 10;
2059const unsigned int kVimDialogMinimalWidth = 310;
2060const unsigned int kVimDialogMinimalHeight = 75;
2061const BRect kDefaultRect =
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002062BRect(0, 0, kVimDialogMinimalWidth, kVimDialogMinimalHeight);
2063
2064VimDialog::VimDialog(int type, const char *title, const char *message,
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002065 const char *buttons, int dfltbutton, const char *textfield, int ex_cmd)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002066: BWindow(kDefaultRect, title, B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL,
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002067 B_NOT_CLOSABLE | B_NOT_RESIZABLE |
2068 B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_ASYNCHRONOUS_CONTROLS)
2069 , fDialogSem(-1)
2070 , fDialogValue(dfltbutton)
2071 , fMessageView(NULL)
2072 , fInputControl(NULL)
2073 , fInputValue(textfield)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002074{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002075 // master view
2076 VimDialog::View* view = new VimDialog::View(Bounds());
2077 if (view == NULL)
2078 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002079
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002080 if (title == NULL)
2081 SetTitle("Vim " VIM_VERSION_MEDIUM);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002082
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002083 AddChild(view);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002084
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002085 // icon
2086 view->InitIcon(type);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002087
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002088 // buttons
2089 int32 which = 1;
2090 float maxButtonWidth = 0;
2091 float maxButtonHeight = 0;
2092 float buttonsWidth = 0;
2093 float buttonsHeight = 0;
2094 BString strButtons(buttons);
2095 strButtons.RemoveAll("&");
2096 do {
2097 int32 end = strButtons.FindFirst('\n');
2098 if (end != B_ERROR)
2099 strButtons.SetByteAt(end, '\0');
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002100
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002101 BButton *button = _CreateButton(which++, strButtons.String());
2102 view->AddChild(button);
2103 fButtonsList.AddItem(button);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002104
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002105 maxButtonWidth = max_c(maxButtonWidth, button->Bounds().Width());
2106 maxButtonHeight = max_c(maxButtonHeight, button->Bounds().Height());
2107 buttonsWidth += button->Bounds().Width();
2108 buttonsHeight += button->Bounds().Height();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002109
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002110 if (end == B_ERROR)
2111 break;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002112
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002113 strButtons.Remove(0, end + 1);
2114 } while (true);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002115
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002116 int32 buttonsCount = fButtonsList.CountItems();
2117 buttonsWidth += kVimDialogButtonsSpacingX * (buttonsCount - 1);
2118 buttonsHeight += kVimDialogButtonsSpacingY * (buttonsCount - 1);
2119 float dialogWidth = buttonsWidth + kVimDialogIconStripeWidth +
2120 kVimDialogSpacingX * 2;
2121 float dialogHeight = maxButtonHeight + kVimDialogSpacingY * 3;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002122
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002123 // Check 'v' flag in 'guioptions': vertical button placement.
2124 bool vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL) ||
2125 dialogWidth >= gui.vimWindow->Bounds().Width();
2126 if (vertical) {
2127 dialogWidth -= buttonsWidth;
2128 dialogWidth += maxButtonWidth;
2129 dialogHeight -= maxButtonHeight;
2130 dialogHeight += buttonsHeight;
2131 }
2132
2133 dialogWidth = max_c(dialogWidth, kVimDialogMinimalWidth);
2134
2135 // message view
2136 BRect rect(0, 0, dialogWidth, 0);
2137 rect.left += kVimDialogIconStripeWidth + 16 + kVimDialogSpacingX;
2138 rect.top += kVimDialogSpacingY;
2139 rect.right -= kVimDialogSpacingX;
2140 rect.bottom = rect.top;
2141 fMessageView = new BTextView(rect, "_tv_", rect.OffsetByCopy(B_ORIGIN),
2142 B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW);
2143
2144 fMessageView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
2145 rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR);
2146 fMessageView->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor);
2147 fMessageView->SetText(message);
2148 fMessageView->MakeEditable(false);
2149 fMessageView->MakeSelectable(false);
2150 fMessageView->SetWordWrap(true);
2151 AddChild(fMessageView);
2152
2153 float messageHeight = fMessageView->TextHeight(0, fMessageView->CountLines());
2154 fMessageView->ResizeBy(0, messageHeight);
2155 fMessageView->SetTextRect(BRect(0, 0, rect.Width(), messageHeight));
2156
2157 dialogHeight += messageHeight;
2158
2159 // input view
2160 if (fInputValue != NULL) {
2161 rect.top =
2162 rect.bottom += messageHeight + kVimDialogSpacingY;
2163 fInputControl = new BTextControl(rect, "_iv_", NULL, fInputValue, NULL,
2164 B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE | B_PULSE_NEEDED);
2165 fInputControl->TextView()->SetText(fInputValue);
2166 fInputControl->TextView()->SetWordWrap(false);
2167 AddChild(fInputControl);
2168
2169 float width = 0.f, height = 0.f;
2170 fInputControl->GetPreferredSize(&width, &height);
2171 fInputControl->MakeFocus(true);
2172
2173 dialogHeight += height + kVimDialogSpacingY * 1.5;
2174 }
2175
2176 dialogHeight = max_c(dialogHeight, kVimDialogMinimalHeight);
2177
2178 ResizeTo(dialogWidth, dialogHeight);
2179 MoveTo((gui.vimWindow->Bounds().Width() - dialogWidth) / 2,
2180 (gui.vimWindow->Bounds().Height() - dialogHeight) / 2);
2181
2182 // adjust layout of buttons
2183 float buttonWidth = max_c(maxButtonWidth, rect.Width() * 0.66);
2184 BPoint origin(dialogWidth, dialogHeight);
2185 origin.x -= kVimDialogSpacingX + (vertical ? buttonWidth : buttonsWidth);
2186 origin.y -= kVimDialogSpacingY + (vertical ? buttonsHeight : maxButtonHeight);
2187
2188 for (int32 i = 0 ; i < buttonsCount; i++) {
2189 BButton *button = (BButton*)fButtonsList.ItemAt(i);
2190 button->MoveTo(origin);
2191 if (vertical) {
2192 origin.y += button->Frame().Height() + kVimDialogButtonsSpacingY;
2193 button->ResizeTo(buttonWidth, button->Frame().Height());
2194 } else
2195 origin.x += button->Frame().Width() + kVimDialogButtonsSpacingX;
2196
2197 if (dfltbutton == i + 1) {
2198 button->MakeDefault(true);
2199 button->MakeFocus(fInputControl == NULL);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002200 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002201 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002202}
2203
2204VimDialog::~VimDialog()
2205{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002206 if (fDialogSem > B_OK)
2207 delete_sem(fDialogSem);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002208}
2209
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002210 int
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002211VimDialog::Go()
2212{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002213 fDialogSem = create_sem(0, "VimDialogSem");
2214 if (fDialogSem < B_OK) {
2215 Quit();
2216 return fDialogValue;
2217 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002218
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002219 Show();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002220
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002221 while (acquire_sem(fDialogSem) == B_INTERRUPTED);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002222
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002223 int retValue = fDialogValue;
2224 if (fInputValue != NULL)
2225 vim_strncpy((char_u*)fInputValue, (char_u*)fInputControl->Text(), IOSIZE - 1);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002226
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002227 if (Lock())
2228 Quit();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002229
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002230 return retValue;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002231}
2232
2233void VimDialog::MessageReceived(BMessage *msg)
2234{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002235 int32 which = 0;
2236 if (msg->what != kVimDialogButtonMsg ||
2237 msg->FindInt32("which", &which) != B_OK)
2238 return BWindow::MessageReceived(msg);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002239
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002240 fDialogValue = which;
2241 delete_sem(fDialogSem);
2242 fDialogSem = -1;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002243}
2244
2245BButton* VimDialog::_CreateButton(int32 which, const char* label)
2246{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002247 BMessage *message = new BMessage(kVimDialogButtonMsg);
2248 message->AddInt32("which", which);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002249
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002250 BRect rect(0, 0, 0, 0);
2251 BString name;
2252 name << "_b" << which << "_";
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002253
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002254 BButton* button = new BButton(rect, name.String(), label, message,
2255 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002256
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002257 float width = 0.f, height = 0.f;
2258 button->GetPreferredSize(&width, &height);
2259 button->ResizeTo(width, height);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002260
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002261 return button;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002262}
2263
2264VimDialog::View::View(BRect frame)
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002265 : BView(frame, "VimDialogView", B_FOLLOW_ALL_SIDES, B_WILL_DRAW),
2266 fIconBitmap(NULL)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002267{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002268 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002269}
2270
2271VimDialog::View::~View()
2272{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002273 delete fIconBitmap;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002274}
2275
2276void VimDialog::View::Draw(BRect updateRect)
2277{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002278 BRect stripeRect = Bounds();
2279 stripeRect.right = kVimDialogIconStripeWidth;
2280 SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT));
2281 FillRect(stripeRect);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002282
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002283 if (fIconBitmap == NULL)
2284 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002285
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002286 SetDrawingMode(B_OP_ALPHA);
2287 SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
2288 DrawBitmapAsync(fIconBitmap, BPoint(18, 6));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002289}
2290
2291void VimDialog::View::InitIcon(int32 type)
2292{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002293 if (type == VIM_GENERIC)
2294 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002295
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002296 BPath path;
2297 status_t status = find_directory(B_BEOS_SERVERS_DIRECTORY, &path);
2298 if (status != B_OK) {
2299 fprintf(stderr, "Cannot retrieve app info:%s\n", strerror(status));
2300 return;
2301 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002302
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002303 path.Append("app_server");
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002304
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002305 BFile file(path.Path(), O_RDONLY);
2306 if (file.InitCheck() != B_OK) {
2307 fprintf(stderr, "App file assignment failed:%s\n",
2308 strerror(file.InitCheck()));
2309 return;
2310 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002311
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002312 BResources resources(&file);
2313 if (resources.InitCheck() != B_OK) {
2314 fprintf(stderr, "App server resources assignment failed:%s\n",
2315 strerror(resources.InitCheck()));
2316 return;
2317 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002318
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002319 const char *name = "";
2320 switch(type) {
2321 case VIM_ERROR: name = "stop"; break;
2322 case VIM_WARNING: name = "warn"; break;
2323 case VIM_INFO: name = "info"; break;
2324 case VIM_QUESTION: name = "idea"; break;
2325 default: return;
2326 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002327
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002328 int32 iconSize = 32;
2329 fIconBitmap = new BBitmap(BRect(0, 0, iconSize - 1, iconSize - 1), 0, B_RGBA32);
2330 if (fIconBitmap == NULL || fIconBitmap->InitCheck() != B_OK) {
2331 fprintf(stderr, "Icon bitmap allocation failed:%s\n",
2332 (fIconBitmap == NULL) ? "null" : strerror(fIconBitmap->InitCheck()));
2333 return;
2334 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002335
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002336 size_t size = 0;
2337 const uint8* iconData = NULL;
2338 // try vector icon first?
2339 iconData = (const uint8*)resources.LoadResource(B_VECTOR_ICON_TYPE, name, &size);
2340 if (iconData != NULL && BIconUtils::GetVectorIcon(iconData, size, fIconBitmap) == B_OK)
2341 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002342
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002343 // try bitmap icon now
2344 iconData = (const uint8*)resources.LoadResource(B_LARGE_ICON_TYPE, name, &size);
2345 if (iconData == NULL) {
2346 fprintf(stderr, "Bitmap icon resource not found\n");
2347 delete fIconBitmap;
2348 fIconBitmap = NULL;
2349 return;
2350 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002351
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002352 if (fIconBitmap->ColorSpace() != B_CMAP8)
2353 BIconUtils::ConvertFromCMAP8(iconData, iconSize, iconSize, iconSize, fIconBitmap);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002354}
2355
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002356const unsigned int kVimDialogOKButtonMsg = 'FDOK';
2357const unsigned int kVimDialogCancelButtonMsg = 'FDCN';
2358const unsigned int kVimDialogSizeInputMsg = 'SICH';
2359const unsigned int kVimDialogFamilySelectMsg = 'MSFM';
2360const unsigned int kVimDialogStyleSelectMsg = 'MSST';
2361const unsigned int kVimDialogSizeSelectMsg = 'MSSZ';
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002362
2363VimSelectFontDialog::VimSelectFontDialog(font_family* family, font_style* style, float* size)
2364: BWindow(kDefaultRect, "Font Selection", B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL,
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002365 B_NOT_CLOSABLE | B_NOT_RESIZABLE |
2366 B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_ASYNCHRONOUS_CONTROLS)
2367 , fStatus(B_NO_INIT)
2368 , fDialogSem(-1)
2369 , fDialogValue(false)
2370 , fFamily(family)
2371 , fStyle(style)
2372 , fSize(size)
2373 , fFontSize(*size)
2374 , fPreview(0)
2375 , fFamiliesList(0)
2376 , fStylesList(0)
2377 , fSizesList(0)
2378 , fSizesInput(0)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002379{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002380 strncpy(fFontFamily, *family, B_FONT_FAMILY_LENGTH);
2381 strncpy(fFontStyle, *style, B_FONT_STYLE_LENGTH);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002382
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002383 // "client" area view
2384 BBox *clientBox = new BBox(Bounds(), B_EMPTY_STRING, B_FOLLOW_ALL_SIDES,
2385 B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP | B_PULSE_NEEDED,
2386 B_PLAIN_BORDER);
2387 AddChild(clientBox);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002388
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002389 // client view
2390 BRect RC = clientBox->Bounds();
2391 RC.InsetBy(kVimDialogSpacingX, kVimDialogSpacingY);
2392 BRect rc(RC.LeftTop(), RC.LeftTop());
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002393
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002394 // at first create all controls
2395 fPreview = new BStringView(rc, "preview", "DejaVu Sans Mono");
2396 clientBox->AddChild(fPreview);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002397
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002398 BBox* boxDivider = new BBox(rc, B_EMPTY_STRING,
2399 B_FOLLOW_NONE, B_WILL_DRAW, B_FANCY_BORDER);
2400 clientBox->AddChild(boxDivider);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002401
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002402 BStringView *labelFamily = new BStringView(rc, "labelFamily", "Family:");
2403 clientBox->AddChild(labelFamily);
2404 labelFamily->ResizeToPreferred();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002405
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002406 BStringView *labelStyle = new BStringView(rc, "labelStyle", "Style:");
2407 clientBox->AddChild(labelStyle);
2408 labelStyle->ResizeToPreferred();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002409
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002410 BStringView *labelSize = new BStringView(rc, "labelSize", "Size:");
2411 clientBox->AddChild(labelSize);
2412 labelSize->ResizeToPreferred();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002413
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002414 fFamiliesList = new BListView(rc, "listFamily",
2415 B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES);
2416 BScrollView *scrollFamilies = new BScrollView("scrollFamily",
2417 fFamiliesList, B_FOLLOW_LEFT_RIGHT, 0, false, true);
2418 clientBox->AddChild(scrollFamilies);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002419
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002420 fStylesList= new BListView(rc, "listStyles",
2421 B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES);
2422 BScrollView *scrollStyles = new BScrollView("scrollStyle",
2423 fStylesList, B_FOLLOW_LEFT_RIGHT, 0, false, true);
2424 clientBox->AddChild(scrollStyles);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002425
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002426 fSizesInput = new BTextControl(rc, "inputSize", NULL, "???",
2427 new BMessage(kVimDialogSizeInputMsg));
2428 clientBox->AddChild(fSizesInput);
2429 fSizesInput->ResizeToPreferred();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002430
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002431 fSizesList = new BListView(rc, "listSizes",
2432 B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES);
2433 BScrollView *scrollSizes = new BScrollView("scrollSize",
2434 fSizesList, B_FOLLOW_LEFT_RIGHT, 0, false, true);
2435 clientBox->AddChild(scrollSizes);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002436
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002437 BButton *buttonOK = new BButton(rc, "buttonOK", "OK",
2438 new BMessage(kVimDialogOKButtonMsg));
2439 clientBox->AddChild(buttonOK);
2440 buttonOK->ResizeToPreferred();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002441
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002442 BButton *buttonCancel = new BButton(rc, "buttonCancel", "Cancel",
2443 new BMessage(kVimDialogCancelButtonMsg));
2444 clientBox->AddChild(buttonCancel);
2445 buttonCancel->ResizeToPreferred();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002446
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002447 // layout controls
2448 float lineHeight = labelFamily->Bounds().Height();
2449 float previewHeight = lineHeight * 3;
2450 float offsetYLabels = previewHeight + kVimDialogSpacingY;
2451 float offsetYLists = offsetYLabels + lineHeight + kVimDialogSpacingY / 2;
2452 float offsetYSizes = offsetYLists + fSizesInput->Bounds().Height() + kVimDialogSpacingY / 2;
2453 float listsHeight = lineHeight * 9;
2454 float offsetYButtons = offsetYLists + listsHeight + kVimDialogSpacingY;
2455 float maxControlsHeight = offsetYButtons + buttonOK->Bounds().Height();
2456 float familiesWidth = labelFamily->Bounds().Width() * 5;
2457 float offsetXStyles = familiesWidth + kVimDialogSpacingX;
2458 float stylesWidth = labelStyle->Bounds().Width() * 4;
2459 float offsetXSizes = offsetXStyles + stylesWidth + kVimDialogSpacingX;
2460 float sizesWidth = labelSize->Bounds().Width() * 2;
2461 float maxControlsWidth = offsetXSizes + sizesWidth;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002462
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002463 ResizeTo(maxControlsWidth + kVimDialogSpacingX * 2,
2464 maxControlsHeight + kVimDialogSpacingY * 2);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002465
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002466 BRect rcVim = gui.vimWindow->Frame();
2467 MoveTo(rcVim.left + (rcVim.Width() - Frame().Width()) / 2,
2468 rcVim.top + (rcVim.Height() - Frame().Height()) / 2);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002469
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002470 fPreview->ResizeTo(maxControlsWidth, previewHeight);
2471 fPreview->SetAlignment(B_ALIGN_CENTER);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002472
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002473 boxDivider->MoveBy(0.f, previewHeight + kVimDialogSpacingY / 2);
2474 boxDivider->ResizeTo(maxControlsWidth, 1.f);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002475
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002476 labelFamily->MoveBy(0.f, offsetYLabels);
2477 labelStyle->MoveBy(offsetXStyles, offsetYLabels);
2478 labelSize->MoveBy(offsetXSizes, offsetYLabels);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002479
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002480 // text control alignment issues
2481 float insetX = fSizesInput->TextView()->Bounds().Width() - fSizesInput->Bounds().Width();
2482 float insetY = fSizesInput->TextView()->Bounds().Width() - fSizesInput->Bounds().Width();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002483
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002484 scrollFamilies->MoveBy(0.f, offsetYLists);
2485 scrollStyles->MoveBy(offsetXStyles, offsetYLists);
2486 fSizesInput->MoveBy(offsetXSizes + insetX / 2, offsetYLists + insetY / 2);
2487 scrollSizes->MoveBy(offsetXSizes, offsetYSizes);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002488
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002489 fSizesInput->SetAlignment(B_ALIGN_CENTER, B_ALIGN_CENTER);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002490
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002491 scrollFamilies->ResizeTo(familiesWidth, listsHeight);
2492 scrollStyles->ResizeTo(stylesWidth, listsHeight);
2493 fSizesInput->ResizeTo(sizesWidth, fSizesInput->Bounds().Height());
2494 scrollSizes->ResizeTo(sizesWidth,
2495 listsHeight - (offsetYSizes - offsetYLists));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002496
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002497 buttonOK->MoveBy(maxControlsWidth - buttonOK->Bounds().Width(), offsetYButtons);
2498 buttonCancel->MoveBy(maxControlsWidth - buttonOK->Bounds().Width()
2499 - buttonCancel->Bounds().Width() - kVimDialogSpacingX, offsetYButtons);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002500
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002501 // fill lists
2502 int selIndex = -1;
2503 int count = count_font_families();
2504 for (int i = 0; i < count; i++) {
2505 font_family family;
2506 if (get_font_family(i, &family ) == B_OK) {
2507 fFamiliesList->AddItem(new BStringItem((const char*)family));
2508 if (strncmp(family, fFontFamily, B_FONT_FAMILY_LENGTH) == 0)
2509 selIndex = i;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002510 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002511 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002512
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002513 if (selIndex >= 0) {
2514 fFamiliesList->Select(selIndex);
2515 fFamiliesList->ScrollToSelection();
2516 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002517
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002518 _UpdateFontStyles();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002519
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002520 selIndex = -1;
2521 for (int size = 8, index = 0; size <= 18; size++, index++) {
2522 BString str;
2523 str << size;
2524 fSizesList->AddItem(new BStringItem(str));
2525 if (size == fFontSize)
2526 selIndex = index;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002527
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002528 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002529
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002530 if (selIndex >= 0) {
2531 fSizesList->Select(selIndex);
2532 fSizesList->ScrollToSelection();
2533 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002534
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002535 fFamiliesList->SetSelectionMessage(new BMessage(kVimDialogFamilySelectMsg));
2536 fStylesList->SetSelectionMessage(new BMessage(kVimDialogStyleSelectMsg));
2537 fSizesList->SetSelectionMessage(new BMessage(kVimDialogSizeSelectMsg));
2538 fSizesInput->SetModificationMessage(new BMessage(kVimDialogSizeInputMsg));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002539
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002540 _UpdateSizeInputPreview();
2541 _UpdateFontPreview();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002542
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002543 fStatus = B_OK;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002544}
2545
2546VimSelectFontDialog::~VimSelectFontDialog()
2547{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002548 _CleanList(fFamiliesList);
2549 _CleanList(fStylesList);
2550 _CleanList(fSizesList);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002551
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002552 if (fDialogSem > B_OK)
2553 delete_sem(fDialogSem);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002554}
2555
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002556 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002557VimSelectFontDialog::_CleanList(BListView* list)
2558{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002559 while (0 < list->CountItems())
2560 delete (dynamic_cast<BStringItem*>(list->RemoveItem((int32)0)));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002561}
2562
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002563 bool
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002564VimSelectFontDialog::Go()
2565{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002566 if (fStatus != B_OK) {
2567 Quit();
2568 return NOFONT;
2569 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002570
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002571 fDialogSem = create_sem(0, "VimFontSelectDialogSem");
2572 if (fDialogSem < B_OK) {
2573 Quit();
2574 return fDialogValue;
2575 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002576
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002577 Show();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002578
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002579 while (acquire_sem(fDialogSem) == B_INTERRUPTED);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002580
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002581 bool retValue = fDialogValue;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002582
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002583 if (Lock())
2584 Quit();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002585
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002586 return retValue;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002587}
2588
2589
2590void VimSelectFontDialog::_UpdateFontStyles()
2591{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002592 _CleanList(fStylesList);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002593
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002594 int32 selIndex = -1;
2595 int32 count = count_font_styles(fFontFamily);
2596 for (int32 i = 0; i < count; i++) {
2597 font_style style;
2598 uint32 flags = 0;
2599 if (get_font_style(fFontFamily, i, &style, &flags) == B_OK) {
2600 fStylesList->AddItem(new BStringItem((const char*)style));
2601 if (strncmp(style, fFontStyle, B_FONT_STYLE_LENGTH) == 0)
2602 selIndex = i;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002603 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002604 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002605
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002606 if (selIndex >= 0) {
2607 fStylesList->Select(selIndex);
2608 fStylesList->ScrollToSelection();
2609 } else
2610 fStylesList->Select(0);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002611}
2612
2613
2614void VimSelectFontDialog::_UpdateSizeInputPreview()
2615{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002616 char buf[10] = {0};
2617 vim_snprintf(buf, sizeof(buf), (char*)"%.0f", fFontSize);
2618 fSizesInput->SetText(buf);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002619}
2620
2621
2622void VimSelectFontDialog::_UpdateFontPreview()
2623{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002624 BFont font;
2625 fPreview->GetFont(&font);
2626 font.SetSize(fFontSize);
2627 font.SetFamilyAndStyle(fFontFamily, fFontStyle);
2628 fPreview->SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002629
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002630 BString str;
2631 str << fFontFamily << " " << fFontStyle << ", " << (int)fFontSize << " pt.";
2632 fPreview->SetText(str);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002633}
2634
2635
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002636 bool
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002637VimSelectFontDialog::_UpdateFromListItem(BListView* list, char* text, int textSize)
2638{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002639 int32 index = list->CurrentSelection();
2640 if (index < 0)
2641 return false;
2642 BStringItem* item = (BStringItem*)list->ItemAt(index);
2643 if (item == NULL)
2644 return false;
2645 strncpy(text, item->Text(), textSize);
2646 return true;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002647}
2648
2649
2650void VimSelectFontDialog::MessageReceived(BMessage *msg)
2651{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002652 switch (msg->what) {
2653 case kVimDialogOKButtonMsg:
2654 strncpy(*fFamily, fFontFamily, B_FONT_FAMILY_LENGTH);
2655 strncpy(*fStyle, fFontStyle, B_FONT_STYLE_LENGTH);
2656 *fSize = fFontSize;
2657 fDialogValue = true;
2658 case kVimDialogCancelButtonMsg:
2659 delete_sem(fDialogSem);
2660 fDialogSem = -1;
2661 return;
2662 case B_KEY_UP:
2663 {
2664 int32 key = 0;
2665 if (msg->FindInt32("raw_char", &key) == B_OK
2666 && key == B_ESCAPE) {
2667 delete_sem(fDialogSem);
2668 fDialogSem = -1;
2669 }
2670 }
2671 break;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002672
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002673 case kVimDialogFamilySelectMsg:
2674 if (_UpdateFromListItem(fFamiliesList,
2675 fFontFamily, B_FONT_FAMILY_LENGTH)) {
2676 _UpdateFontStyles();
2677 _UpdateFontPreview();
2678 }
2679 break;
2680 case kVimDialogStyleSelectMsg:
2681 if (_UpdateFromListItem(fStylesList,
2682 fFontStyle, B_FONT_STYLE_LENGTH))
2683 _UpdateFontPreview();
2684 break;
2685 case kVimDialogSizeSelectMsg:
2686 {
2687 char buf[10] = {0};
2688 if (_UpdateFromListItem(fSizesList, buf, sizeof(buf))) {
2689 float size = atof(buf);
2690 if (size > 0.f) {
2691 fFontSize = size;
2692 _UpdateSizeInputPreview();
2693 _UpdateFontPreview();
2694 }
2695 }
2696 }
2697 break;
2698 case kVimDialogSizeInputMsg:
2699 {
2700 float size = atof(fSizesInput->Text());
2701 if (size > 0.f) {
2702 fFontSize = size;
2703 _UpdateFontPreview();
2704 }
2705 }
2706 break;
2707 default:
2708 break;
2709 }
2710 return BWindow::MessageReceived(msg);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002711}
2712
2713#endif // FEAT_GUI_DIALOG
2714
2715#ifdef FEAT_TOOLBAR
2716
2717// some forward declaration required by toolbar functions...
2718static BMessage * MenuMessage(vimmenu_T *menu);
2719
2720VimToolbar::VimToolbar(BRect frame, const char *name) :
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002721 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 +01002722{
2723}
2724
2725VimToolbar::~VimToolbar()
2726{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002727 int32 count = fButtonsList.CountItems();
2728 for (int32 i = 0; i < count; i++)
2729 delete (BPictureButton*)fButtonsList.ItemAt(i);
2730 fButtonsList.MakeEmpty();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002731
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002732 delete normalButtonsBitmap;
2733 delete grayedButtonsBitmap;
2734 normalButtonsBitmap = NULL;
2735 grayedButtonsBitmap = NULL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002736}
2737
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002738 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002739VimToolbar::AttachedToWindow()
2740{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002741 BBox::AttachedToWindow();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002742
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002743 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002744}
2745
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002746 float
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002747VimToolbar::ToolbarHeight() const
2748{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002749 float size = NULL == normalButtonsBitmap ? 18. : normalButtonsBitmap->Bounds().Height();
2750 return size + ToolbarMargin * 2 + ButtonMargin * 2 + 1;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002751}
2752
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002753 bool
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002754VimToolbar::ModifyBitmapToGrayed(BBitmap *bitmap)
2755{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002756 float height = bitmap->Bounds().Height();
2757 float width = bitmap->Bounds().Width();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002758
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002759 rgb_color *bits = (rgb_color*)bitmap->Bits();
2760 int32 pixels = bitmap->BitsLength() / 4;
2761 for (int32 i = 0; i < pixels; i++) {
2762 bits[i].red = bits[i].green =
2763 bits[i].blue = ((uint32)bits[i].red + bits[i].green + bits[i].blue) / 3;
2764 bits[i].alpha /= 4;
2765 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002766
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002767 return true;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002768}
2769
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002770 bool
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002771VimToolbar::PrepareButtonBitmaps()
2772{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002773 // first try to load potentially customized $VIRUNTIME/bitmaps/builtin-tools.png
2774 normalButtonsBitmap = LoadVimBitmap("builtin-tools.png");
2775 if (normalButtonsBitmap == NULL)
2776 // customized not found? dig application resources for "builtin-tools" one
2777 normalButtonsBitmap = BTranslationUtils::GetBitmap(B_PNG_FORMAT, "builtin-tools");
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002778
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002779 if (normalButtonsBitmap == NULL)
2780 return false;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002781
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002782 BMessage archive;
2783 normalButtonsBitmap->Archive(&archive);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002784
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002785 grayedButtonsBitmap = new BBitmap(&archive);
2786 if (grayedButtonsBitmap == NULL)
2787 return false;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002788
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002789 // modify grayed bitmap
2790 ModifyBitmapToGrayed(grayedButtonsBitmap);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002791
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002792 return true;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002793}
2794
2795BBitmap *VimToolbar::LoadVimBitmap(const char* fileName)
2796{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002797 BBitmap *bitmap = NULL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002798
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002799 int mustfree = 0;
2800 char_u* runtimePath = vim_getenv((char_u*)"VIMRUNTIME", &mustfree);
2801 if (runtimePath != NULL && fileName != NULL) {
2802 BString strPath((char*)runtimePath);
2803 strPath << "/bitmaps/" << fileName;
2804 bitmap = BTranslationUtils::GetBitmap(strPath.String());
2805 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002806
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002807 if (mustfree)
2808 vim_free(runtimePath);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002809
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002810 return bitmap;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002811}
2812
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002813 bool
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002814VimToolbar::GetPictureFromBitmap(BPicture *pictureTo, int32 index, BBitmap *bitmapFrom, bool pressed)
2815{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002816 float size = bitmapFrom->Bounds().Height() + 1.;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002817
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002818 BView view(BRect(0, 0, size, size), "", 0, 0);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002819
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002820 AddChild(&view);
2821 view.BeginPicture(pictureTo);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002822
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002823 view.SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
2824 view.FillRect(view.Bounds());
2825 view.SetDrawingMode(B_OP_OVER);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002826
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002827 BRect source(0, 0, size - 1, size - 1);
2828 BRect destination(source);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002829
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002830 source.OffsetBy(size * index, 0);
2831 destination.OffsetBy(ButtonMargin, ButtonMargin);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002832
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002833 view.DrawBitmap(bitmapFrom, source, destination);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002834
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002835 if (pressed) {
2836 rgb_color shineColor = ui_color(B_SHINE_COLOR);
2837 rgb_color shadowColor = ui_color(B_SHADOW_COLOR);
2838 size += ButtonMargin * 2 - 1;
2839 view.BeginLineArray(4);
2840 view.AddLine(BPoint(0, 0), BPoint(size, 0), shadowColor);
2841 view.AddLine(BPoint(size, 0), BPoint(size, size), shineColor);
2842 view.AddLine(BPoint(size, size), BPoint(0, size), shineColor);
2843 view.AddLine(BPoint(0, size), BPoint(0, 0), shadowColor);
2844 view.EndLineArray();
2845 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002846
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002847 view.EndPicture();
2848 RemoveChild(&view);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002849
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002850 return true;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002851}
2852
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002853 bool
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002854VimToolbar::AddButton(int32 index, vimmenu_T *menu)
2855{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002856 BPictureButton *button = NULL;
2857 if (!menu_is_separator(menu->name)) {
2858 float size = normalButtonsBitmap ?
2859 normalButtonsBitmap->Bounds().Height() + 1. + ButtonMargin * 2 : 18.;
2860 BRect frame(0, 0, size, size);
2861 BPicture pictureOn;
2862 BPicture pictureOff;
2863 BPicture pictureGray;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002864
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002865 if (menu->iconfile == NULL && menu->iconidx >= 0 && normalButtonsBitmap) {
2866 GetPictureFromBitmap(&pictureOn, menu->iconidx, normalButtonsBitmap, true);
2867 GetPictureFromBitmap(&pictureOff, menu->iconidx, normalButtonsBitmap, false);
2868 GetPictureFromBitmap(&pictureGray, menu->iconidx, grayedButtonsBitmap, false);
2869 } else {
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002870
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002871 char_u buffer[MAXPATHL] = {0};
2872 BBitmap *bitmap = NULL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002873
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002874 if (menu->iconfile) {
2875 gui_find_iconfile(menu->iconfile, buffer, (char*)"png");
2876 bitmap = BTranslationUtils::GetBitmap((char*)buffer);
2877 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002878
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002879 if (bitmap == NULL && gui_find_bitmap(menu->name, buffer, (char*)"png") == OK)
2880 bitmap = BTranslationUtils::GetBitmap((char*)buffer);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002881
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002882 if (bitmap == NULL)
2883 bitmap = new BBitmap(BRect(0, 0, size, size), B_RGB32);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002884
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002885 GetPictureFromBitmap(&pictureOn, 0, bitmap, true);
2886 GetPictureFromBitmap(&pictureOff, 0, bitmap, false);
2887 ModifyBitmapToGrayed(bitmap);
2888 GetPictureFromBitmap(&pictureGray, 0, bitmap, false);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002889
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002890 delete bitmap;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002891 }
2892
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002893 button = new BPictureButton(frame, (char*)menu->name,
2894 &pictureOff, &pictureOn, MenuMessage(menu));
2895
2896 button->SetDisabledOn(&pictureGray);
2897 button->SetDisabledOff(&pictureGray);
2898
2899 button->SetTarget(gui.vimTextArea);
2900
2901 AddChild(button);
2902
2903 menu->button = button;
2904 }
2905
2906 bool result = fButtonsList.AddItem(button, index);
2907 InvalidateLayout();
2908 return result;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002909}
2910
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002911 bool
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002912VimToolbar::RemoveButton(vimmenu_T *menu)
2913{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002914 if (menu->button) {
2915 if (fButtonsList.RemoveItem(menu->button)) {
2916 delete menu->button;
2917 menu->button = NULL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002918 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002919 }
2920 return true;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002921}
2922
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002923 bool
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002924VimToolbar::GrayButton(vimmenu_T *menu, int grey)
2925{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002926 if (menu->button) {
2927 int32 index = fButtonsList.IndexOf(menu->button);
2928 if (index >= 0)
2929 menu->button->SetEnabled(grey ? false : true);
2930 }
2931 return true;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002932}
2933
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002934 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002935VimToolbar::InvalidateLayout()
2936{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002937 int32 offset = ToolbarMargin;
2938 int32 count = fButtonsList.CountItems();
2939 for (int32 i = 0; i < count; i++) {
2940 BPictureButton *button = (BPictureButton *)fButtonsList.ItemAt(i);
2941 if (button) {
2942 button->MoveTo(offset, ToolbarMargin);
2943 offset += button->Bounds().Width() + ToolbarMargin;
2944 } else
2945 offset += ToolbarMargin * 3;
2946 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002947}
2948
2949#endif /*FEAT_TOOLBAR*/
2950
2951#if defined(FEAT_GUI_TABLINE)
2952
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002953 float
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002954VimTabLine::TablineHeight() const
2955{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002956// float size = NULL == normalButtonsBitmap ? 18. : normalButtonsBitmap->Bounds().Height();
2957// return size + ToolbarMargin * 2 + ButtonMargin * 2 + 1;
2958 return TabHeight(); // + ToolbarMargin;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002959}
2960
2961void
2962VimTabLine::MouseDown(BPoint point)
2963{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002964 if (!gui_mch_showing_tabline())
2965 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002966
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002967 BMessage *m = Window()->CurrentMessage();
2968 assert(m);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002969
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002970 int32 buttons = 0;
2971 m->FindInt32("buttons", &buttons);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002972
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002973 int32 clicks = 0;
2974 m->FindInt32("clicks", &clicks);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002975
Bram Moolenaarb52575f2020-04-24 22:16:13 +02002976 int index = 0; // 0 means here - no tab found
2977 for (int i = 0; i < CountTabs(); i++) {
2978 if (TabFrame(i).Contains(point)) {
2979 index = i + 1; // indexes are 1-based
2980 break;
2981 }
2982 }
2983
2984 int event = -1;
2985
2986 if ((buttons & B_PRIMARY_MOUSE_BUTTON) && clicks > 1)
2987 // left button double click on - create new tab
2988 event = TABLINE_MENU_NEW;
2989
2990 else if (buttons & B_TERTIARY_MOUSE_BUTTON)
2991 // middle button click - close the pointed tab
2992 // or create new one in case empty space
2993 event = index > 0 ? TABLINE_MENU_CLOSE : TABLINE_MENU_NEW;
2994
2995 else if (buttons & B_SECONDARY_MOUSE_BUTTON) {
2996 // right button click - show context menu
2997 BPopUpMenu* popUpMenu = new BPopUpMenu("tabLineContextMenu", false, false);
2998 popUpMenu->AddItem(new BMenuItem(_("Close tabi R"), new BMessage(TABLINE_MENU_CLOSE)));
2999 popUpMenu->AddItem(new BMenuItem(_("New tab T"), new BMessage(TABLINE_MENU_NEW)));
3000 popUpMenu->AddItem(new BMenuItem(_("Open tab..."), new BMessage(TABLINE_MENU_OPEN)));
3001
3002 ConvertToScreen(&point);
3003 BMenuItem* item = popUpMenu->Go(point);
3004 if (item != NULL) {
3005 event = item->Command();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003006 }
3007
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003008 delete popUpMenu;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003009
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003010 } else {
3011 // default processing
3012 BTabView::MouseDown(point);
3013 return;
3014 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003015
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003016 if (event < 0)
3017 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003018
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003019 VimTablineMenuMsg tmm;
3020 tmm.index = index;
3021 tmm.event = event;
3022 write_port(gui.vdcmp, VimMsg::TablineMenu, &tmm, sizeof(tmm));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003023}
3024
3025void
3026VimTabLine::VimTab::Select(BView* owner)
3027{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003028 BTab::Select(owner);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003029
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003030 VimTabLine *tabLine = gui.vimForm->TabLine();
3031 if (tabLine != NULL) {
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003032
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003033 int32 i = 0;
3034 for (; i < tabLine->CountTabs(); i++)
3035 if (this == tabLine->TabAt(i))
3036 break;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003037
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003038// printf("%d:%d:%s\n", i, tabLine->CountTabs(), tabLine->TabAt(i)->Label());
3039 if (i < tabLine->CountTabs()) {
3040 VimTablineMsg tm;
3041 tm.index = i + 1;
3042 write_port(gui.vdcmp, VimMsg::Tabline, &tm, sizeof(tm));
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003043 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003044 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003045}
3046
3047#endif // defined(FEAT_GUI_TABLINE)
3048
3049// ---------------- ----------------
3050
3051// some global variables
3052static char appsig[] = "application/x-vnd.Haiku-Vim-8";
3053key_map *keyMap;
3054char *keyMapChars;
3055int main_exitcode = 127;
3056
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003057 status_t
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003058gui_haiku_process_event(bigtime_t timeout)
3059{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003060 struct VimMsg vm;
3061 int32 what;
3062 ssize_t size;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003063
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003064 size = read_port_etc(gui.vdcmp, &what, &vm, sizeof(vm),
3065 B_TIMEOUT, timeout);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003066
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003067 if (size >= 0) {
3068 switch (what) {
3069 case VimMsg::Key:
3070 {
3071 char_u *string = vm.u.Key.chars;
3072 int len = vm.u.Key.length;
3073 if (len == 1 && string[0] == Ctrl_chr('C')) {
3074 trash_input_buf();
3075 got_int = TRUE;
3076 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003077
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003078 if (vm.u.Key.csi_escape)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003079#ifndef FEAT_MBYTE_IME
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003080 {
3081 int i;
3082 char_u buf[2];
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003083
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003084 for (i = 0; i < len; ++i)
3085 {
3086 add_to_input_buf(string + i, 1);
3087 if (string[i] == CSI)
3088 {
3089 // Turn CSI into K_CSI.
3090 buf[0] = KS_EXTRA;
3091 buf[1] = (int)KE_CSI;
3092 add_to_input_buf(buf, 2);
3093 }
3094 }
3095 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003096#else
Bram Moolenaar80a8d382020-05-03 22:57:32 +02003097 add_to_input_buf_csi(string, len);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003098#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003099 else
3100 add_to_input_buf(string, len);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003101 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003102 break;
3103 case VimMsg::Resize:
3104 gui_resize_shell(vm.u.NewSize.width, vm.u.NewSize.height);
3105 break;
3106 case VimMsg::ScrollBar:
3107 {
3108 /*
3109 * If loads of scroll messages queue up, use only the last
3110 * one. Always report when the scrollbar stops dragging.
3111 * This is not perfect yet anyway: these events are queued
3112 * yet again, this time in the keyboard input buffer.
3113 */
3114 int32 oldCount =
3115 atomic_add(&vm.u.Scroll.sb->scrollEventCount, -1);
3116 if (oldCount <= 1 || !vm.u.Scroll.stillDragging)
3117 gui_drag_scrollbar(vm.u.Scroll.sb->getGsb(),
3118 vm.u.Scroll.value, vm.u.Scroll.stillDragging);
3119 }
3120 break;
3121#if defined(FEAT_MENU)
3122 case VimMsg::Menu:
3123 gui_menu_cb(vm.u.Menu.guiMenu);
3124 break;
3125#endif
3126 case VimMsg::Mouse:
3127 {
3128 int32 oldCount;
3129 if (vm.u.Mouse.button == MOUSE_DRAG)
3130 oldCount =
3131 atomic_add(&gui.vimTextArea->mouseDragEventCount, -1);
3132 else
3133 oldCount = 0;
3134 if (oldCount <= 1)
3135 gui_send_mouse_event(vm.u.Mouse.button, vm.u.Mouse.x,
3136 vm.u.Mouse.y, vm.u.Mouse.repeated_click,
3137 vm.u.Mouse.modifiers);
3138 }
3139 break;
3140 case VimMsg::MouseMoved:
3141 {
3142 gui_mouse_moved(vm.u.MouseMoved.x, vm.u.MouseMoved.y);
3143 }
3144 break;
3145 case VimMsg::Focus:
3146 gui.in_focus = vm.u.Focus.active;
3147 // XXX Signal that scrollbar dragging has stopped?
3148 // This is needed because we don't get a MouseUp if
3149 // that happens while outside the window... :-(
3150 if (gui.dragged_sb) {
3151 gui.dragged_sb = SBAR_NONE;
3152 }
3153 // gui_update_cursor(TRUE, FALSE);
3154 break;
3155 case VimMsg::Refs:
3156 ::RefsReceived(vm.u.Refs.message, vm.u.Refs.changedir);
3157 break;
3158 case VimMsg::Tabline:
3159 send_tabline_event(vm.u.Tabline.index);
3160 break;
3161 case VimMsg::TablineMenu:
3162 send_tabline_menu_event(vm.u.TablineMenu.index, vm.u.TablineMenu.event);
3163 break;
3164 default:
3165 // unrecognised message, ignore it
3166 break;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003167 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003168 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003169
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003170 /*
3171 * If size < B_OK, it is an error code.
3172 */
3173 return size;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003174}
3175
3176/*
3177 * Here are some functions to protect access to ScreenLines[] and
3178 * LineOffset[]. These are used from the window thread to respond
3179 * to a Draw() callback. When that occurs, the window is already
3180 * locked by the system.
3181 *
3182 * Other code that needs to lock is any code that changes these
3183 * variables. Other read-only access, or access merely to the
3184 * contents of the screen buffer, need not be locked.
3185 *
3186 * If there is no window, don't call Lock() but do succeed.
3187 */
3188
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003189 int
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003190vim_lock_screen()
3191{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003192 return !gui.vimWindow || gui.vimWindow->Lock();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003193}
3194
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003195 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003196vim_unlock_screen()
3197{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003198 if (gui.vimWindow)
3199 gui.vimWindow->Unlock();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003200}
3201
3202#define RUN_BAPPLICATION_IN_NEW_THREAD 0
3203
3204#if RUN_BAPPLICATION_IN_NEW_THREAD
3205
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003206 int32
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003207run_vimapp(void *args)
3208{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003209 VimApp app(appsig);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003210
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003211 gui.vimApp = &app;
3212 app.Run(); // Run until Quit() called
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003213
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003214 return 0;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003215}
3216
3217#else
3218
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003219 int32
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003220call_main(void *args)
3221{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003222 struct MainArgs *ma = (MainArgs *)args;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003223
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003224 return main(ma->argc, ma->argv);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003225}
3226#endif
3227
3228/*
3229 * Parse the GUI related command-line arguments. Any arguments used are
3230 * deleted from argv, and *argc is decremented accordingly. This is called
3231 * when vim is started, whether or not the GUI has been started.
3232 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003233 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003234gui_mch_prepare(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003235 int *argc,
3236 char **argv)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003237{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003238 /*
3239 * We don't have any command line arguments for the BeOS GUI yet,
3240 * but this is an excellent place to create our Application object.
3241 */
3242 if (!gui.vimApp) {
3243 thread_info tinfo;
3244 get_thread_info(find_thread(NULL), &tinfo);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003245
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003246 // May need the port very early on to process RefsReceived()
3247 gui.vdcmp = create_port(B_MAX_PORT_COUNT, "vim VDCMP");
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003248
3249#if RUN_BAPPLICATION_IN_NEW_THREAD
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003250 thread_id tid = spawn_thread(run_vimapp, "vim VimApp",
3251 tinfo.priority, NULL);
3252 if (tid >= B_OK) {
3253 resume_thread(tid);
3254 } else {
3255 getout(1);
3256 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003257#else
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003258 MainArgs ma = { *argc, argv };
3259 thread_id tid = spawn_thread(call_main, "vim main()",
3260 tinfo.priority, &ma);
3261 if (tid >= B_OK) {
3262 VimApp app(appsig);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003263
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003264 gui.vimApp = &app;
3265 resume_thread(tid);
3266 /*
3267 * This is rather horrible.
3268 * call_main will call main() again...
3269 * There will be no infinite recursion since
3270 * gui.vimApp is set now.
3271 */
3272 app.Run(); // Run until Quit() called
3273 // fprintf(stderr, "app.Run() returned...\n");
3274 status_t dummy_exitcode;
3275 (void)wait_for_thread(tid, &dummy_exitcode);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003276
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003277 /*
3278 * This path should be the normal one taken to exit Vim.
3279 * The main() thread calls mch_exit() which calls
3280 * gui_mch_exit() which terminates its thread.
3281 */
3282 exit(main_exitcode);
3283 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003284#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003285 }
3286 // Don't fork() when starting the GUI. Spawned threads are not
3287 // duplicated with a fork(). The result is a mess.
3288 gui.dofork = FALSE;
3289 /*
3290 * XXX Try to determine whether we were started from
3291 * the Tracker or the terminal.
3292 * It would be nice to have this work, because the Tracker
3293 * follows symlinks, so even if you double-click on gvim,
3294 * when it is a link to vim it will still pass a command name
3295 * of vim...
3296 * We try here to see if stdin comes from /dev/null. If so,
3297 * (or if there is an error, which should never happen) start the GUI.
3298 * This does the wrong thing for vim - </dev/null, and we're
3299 * too early to see the command line parsing. Tough.
3300 * On the other hand, it starts the gui for vim file & which is nice.
3301 */
3302 if (!isatty(0)) {
3303 struct stat stat_stdin, stat_dev_null;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003304
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003305 if (fstat(0, &stat_stdin) == -1 ||
3306 stat("/dev/null", &stat_dev_null) == -1 ||
3307 (stat_stdin.st_dev == stat_dev_null.st_dev &&
3308 stat_stdin.st_ino == stat_dev_null.st_ino))
3309 gui.starting = TRUE;
3310 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003311}
3312
3313/*
3314 * Check if the GUI can be started. Called before gvimrc is sourced.
3315 * Return OK or FAIL.
3316 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003317 int
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003318gui_mch_init_check(void)
3319{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003320 return OK; // TODO: GUI can always be started?
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003321}
3322
3323/*
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003324 * Initialise the GUI. Create all the windows, set up all the call-backs
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003325 * etc.
3326 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003327 int
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003328gui_mch_init()
3329{
3330 display_errors();
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003331 gui.def_norm_pixel = RGB(0x00, 0x00, 0x00); // black
3332 gui.def_back_pixel = RGB(0xFF, 0xFF, 0xFF); // white
3333 gui.norm_pixel = gui.def_norm_pixel;
3334 gui.back_pixel = gui.def_back_pixel;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003335
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003336 gui.scrollbar_width = (int) B_V_SCROLL_BAR_WIDTH;
3337 gui.scrollbar_height = (int) B_H_SCROLL_BAR_HEIGHT;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003338#ifdef FEAT_MENU
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003339 gui.menu_height = 19; // initial guess -
3340 // correct for my default settings
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003341#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003342 gui.border_offset = 3; // coordinates are inside window borders
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003343
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003344 if (gui.vdcmp < B_OK)
3345 return FAIL;
3346 get_key_map(&keyMap, &keyMapChars);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003347
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003348 gui.vimWindow = new VimWindow(); // hidden and locked
3349 if (!gui.vimWindow)
3350 return FAIL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003351
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003352 gui.vimWindow->Run(); // Run() unlocks but does not show
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003353
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003354 // Get the colors from the "Normal" group (set in syntax.c or in a vimrc
3355 // file)
3356 set_normal_colors();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003357
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003358 /*
3359 * Check that none of the colors are the same as the background color
3360 */
3361 gui_check_colors();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003362
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003363 // Get the colors for the highlight groups (gui_check_colors() might have
3364 // changed them)
3365 highlight_gui_started(); // re-init colors and fonts
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003366
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003367 gui_mch_new_colors(); // window must exist for this
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003368
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003369 return OK;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003370}
3371
3372/*
3373 * Called when the foreground or background color has been changed.
3374 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003375 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003376gui_mch_new_colors()
3377{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003378 rgb_color rgb = GUI_TO_RGB(gui.back_pixel);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003379
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003380 if (gui.vimWindow->Lock()) {
3381 gui.vimForm->SetViewColor(rgb);
3382 // Does this not have too much effect for those small rectangles?
3383 gui.vimForm->Invalidate();
3384 gui.vimWindow->Unlock();
3385 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003386}
3387
3388/*
3389 * Open the GUI window which was created by a call to gui_mch_init().
3390 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003391 int
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003392gui_mch_open()
3393{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003394 if (gui_win_x != -1 && gui_win_y != -1)
3395 gui_mch_set_winpos(gui_win_x, gui_win_y);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003396
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003397 // Actually open the window
3398 if (gui.vimWindow->Lock()) {
3399 gui.vimWindow->Show();
3400 gui.vimWindow->Unlock();
3401 return OK;
3402 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003403
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003404 return FAIL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003405}
3406
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003407 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003408gui_mch_exit(int vim_exitcode)
3409{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003410 if (gui.vimWindow) {
3411 thread_id tid = gui.vimWindow->Thread();
3412 gui.vimWindow->Lock();
3413 gui.vimWindow->Quit();
3414 // Wait until it is truely gone
3415 int32 exitcode;
3416 wait_for_thread(tid, &exitcode);
3417 }
3418 delete_port(gui.vdcmp);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003419#if !RUN_BAPPLICATION_IN_NEW_THREAD
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003420 /*
3421 * We are in the main() thread - quit the App thread and
3422 * quit ourselves (passing on the exitcode). Use a global since the
3423 * value from exit_thread() is only used if wait_for_thread() is
3424 * called in time (race condition).
3425 */
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003426#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003427 if (gui.vimApp) {
3428 VimTextAreaView::guiBlankMouse(false);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003429
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003430 main_exitcode = vim_exitcode;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003431#if RUN_BAPPLICATION_IN_NEW_THREAD
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003432 thread_id tid = gui.vimApp->Thread();
3433 int32 exitcode;
3434 gui.vimApp->Lock();
3435 gui.vimApp->Quit();
3436 gui.vimApp->Unlock();
3437 wait_for_thread(tid, &exitcode);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003438#else
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003439 gui.vimApp->Lock();
3440 gui.vimApp->Quit();
3441 gui.vimApp->Unlock();
3442 // suicide
3443 exit_thread(vim_exitcode);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003444#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003445 }
3446 // If we are somehow still here, let mch_exit() handle things.
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003447}
3448
3449/*
3450 * Get the position of the top left corner of the window.
3451 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003452 int
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003453gui_mch_get_winpos(int *x, int *y)
3454{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003455 if (gui.vimWindow->Lock()) {
3456 BRect r;
3457 r = gui.vimWindow->Frame();
3458 gui.vimWindow->Unlock();
3459 *x = (int)r.left;
3460 *y = (int)r.top;
3461 return OK;
3462 }
3463 else
3464 return FAIL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003465}
3466
3467/*
3468 * Set the position of the top left corner of the window to the given
3469 * coordinates.
3470 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003471 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003472gui_mch_set_winpos(int x, int y)
3473{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003474 if (gui.vimWindow->Lock()) {
3475 gui.vimWindow->MoveTo(x, y);
3476 gui.vimWindow->Unlock();
3477 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003478}
3479
3480/*
3481 * Set the size of the window to the given width and height in pixels.
3482 */
3483void
3484gui_mch_set_shellsize(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003485 int width,
3486 int height,
3487 int min_width,
3488 int min_height,
3489 int base_width,
3490 int base_height,
3491 int direction) // TODO: utilize?
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003492{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003493 /*
3494 * We are basically given the size of the VimForm, if I understand
3495 * correctly. Since it fills the window completely, this will also
3496 * be the size of the window.
3497 */
3498 if (gui.vimWindow->Lock()) {
3499 gui.vimWindow->ResizeTo(width - PEN_WIDTH, height - PEN_WIDTH);
3500
3501 // set size limits
3502 float minWidth, maxWidth, minHeight, maxHeight;
3503
3504 gui.vimWindow->GetSizeLimits(&minWidth, &maxWidth,
3505 &minHeight, &maxHeight);
3506 gui.vimWindow->SetSizeLimits(min_width, maxWidth,
3507 min_height, maxHeight);
3508
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003509 /*
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003510 * Set the resizing alignment depending on font size.
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003511 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003512 gui.vimWindow->SetWindowAlignment(
3513 B_PIXEL_ALIGNMENT, // window_alignment mode,
3514 1, // int32 h,
3515 0, // int32 hOffset = 0,
3516 gui.char_width, // int32 width = 0,
3517 base_width, // int32 widthOffset = 0,
3518 1, // int32 v = 0,
3519 0, // int32 vOffset = 0,
3520 gui.char_height, // int32 height = 0,
3521 base_height // int32 heightOffset = 0
3522 );
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003523
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003524 gui.vimWindow->Unlock();
3525 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003526}
3527
3528void
3529gui_mch_get_screen_dimensions(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003530 int *screen_w,
3531 int *screen_h)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003532{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003533 BRect frame;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003534
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003535 {
3536 BScreen screen(gui.vimWindow);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003537
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003538 if (screen.IsValid()) {
3539 frame = screen.Frame();
3540 } else {
3541 frame.right = 640;
3542 frame.bottom = 480;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003543 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003544 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003545
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003546 // XXX approximations...
3547 *screen_w = (int) frame.right - 2 * gui.scrollbar_width - 20;
3548 *screen_h = (int) frame.bottom - gui.scrollbar_height
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003549#ifdef FEAT_MENU
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003550 - gui.menu_height
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003551#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003552 - 30;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003553}
3554
3555void
3556gui_mch_set_text_area_pos(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003557 int x,
3558 int y,
3559 int w,
3560 int h)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003561{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003562 if (!gui.vimTextArea)
3563 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003564
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003565 if (gui.vimWindow->Lock()) {
3566 gui.vimTextArea->MoveTo(x, y);
3567 gui.vimTextArea->ResizeTo(w - PEN_WIDTH, h - PEN_WIDTH);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003568
Bram Moolenaarbeae4082020-04-23 15:41:49 +02003569#ifdef FEAT_GUI_TABLINE
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003570 if (gui.vimForm->TabLine() != NULL) {
3571 gui.vimForm->TabLine()->ResizeTo(w, gui.vimForm->TablineHeight());
3572 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003573#endif // FEAT_GUI_TABLINE
3574
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003575 gui.vimWindow->Unlock();
3576 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003577}
3578
3579
3580/*
3581 * Scrollbar stuff:
3582 */
3583
3584void
3585gui_mch_enable_scrollbar(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003586 scrollbar_T *sb,
3587 int flag)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003588{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003589 VimScrollBar *vsb = sb->id;
3590 if (gui.vimWindow->Lock()) {
3591 /*
3592 * This function is supposed to be idempotent, but Show()/Hide()
3593 * is not. Therefore we test if they are needed.
3594 */
3595 if (flag) {
3596 if (vsb->IsHidden()) {
3597 vsb->Show();
3598 }
3599 } else {
3600 if (!vsb->IsHidden()) {
3601 vsb->Hide();
3602 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003603 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003604 gui.vimWindow->Unlock();
3605 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003606}
3607
3608void
3609gui_mch_set_scrollbar_thumb(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003610 scrollbar_T *sb,
3611 int val,
3612 int size,
3613 int max)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003614{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003615 if (gui.vimWindow->Lock()) {
3616 VimScrollBar *s = sb->id;
3617 if (max == 0) {
3618 s->SetValue(0);
3619 s->SetRange(0.0, 0.0);
3620 } else {
3621 s->SetProportion((float)size / (max + 1.0));
3622 s->SetSteps(1.0, size > 5 ? size - 2 : size);
3623#ifndef SCROLL_PAST_END // really only defined in gui.c...
3624 max = max + 1 - size;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003625#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003626 if (max < s->Value()) {
3627 /*
3628 * If the new maximum is lower than the current value,
3629 * setting it would cause the value to be clipped and
3630 * therefore a ValueChanged() call.
3631 * We avoid this by setting the value first, because
3632 * it presumably is <= max.
3633 */
3634 s->SetValue(val);
3635 s->SetRange(0.0, max);
3636 } else {
3637 /*
3638 * In the other case, set the range first, since the
3639 * new value might be higher than the current max.
3640 */
3641 s->SetRange(0.0, max);
3642 s->SetValue(val);
3643 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003644 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003645 gui.vimWindow->Unlock();
3646 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003647}
3648
3649void
3650gui_mch_set_scrollbar_pos(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003651 scrollbar_T *sb,
3652 int x,
3653 int y,
3654 int w,
3655 int h)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003656{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003657 if (gui.vimWindow->Lock()) {
3658 BRect winb = gui.vimWindow->Bounds();
3659 float vsbx = x, vsby = y;
3660 VimScrollBar *vsb = sb->id;
3661 vsb->ResizeTo(w - PEN_WIDTH, h - PEN_WIDTH);
3662 if (winb.right-(x+w)<w) vsbx = winb.right - (w - PEN_WIDTH);
3663 vsb->MoveTo(vsbx, vsby);
3664 gui.vimWindow->Unlock();
3665 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003666}
3667
Bram Moolenaar203ec772020-07-17 20:43:43 +02003668 int
3669gui_mch_get_scrollbar_xpadding(void)
3670{
3671 // TODO: Calculate the padding for adjust scrollbar position when the
3672 // Window is maximized.
3673 return 0;
3674}
3675
3676 int
3677gui_mch_get_scrollbar_ypadding(void)
3678{
3679 // TODO: Calculate the padding for adjust scrollbar position when the
3680 // Window is maximized.
3681 return 0;
3682}
3683
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003684void
3685gui_mch_create_scrollbar(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003686 scrollbar_T *sb,
3687 int orient) // SBAR_VERT or SBAR_HORIZ
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003688{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003689 orientation posture =
3690 (orient == SBAR_HORIZ) ? B_HORIZONTAL : B_VERTICAL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003691
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003692 VimScrollBar *vsb = sb->id = new VimScrollBar(sb, posture);
3693 if (gui.vimWindow->Lock()) {
3694 vsb->SetTarget(gui.vimTextArea);
3695 vsb->Hide();
3696 gui.vimForm->AddChild(vsb);
3697 gui.vimWindow->Unlock();
3698 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003699}
3700
Bram Moolenaarbeae4082020-04-23 15:41:49 +02003701#if defined(FEAT_WINDOWS) || defined(FEAT_GUI_HAIKU) || defined(PROTO)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003702void
3703gui_mch_destroy_scrollbar(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003704 scrollbar_T *sb)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003705{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003706 if (gui.vimWindow->Lock()) {
3707 sb->id->RemoveSelf();
3708 delete sb->id;
3709 gui.vimWindow->Unlock();
3710 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003711}
3712#endif
3713
3714/*
3715 * Cursor does not flash
3716 */
3717 int
3718gui_mch_is_blink_off(void)
3719{
3720 return FALSE;
3721}
3722
3723/*
3724 * Cursor blink functions.
3725 *
3726 * This is a simple state machine:
3727 * BLINK_NONE not blinking at all
3728 * BLINK_OFF blinking, cursor is not shown
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003729 * BLINK_ON blinking, cursor is shown
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003730 */
3731
3732#define BLINK_NONE 0
3733#define BLINK_OFF 1
3734#define BLINK_ON 2
3735
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003736static int blink_state = BLINK_NONE;
3737static long_u blink_waittime = 700;
3738static long_u blink_ontime = 400;
3739static long_u blink_offtime = 250;
3740static int blink_timer = 0;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003741
3742void
3743gui_mch_set_blinking(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003744 long waittime,
3745 long on,
3746 long off)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003747{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003748 // TODO
3749 blink_waittime = waittime;
3750 blink_ontime = on;
3751 blink_offtime = off;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003752}
3753
3754/*
3755 * Stop the cursor blinking. Show the cursor if it wasn't shown.
3756 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003757 void
Bram Moolenaarbeae4082020-04-23 15:41:49 +02003758gui_mch_stop_blink(int may_call_gui_update_cursor)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003759{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003760 // TODO
3761 if (blink_timer != 0)
3762 {
3763 // XtRemoveTimeOut(blink_timer);
3764 blink_timer = 0;
3765 }
3766 if (blink_state == BLINK_OFF)
3767 gui_update_cursor(TRUE, FALSE);
3768 blink_state = BLINK_NONE;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003769}
3770
3771/*
3772 * Start the cursor blinking. If it was already blinking, this restarts the
3773 * waiting time and shows the cursor.
3774 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003775 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003776gui_mch_start_blink()
3777{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003778 // TODO
3779 if (blink_timer != 0)
3780 ;// XtRemoveTimeOut(blink_timer);
3781 // Only switch blinking on if none of the times is zero
3782 if (blink_waittime && blink_ontime && blink_offtime && gui.in_focus)
3783 {
3784 blink_timer = 1; // XtAppAddTimeOut(app_context, blink_waittime,
3785 blink_state = BLINK_ON;
3786 gui_update_cursor(TRUE, FALSE);
3787 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003788}
3789
3790/*
3791 * Initialise vim to use the font with the given name. Return FAIL if the font
3792 * could not be loaded, OK otherwise.
3793 */
3794int
3795gui_mch_init_font(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003796 char_u *font_name,
3797 int fontset)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003798{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003799 if (gui.vimWindow->Lock())
3800 {
3801 int rc = gui.vimTextArea->mchInitFont(font_name);
3802 gui.vimWindow->Unlock();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003803
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003804 return rc;
3805 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003806
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003807 return FAIL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003808}
3809
3810
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003811 int
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003812gui_mch_adjust_charsize()
3813{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003814 return FAIL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003815}
3816
3817
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003818 int
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003819gui_mch_font_dialog(font_family* family, font_style* style, float* size)
3820{
3821#if defined(FEAT_GUI_DIALOG)
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003822 // gui.vimWindow->Unlock();
3823 VimSelectFontDialog *dialog = new VimSelectFontDialog(family, style, size);
3824 return dialog->Go();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003825#else
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003826 return NOFONT;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003827#endif // FEAT_GUI_DIALOG
3828}
3829
3830
3831GuiFont
3832gui_mch_get_font(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003833 char_u *name,
3834 int giveErrorIfMissing)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003835{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003836 static VimFont *fontList = NULL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003837
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003838 if (!gui.in_use) // can't do this when GUI not running
3839 return NOFONT;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003840
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003841 // storage for locally modified name;
3842 const int buff_size = B_FONT_FAMILY_LENGTH + B_FONT_STYLE_LENGTH + 20;
3843 static char font_name[buff_size] = {0};
3844 font_family family = {0};
3845 font_style style = {0};
3846 float size = 0.f;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003847
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003848 if (name == 0 && be_fixed_font == 0) {
3849 if (giveErrorIfMissing)
3850 semsg(_(e_font), name);
3851 return NOFONT;
3852 }
3853
3854 bool useSelectGUI = false;
3855 if (name != NULL)
3856 if (STRCMP(name, "*") == 0) {
3857 useSelectGUI = true;
3858 STRNCPY(font_name, hl_get_font_name(), buff_size);
3859 } else
3860 STRNCPY(font_name, name, buff_size);
3861
3862 if (font_name[0] == 0) {
3863 be_fixed_font->GetFamilyAndStyle(&family, &style);
3864 size = be_fixed_font->Size();
3865 vim_snprintf(font_name, buff_size,
3866 (char*)"%s/%s/%.0f", family, style, size);
3867 }
3868
3869 // replace underscores with spaces
3870 char* end = 0;
3871 while (end = strchr((char *)font_name, '_'))
3872 *end = ' ';
3873
3874 // store the name before strtok corrupt the buffer ;-)
3875 static char buff[buff_size] = {0};
3876 STRNCPY(buff, font_name, buff_size);
3877 STRNCPY(family, strtok(buff, "/\0"), B_FONT_FAMILY_LENGTH);
3878 char* style_s = strtok(0, "/\0");
3879 if (style_s != 0)
3880 STRNCPY(style, style_s, B_FONT_STYLE_LENGTH);
3881 size = atof((style_s != 0) ? strtok(0, "/\0") : "0");
3882
3883 if (useSelectGUI) {
3884 if (gui_mch_font_dialog(&family, &style, &size) == NOFONT)
3885 return FAIL;
3886 // compose for further processing
3887 vim_snprintf(font_name, buff_size,
3888 (char*)"%s/%s/%.0f", family, style, size);
3889 hl_set_font_name((char_u*)font_name);
3890
3891 // Set guifont to the name of the selected font.
3892 char_u* new_p_guifont = (char_u*)alloc(STRLEN(font_name) + 1);
3893 if (new_p_guifont != NULL) {
3894 STRCPY(new_p_guifont, font_name);
3895 vim_free(p_guifont);
3896 p_guifont = new_p_guifont;
3897 // Replace spaces in the font name with underscores.
3898 for ( ; *new_p_guifont; ++new_p_guifont)
3899 if (*new_p_guifont == ' ')
3900 *new_p_guifont = '_';
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003901 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003902 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003903
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003904 VimFont *flp;
3905 for (flp = fontList; flp; flp = flp->next) {
3906 if (STRCMP(font_name, flp->name) == 0) {
3907 flp->refcount++;
3908 return (GuiFont)flp;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003909 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003910 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003911
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003912 VimFont *font = new VimFont();
3913 font->name = vim_strsave((char_u*)font_name);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003914
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003915 if (count_font_styles(family) <= 0) {
3916 if (giveErrorIfMissing)
3917 semsg(_(e_font), font->name);
3918 delete font;
3919 return NOFONT;
3920 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003921
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003922 // Remember font in the static list for later use
3923 font->next = fontList;
3924 fontList = font;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003925
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003926 font->SetFamilyAndStyle(family, style);
3927 if (size > 0.f)
3928 font->SetSize(size);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003929
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003930 font->SetSpacing(B_FIXED_SPACING);
3931 font->SetEncoding(B_UNICODE_UTF8);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003932
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003933 return (GuiFont)font;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003934}
3935
3936/*
3937 * Set the current text font.
3938 */
3939void
3940gui_mch_set_font(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003941 GuiFont font)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003942{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003943 if (gui.vimWindow->Lock()) {
3944 VimFont *vf = (VimFont *)font;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003945
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003946 gui.vimTextArea->SetFont(vf);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003947
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003948 gui.char_width = (int) vf->StringWidth("n");
3949 font_height fh;
3950 vf->GetHeight(&fh);
3951 gui.char_height = (int)(fh.ascent + 0.9999)
3952 + (int)(fh.descent + 0.9999) + (int)(fh.leading + 0.9999);
3953 gui.char_ascent = (int)(fh.ascent + 0.9999);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003954
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003955 gui.vimWindow->Unlock();
3956 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003957}
3958
3959// XXX TODO This is apparently never called...
3960void
3961gui_mch_free_font(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003962 GuiFont font)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003963{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003964 if (font == NOFONT)
3965 return;
3966 VimFont *f = (VimFont *)font;
3967 if (--f->refcount <= 0) {
3968 if (f->refcount < 0)
3969 fprintf(stderr, "VimFont: refcount < 0\n");
3970 delete f;
3971 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003972}
3973
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003974 char_u *
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003975gui_mch_get_fontname(GuiFont font, char_u *name)
3976{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003977 if (name == NULL)
3978 return NULL;
3979 return vim_strsave(name);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003980}
3981
3982/*
3983 * Adjust gui.char_height (after 'linespace' was changed).
3984 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003985 int
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003986gui_mch_adjust_charheight()
3987{
3988
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003989 // TODO: linespace support?
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003990
3991// #ifdef FEAT_XFONTSET
Bram Moolenaarb52575f2020-04-24 22:16:13 +02003992// if (gui.fontset != NOFONTSET)
3993// {
3994// gui.char_height = fontset_height((XFontSet)gui.fontset) + p_linespace;
3995// gui.char_ascent = fontset_ascent((XFontSet)gui.fontset)
3996// + p_linespace / 2;
3997// }
3998// else
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003999// #endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004000 {
4001 VimFont *font = (VimFont *)gui.norm_font;
4002 font_height fh = {0};
4003 font->GetHeight(&fh);
4004 gui.char_height = (int)(fh.ascent + fh.descent + 0.5) + p_linespace;
4005 gui.char_ascent = (int)(fh.ascent + 0.5) + p_linespace / 2;
4006 }
4007 return OK;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004008}
4009
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004010 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004011gui_mch_getmouse(int *x, int *y)
4012{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004013 fprintf(stderr, "gui_mch_getmouse");
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004014
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004015 /*int rootx, rooty, winx, winy;
4016 Window root, child;
4017 unsigned int mask;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004018
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004019 if (gui.wid && XQueryPointer(gui.dpy, gui.wid, &root, &child,
4020 &rootx, &rooty, &winx, &winy, &mask)) {
4021 *x = winx;
4022 *y = winy;
4023 } else*/ {
4024 *x = -1;
4025 *y = -1;
4026 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004027}
4028
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004029 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004030gui_mch_mousehide(int hide)
4031{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004032 fprintf(stderr, "gui_mch_getmouse");
4033 // TODO
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004034}
4035
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004036 static int
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004037hex_digit(int c)
4038{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004039 if (isdigit(c))
4040 return c - '0';
4041 c = TOLOWER_ASC(c);
4042 if (c >= 'a' && c <= 'f')
4043 return c - 'a' + 10;
4044 return -1000;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004045}
4046
4047/*
4048 * This function has been lifted from gui_w32.c and extended a bit.
4049 *
4050 * Return the Pixel value (color) for the given color name.
4051 * Return INVALCOLOR for error.
4052 */
4053guicolor_T
4054gui_mch_get_color(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004055 char_u *name)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004056{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004057 typedef struct GuiColourTable
4058 {
4059 const char *name;
4060 guicolor_T colour;
4061 } GuiColourTable;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004062
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004063#define NSTATIC_COLOURS 50 // 32
4064#define NDYNAMIC_COLOURS 33
4065#define NCOLOURS (NSTATIC_COLOURS + NDYNAMIC_COLOURS)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004066
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004067 static GuiColourTable table[NCOLOURS] =
4068 {
4069 {"Black", RGB(0x00, 0x00, 0x00)},
4070 {"DarkGray", RGB(0x80, 0x80, 0x80)},
4071 {"DarkGrey", RGB(0x80, 0x80, 0x80)},
4072 {"Gray", RGB(0xC0, 0xC0, 0xC0)},
4073 {"Grey", RGB(0xC0, 0xC0, 0xC0)},
4074 {"LightGray", RGB(0xD3, 0xD3, 0xD3)},
4075 {"LightGrey", RGB(0xD3, 0xD3, 0xD3)},
4076 {"Gray10", RGB(0x1A, 0x1A, 0x1A)},
4077 {"Grey10", RGB(0x1A, 0x1A, 0x1A)},
4078 {"Gray20", RGB(0x33, 0x33, 0x33)},
4079 {"Grey20", RGB(0x33, 0x33, 0x33)},
4080 {"Gray30", RGB(0x4D, 0x4D, 0x4D)},
4081 {"Grey30", RGB(0x4D, 0x4D, 0x4D)},
4082 {"Gray40", RGB(0x66, 0x66, 0x66)},
4083 {"Grey40", RGB(0x66, 0x66, 0x66)},
4084 {"Gray50", RGB(0x7F, 0x7F, 0x7F)},
4085 {"Grey50", RGB(0x7F, 0x7F, 0x7F)},
4086 {"Gray60", RGB(0x99, 0x99, 0x99)},
4087 {"Grey60", RGB(0x99, 0x99, 0x99)},
4088 {"Gray70", RGB(0xB3, 0xB3, 0xB3)},
4089 {"Grey70", RGB(0xB3, 0xB3, 0xB3)},
4090 {"Gray80", RGB(0xCC, 0xCC, 0xCC)},
4091 {"Grey80", RGB(0xCC, 0xCC, 0xCC)},
4092 {"Gray90", RGB(0xE5, 0xE5, 0xE5)},
4093 {"Grey90", RGB(0xE5, 0xE5, 0xE5)},
4094 {"White", RGB(0xFF, 0xFF, 0xFF)},
4095 {"DarkRed", RGB(0x80, 0x00, 0x00)},
4096 {"Red", RGB(0xFF, 0x00, 0x00)},
4097 {"LightRed", RGB(0xFF, 0xA0, 0xA0)},
4098 {"DarkBlue", RGB(0x00, 0x00, 0x80)},
4099 {"Blue", RGB(0x00, 0x00, 0xFF)},
4100 {"LightBlue", RGB(0xA0, 0xA0, 0xFF)},
4101 {"DarkGreen", RGB(0x00, 0x80, 0x00)},
4102 {"Green", RGB(0x00, 0xFF, 0x00)},
4103 {"LightGreen", RGB(0xA0, 0xFF, 0xA0)},
4104 {"DarkCyan", RGB(0x00, 0x80, 0x80)},
4105 {"Cyan", RGB(0x00, 0xFF, 0xFF)},
4106 {"LightCyan", RGB(0xA0, 0xFF, 0xFF)},
4107 {"DarkMagenta", RGB(0x80, 0x00, 0x80)},
4108 {"Magenta", RGB(0xFF, 0x00, 0xFF)},
4109 {"LightMagenta", RGB(0xFF, 0xA0, 0xFF)},
4110 {"Brown", RGB(0x80, 0x40, 0x40)},
4111 {"Yellow", RGB(0xFF, 0xFF, 0x00)},
4112 {"LightYellow", RGB(0xFF, 0xFF, 0xA0)},
4113 {"DarkYellow", RGB(0xBB, 0xBB, 0x00)},
4114 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)},
4115 {"Orange", RGB(0xFF, 0xA5, 0x00)},
4116 {"Purple", RGB(0xA0, 0x20, 0xF0)},
4117 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)},
4118 {"Violet", RGB(0xEE, 0x82, 0xEE)},
4119 // NOTE: some entries are zero-allocated for NDDYNAMIC_COLORS
4120 // in this table!
4121 };
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004122
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004123 static int endColour = NSTATIC_COLOURS;
4124 static int newColour = NSTATIC_COLOURS;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004125
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004126 int r, g, b;
4127 int i;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004128
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004129 if (name[0] == '#' && STRLEN(name) == 7)
4130 {
4131 // Name is in "#rrggbb" format
4132 r = hex_digit(name[1]) * 16 + hex_digit(name[2]);
4133 g = hex_digit(name[3]) * 16 + hex_digit(name[4]);
4134 b = hex_digit(name[5]) * 16 + hex_digit(name[6]);
4135 if (r < 0 || g < 0 || b < 0)
4136 return INVALCOLOR;
4137 return RGB(r, g, b);
4138 }
4139 else
4140 {
4141 // Check if the name is one of the colours we know
4142 for (i = 0; i < endColour; i++)
4143 if (STRICMP(name, table[i].name) == 0)
4144 return table[i].colour;
4145 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004146
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004147 /*
4148 * Last attempt. Look in the file "$VIMRUNTIME/rgb.txt".
4149 */
4150 {
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004151#define LINE_LEN 100
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004152 FILE *fd;
4153 char line[LINE_LEN];
4154 char_u *fname;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004155
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004156 fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt");
4157 if (fname == NULL)
4158 return INVALCOLOR;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004159
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004160 fd = fopen((char *)fname, "rt");
4161 vim_free(fname);
4162 if (fd == NULL)
4163 return INVALCOLOR;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004164
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004165 while (!feof(fd))
4166 {
4167 int len;
4168 int pos;
4169 char *colour;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004170
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004171 fgets(line, LINE_LEN, fd);
4172 len = strlen(line);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004173
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004174 if (len <= 1 || line[len-1] != '\n')
4175 continue;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004176
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004177 line[len-1] = '\0';
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004178
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004179 i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos);
4180 if (i != 3)
4181 continue;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004182
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004183 colour = line + pos;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004184
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004185 if (STRICMP(colour, name) == 0)
4186 {
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004187 fclose(fd);
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004188 /*
4189 * Now remember this colour in the table.
4190 * A LRU scheme might be better but this is simpler.
4191 * Or could use a growing array.
4192 */
4193 guicolor_T gcolour = RGB(r,g,b);
4194
4195 // NOTE: see note above in table allocation! We are working here with
4196 // dynamically allocated names, not constant ones!
4197 vim_free((char*)table[newColour].name);
4198 table[newColour].name = (char *)vim_strsave((char_u *)colour);
4199 table[newColour].colour = gcolour;
4200
4201 newColour++;
4202 if (newColour >= NCOLOURS)
4203 newColour = NSTATIC_COLOURS;
4204 if (endColour < NCOLOURS)
4205 endColour = newColour;
4206
4207 return gcolour;
4208 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004209 }
4210
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004211 fclose(fd);
4212 }
4213
4214 return INVALCOLOR;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004215}
4216
4217/*
4218 * Set the current text foreground color.
4219 */
4220void
4221gui_mch_set_fg_color(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004222 guicolor_T color)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004223{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004224 rgb_color rgb = GUI_TO_RGB(color);
4225 if (gui.vimWindow->Lock()) {
4226 gui.vimTextArea->SetHighColor(rgb);
4227 gui.vimWindow->Unlock();
4228 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004229}
4230
4231/*
4232 * Set the current text background color.
4233 */
4234void
4235gui_mch_set_bg_color(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004236 guicolor_T color)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004237{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004238 rgb_color rgb = GUI_TO_RGB(color);
4239 if (gui.vimWindow->Lock()) {
4240 gui.vimTextArea->SetLowColor(rgb);
4241 gui.vimWindow->Unlock();
4242 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004243}
4244
4245/*
4246 * Set the current text special color.
4247 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004248 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004249gui_mch_set_sp_color(guicolor_T color)
4250{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004251 // prev_sp_color = color;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004252}
4253
4254void
4255gui_mch_draw_string(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004256 int row,
4257 int col,
4258 char_u *s,
4259 int len,
4260 int flags)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004261{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004262 if (gui.vimWindow->Lock()) {
4263 gui.vimTextArea->mchDrawString(row, col, s, len, flags);
4264 gui.vimWindow->Unlock();
4265 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004266}
4267
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004268 guicolor_T
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004269gui_mch_get_rgb_color(int r, int g, int b)
4270{
4271 return gui_get_rgb_color_cmn(r, g, b);
4272}
4273
4274
4275// Return OK if the key with the termcap name "name" is supported.
4276int
4277gui_mch_haskey(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004278 char_u *name)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004279{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004280 int i;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004281
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004282 for (i = 0; special_keys[i].BeKeys != 0; i++)
4283 if (name[0] == special_keys[i].vim_code0 &&
4284 name[1] == special_keys[i].vim_code1)
4285 return OK;
4286 return FAIL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004287}
4288
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004289 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004290gui_mch_beep()
4291{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004292 ::beep();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004293}
4294
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004295 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004296gui_mch_flash(int msec)
4297{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004298 // Do a visual beep by reversing the foreground and background colors
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004299
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004300 if (gui.vimWindow->Lock()) {
4301 BRect rect = gui.vimTextArea->Bounds();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004302
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004303 gui.vimTextArea->SetDrawingMode(B_OP_INVERT);
4304 gui.vimTextArea->FillRect(rect);
4305 gui.vimTextArea->Sync();
4306 snooze(msec * 1000); // wait for a few msec
4307 gui.vimTextArea->FillRect(rect);
4308 gui.vimTextArea->SetDrawingMode(B_OP_COPY);
4309 gui.vimTextArea->Flush();
4310 gui.vimWindow->Unlock();
4311 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004312}
4313
4314/*
4315 * Invert a rectangle from row r, column c, for nr rows and nc columns.
4316 */
4317void
4318gui_mch_invert_rectangle(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004319 int r,
4320 int c,
4321 int nr,
4322 int nc)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004323{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004324 BRect rect;
4325 rect.left = FILL_X(c);
4326 rect.top = FILL_Y(r);
4327 rect.right = rect.left + nc * gui.char_width - PEN_WIDTH;
4328 rect.bottom = rect.top + nr * gui.char_height - PEN_WIDTH;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004329
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004330 if (gui.vimWindow->Lock()) {
4331 gui.vimTextArea->SetDrawingMode(B_OP_INVERT);
4332 gui.vimTextArea->FillRect(rect);
4333 gui.vimTextArea->SetDrawingMode(B_OP_COPY);
4334 gui.vimWindow->Unlock();
4335 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004336}
4337
4338/*
4339 * Iconify the GUI window.
4340 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004341 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004342gui_mch_iconify()
4343{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004344 if (gui.vimWindow->Lock()) {
4345 gui.vimWindow->Minimize(true);
4346 gui.vimWindow->Unlock();
4347 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004348}
4349
4350#if defined(FEAT_EVAL) || defined(PROTO)
4351/*
4352 * Bring the Vim window to the foreground.
4353 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004354 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004355gui_mch_set_foreground(void)
4356{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004357 // TODO
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004358}
4359#endif
4360
4361/*
4362 * Set the window title
4363 */
4364void
4365gui_mch_settitle(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004366 char_u *title,
4367 char_u *icon)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004368{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004369 if (gui.vimWindow->Lock()) {
4370 gui.vimWindow->SetTitle((char *)title);
4371 gui.vimWindow->Unlock();
4372 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004373}
4374
4375/*
4376 * Draw a cursor without focus.
4377 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004378 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004379gui_mch_draw_hollow_cursor(guicolor_T color)
4380{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004381 gui_mch_set_fg_color(color);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004382
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004383 BRect r;
4384 r.left = FILL_X(gui.col);
4385 r.top = FILL_Y(gui.row);
4386 int cells = utf_off2cells(LineOffset[gui.row] + gui.col, 100); // TODO-TODO
4387 if (cells>=4) cells = 1;
4388 r.right = r.left + cells*gui.char_width - PEN_WIDTH;
4389 r.bottom = r.top + gui.char_height - PEN_WIDTH;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004390
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004391 if (gui.vimWindow->Lock()) {
4392 gui.vimTextArea->StrokeRect(r);
4393 gui.vimWindow->Unlock();
4394 // gui_mch_flush();
4395 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004396}
4397
4398/*
4399 * Draw part of a cursor, only w pixels wide, and h pixels high.
4400 */
4401void
4402gui_mch_draw_part_cursor(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004403 int w,
4404 int h,
4405 guicolor_T color)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004406{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004407 gui_mch_set_fg_color(color);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004408
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004409 BRect r;
4410 r.left =
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004411#ifdef FEAT_RIGHTLEFT
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004412 // vertical line should be on the right of current point
4413 CURSOR_BAR_RIGHT ? FILL_X(gui.col + 1) - w :
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004414#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004415 FILL_X(gui.col);
4416 r.right = r.left + w - PEN_WIDTH;
4417 r.bottom = FILL_Y(gui.row + 1) - PEN_WIDTH;
4418 r.top = r.bottom - h + PEN_WIDTH;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004419
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004420 if (gui.vimWindow->Lock()) {
4421 gui.vimTextArea->FillRect(r);
4422 gui.vimWindow->Unlock();
4423 // gui_mch_flush();
4424 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004425}
4426
4427/*
4428 * Catch up with any queued events. This may put keyboard input into the
4429 * input buffer, call resize call-backs, trigger timers etc. If there is
4430 * nothing in the event queue (& no timers pending), then we return
4431 * immediately.
4432 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004433 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004434gui_mch_update()
4435{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004436 gui_mch_flush();
4437 while (port_count(gui.vdcmp) > 0 &&
4438 !vim_is_input_buf_full() &&
4439 gui_haiku_process_event(0) >= B_OK)
4440 /* nothing */ ;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004441}
4442
4443/*
4444 * GUI input routine called by gui_wait_for_chars(). Waits for a character
4445 * from the keyboard.
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004446 * wtime == -1 Wait forever.
4447 * wtime == 0 This should never happen.
4448 * wtime > 0 Wait wtime milliseconds for a character.
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004449 * Returns OK if a character was found to be available within the given time,
4450 * or FAIL otherwise.
4451 */
4452int
4453gui_mch_wait_for_chars(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004454 int wtime)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004455{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004456 int focus;
Bram Moolenaar80a8d382020-05-03 22:57:32 +02004457 bigtime_t until, timeout;
4458 status_t st;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004459
Bram Moolenaar80a8d382020-05-03 22:57:32 +02004460 if (wtime >= 0)
4461 {
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004462 timeout = wtime * 1000;
4463 until = system_time() + timeout;
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004464 }
Bram Moolenaar80a8d382020-05-03 22:57:32 +02004465 else
4466 timeout = B_INFINITE_TIMEOUT;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004467
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004468 focus = gui.in_focus;
4469 for (;;)
4470 {
4471 // Stop or start blinking when focus changes
4472 if (gui.in_focus != focus)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004473 {
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004474 if (gui.in_focus)
4475 gui_mch_start_blink();
4476 else
4477 gui_mch_stop_blink(TRUE);
4478 focus = gui.in_focus;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004479 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004480
4481 gui_mch_flush();
Bram Moolenaar80a8d382020-05-03 22:57:32 +02004482
4483#ifdef MESSAGE_QUEUE
4484# ifdef FEAT_TIMERS
4485 did_add_timer = FALSE;
4486# endif
4487 parse_queued_messages();
4488# ifdef FEAT_TIMERS
4489 if (did_add_timer)
4490 // Need to recompute the waiting time.
4491 break;
4492# endif
4493# ifdef FEAT_JOB_CHANNEL
4494 if (has_any_channel())
4495 {
4496 if (wtime < 0 || timeout > 20000)
4497 timeout = 20000;
4498 }
4499 else if (wtime < 0)
4500 timeout = B_INFINITE_TIMEOUT;
4501# endif
4502#endif
4503
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004504 /*
4505 * Don't use gui_mch_update() because then we will spin-lock until a
4506 * char arrives, instead we use gui_haiku_process_event() to hang until
4507 * an event arrives. No need to check for input_buf_full because we
4508 * are returning as soon as it contains a single char.
4509 */
4510 st = gui_haiku_process_event(timeout);
4511
4512 if (input_available())
4513 return OK;
4514 if (st < B_OK) // includes B_TIMED_OUT
4515 return FAIL;
4516
4517 /*
4518 * Calculate how much longer we're willing to wait for the
4519 * next event.
4520 */
Bram Moolenaar80a8d382020-05-03 22:57:32 +02004521 if (wtime >= 0)
4522 {
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004523 timeout = until - system_time();
4524 if (timeout < 0)
4525 break;
4526 }
4527 }
4528 return FAIL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004529
4530}
4531
4532/*
4533 * Output routines.
4534 */
4535
4536/*
4537 * Flush any output to the screen. This is typically called before
4538 * the app goes to sleep.
4539 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004540 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004541gui_mch_flush()
4542{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004543 // does this need to lock the window? Apparently not but be safe.
4544 if (gui.vimWindow->Lock()) {
4545 gui.vimWindow->Flush();
4546 gui.vimWindow->Unlock();
4547 }
4548 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004549}
4550
4551/*
4552 * Clear a rectangular region of the screen from text pos (row1, col1) to
4553 * (row2, col2) inclusive.
4554 */
4555void
4556gui_mch_clear_block(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004557 int row1,
4558 int col1,
4559 int row2,
4560 int col2)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004561{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004562 if (gui.vimWindow->Lock()) {
4563 gui.vimTextArea->mchClearBlock(row1, col1, row2, col2);
4564 gui.vimWindow->Unlock();
4565 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004566}
4567
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004568 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004569gui_mch_clear_all()
4570{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004571 if (gui.vimWindow->Lock()) {
4572 gui.vimTextArea->mchClearAll();
4573 gui.vimWindow->Unlock();
4574 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004575}
4576
4577/*
4578 * Delete the given number of lines from the given row, scrolling up any
4579 * text further down within the scroll region.
4580 */
4581void
4582gui_mch_delete_lines(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004583 int row,
4584 int num_lines)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004585{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004586 gui.vimTextArea->mchDeleteLines(row, num_lines);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004587}
4588
4589/*
4590 * Insert the given number of lines before the given row, scrolling down any
4591 * following text within the scroll region.
4592 */
4593void
4594gui_mch_insert_lines(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004595 int row,
4596 int num_lines)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004597{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004598 gui.vimTextArea->mchInsertLines(row, num_lines);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004599}
4600
4601#if defined(FEAT_MENU) || defined(PROTO)
4602/*
4603 * Menu stuff.
4604 */
4605
4606void
4607gui_mch_enable_menu(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004608 int flag)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004609{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004610 if (gui.vimWindow->Lock())
4611 {
4612 BMenuBar *menubar = gui.vimForm->MenuBar();
4613 menubar->SetEnabled(flag);
4614 gui.vimWindow->Unlock();
4615 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004616}
4617
4618void
4619gui_mch_set_menu_pos(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004620 int x,
4621 int y,
4622 int w,
4623 int h)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004624{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004625 // It will be in the right place anyway
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004626}
4627
4628/*
4629 * Add a sub menu to the menu bar.
4630 */
4631void
4632gui_mch_add_menu(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004633 vimmenu_T *menu,
4634 int idx)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004635{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004636 vimmenu_T *parent = menu->parent;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004637
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004638 // popup menu - just create it unattached
4639 if (menu_is_popup(menu->name) && parent == NULL) {
4640 BPopUpMenu* popUpMenu = new BPopUpMenu((const char*)menu->name, false, false);
4641 menu->submenu_id = popUpMenu;
4642 menu->id = NULL;
4643 return;
4644 }
4645
4646 if (!menu_is_menubar(menu->name)
4647 || (parent != NULL && parent->submenu_id == NULL))
4648 return;
4649
4650 if (gui.vimWindow->Lock())
4651 {
4652 // Major re-write of the menu code, it was failing with memory corruption when
4653 // we started loading multiple files (the Buffer menu)
4654 //
4655 // Note we don't use the preference values yet, all are inserted into the
4656 // menubar on a first come-first served basis...
4657 //
4658 // richard@whitequeen.com jul 99
4659
4660 BMenu *tmp;
4661
4662 if ( parent )
4663 tmp = parent->submenu_id;
4664 else
4665 tmp = gui.vimForm->MenuBar();
4666 // make sure we don't try and add the same menu twice. The Buffers menu tries to
4667 // do this and Be starts to crash...
4668
4669 if ( ! tmp->FindItem((const char *) menu->dname)) {
4670
4671 BMenu *bmenu = new BMenu((char *)menu->dname);
4672
4673 menu->submenu_id = bmenu;
4674
4675 // when we add a BMenu to another Menu, it creates the interconnecting BMenuItem
4676 tmp->AddItem(bmenu);
4677
4678 // Now its safe to query the menu for the associated MenuItem....
4679 menu->id = tmp->FindItem((const char *) menu->dname);
4680
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004681 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004682 gui.vimWindow->Unlock();
4683 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004684}
4685
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004686 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004687gui_mch_toggle_tearoffs(int enable)
4688{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004689 // no tearoff menus
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004690}
4691
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004692 static BMessage *
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004693MenuMessage(vimmenu_T *menu)
4694{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004695 BMessage *m = new BMessage('menu');
4696 m->AddPointer("VimMenu", (void *)menu);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004697
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004698 return m;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004699}
4700
4701/*
4702 * Add a menu item to a menu
4703 */
4704void
4705gui_mch_add_menu_item(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004706 vimmenu_T *menu,
4707 int idx)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004708{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004709 int mnemonic = 0;
4710 vimmenu_T *parent = menu->parent;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004711
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004712 // TODO: use menu->actext
4713 // This is difficult, since on Be, an accelerator must be a single char
4714 // and a lot of Vim ones are the standard VI commands.
4715 //
4716 // Punt for Now...
4717 // richard@whiequeen.com jul 99
4718 if (gui.vimWindow->Lock())
4719 {
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004720#ifdef FEAT_TOOLBAR
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004721 if (menu_is_toolbar(parent->name)) {
4722 VimToolbar *toolbar = gui.vimForm->ToolBar();
4723 if (toolbar != NULL) {
4724 toolbar->AddButton(idx, menu);
4725 }
4726 } else
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004727#endif
4728
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004729 if (parent->submenu_id != NULL || menu_is_popup(parent->name)) {
4730 if (menu_is_separator(menu->name)) {
4731 BSeparatorItem *item = new BSeparatorItem();
4732 parent->submenu_id->AddItem(item);
4733 menu->id = item;
4734 menu->submenu_id = NULL;
4735 }
4736 else {
4737 BMenuItem *item = new BMenuItem((char *)menu->dname,
4738 MenuMessage(menu));
4739 item->SetTarget(gui.vimTextArea);
4740 item->SetTrigger((char) menu->mnemonic);
4741 parent->submenu_id->AddItem(item);
4742 menu->id = item;
4743 menu->submenu_id = NULL;
4744 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004745 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004746 gui.vimWindow->Unlock();
4747 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004748}
4749
4750/*
4751 * Destroy the machine specific menu widget.
4752 */
4753void
4754gui_mch_destroy_menu(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004755 vimmenu_T *menu)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004756{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004757 if (gui.vimWindow->Lock())
4758 {
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004759#ifdef FEAT_TOOLBAR
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004760 if (menu->parent && menu_is_toolbar(menu->parent->name)) {
4761 VimToolbar *toolbar = gui.vimForm->ToolBar();
4762 if (toolbar != NULL) {
4763 toolbar->RemoveButton(menu);
4764 }
4765 } else
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004766#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004767 {
4768 assert(menu->submenu_id == NULL || menu->submenu_id->CountItems() == 0);
4769 /*
4770 * Detach this menu from its parent, so that it is not deleted
4771 * twice once we get to delete that parent.
4772 * Deleting a BMenuItem also deletes the associated BMenu, if any
4773 * (which does not have any items anymore since they were
4774 * removed and deleted before).
4775 */
4776 BMenu *bmenu = menu->id->Menu();
4777 if (bmenu)
4778 {
4779 bmenu->RemoveItem(menu->id);
4780 /*
4781 * If we removed the last item from the menu bar,
4782 * resize it out of sight.
4783 */
4784 if (bmenu == gui.vimForm->MenuBar() && bmenu->CountItems() == 0)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004785 {
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004786 bmenu->ResizeTo(-MENUBAR_MARGIN, -MENUBAR_MARGIN);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004787 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004788 }
4789 delete menu->id;
4790 menu->id = NULL;
4791 menu->submenu_id = NULL;
4792
4793 gui.menu_height = (int) gui.vimForm->MenuHeight();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004794 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004795 gui.vimWindow->Unlock();
4796 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004797}
4798
4799/*
4800 * Make a menu either grey or not grey.
4801 */
4802void
4803gui_mch_menu_grey(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004804 vimmenu_T *menu,
4805 int grey)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004806{
4807#ifdef FEAT_TOOLBAR
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004808 if (menu->parent && menu_is_toolbar(menu->parent->name)) {
4809 if (gui.vimWindow->Lock()) {
4810 VimToolbar *toolbar = gui.vimForm->ToolBar();
4811 if (toolbar != NULL) {
4812 toolbar->GrayButton(menu, grey);
4813 }
4814 gui.vimWindow->Unlock();
4815 }
4816 } else
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004817#endif
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004818 if (menu->id != NULL)
4819 menu->id->SetEnabled(!grey);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004820}
4821
4822/*
4823 * Make menu item hidden or not hidden
4824 */
4825void
4826gui_mch_menu_hidden(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004827 vimmenu_T *menu,
4828 int hidden)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004829{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004830 if (menu->id != NULL)
4831 menu->id->SetEnabled(!hidden);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004832}
4833
4834/*
4835 * This is called after setting all the menus to grey/hidden or not.
4836 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004837 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004838gui_mch_draw_menubar()
4839{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004840 // Nothing to do in BeOS
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004841}
4842
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004843 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004844gui_mch_show_popupmenu(vimmenu_T *menu)
4845{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004846 if (!menu_is_popup(menu->name) || menu->submenu_id == NULL)
4847 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004848
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004849 BPopUpMenu* popupMenu = dynamic_cast<BPopUpMenu*>(menu->submenu_id);
4850 if (popupMenu == NULL)
4851 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004852
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004853 BPoint point;
4854 if (gui.vimWindow->Lock()) {
4855 uint32 buttons = 0;
4856 gui.vimTextArea->GetMouse(&point, &buttons);
4857 gui.vimTextArea->ConvertToScreen(&point);
4858 gui.vimWindow->Unlock();
4859 }
4860 popupMenu->Go(point, true);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004861}
4862
4863#endif // FEAT_MENU
4864
4865// Mouse stuff
4866
4867#ifdef FEAT_CLIPBOARD
4868/*
4869 * Clipboard stuff, for cutting and pasting text to other windows.
4870 */
4871char textplain[] = "text/plain";
4872char vimselectiontype[] = "application/x-vnd.Rhialto-Vim-selectiontype";
4873
4874/*
4875 * Get the current selection and put it in the clipboard register.
4876 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004877 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004878clip_mch_request_selection(Clipboard_T *cbd)
4879{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004880 if (be_clipboard->Lock())
4881 {
4882 BMessage *m = be_clipboard->Data();
4883 // m->PrintToStream();
4884
4885 char_u *string = NULL;
4886 ssize_t stringlen = -1;
4887
4888 if (m->FindData(textplain, B_MIME_TYPE,
4889 (const void **)&string, &stringlen) == B_OK
4890 || m->FindString("text", (const char **)&string) == B_OK)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004891 {
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004892 if (stringlen == -1)
4893 stringlen = STRLEN(string);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004894
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004895 int type;
4896 char *seltype;
4897 ssize_t seltypelen;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004898
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004899 /*
4900 * Try to get the special vim selection type first
4901 */
4902 if (m->FindData(vimselectiontype, B_MIME_TYPE,
4903 (const void **)&seltype, &seltypelen) == B_OK)
4904 {
4905 switch (*seltype)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004906 {
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004907 default:
4908 case 'L': type = MLINE; break;
4909 case 'C': type = MCHAR; break;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004910#ifdef FEAT_VISUAL
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004911 case 'B': type = MBLOCK; break;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004912#endif
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004913 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004914 }
4915 else
4916 {
4917 // Otherwise use heuristic as documented
4918 type = memchr(string, stringlen, '\n') ? MLINE : MCHAR;
4919 }
4920 clip_yank_selection(type, string, (long)stringlen, cbd);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004921 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004922 be_clipboard->Unlock();
4923 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004924}
4925/*
4926 * Make vim the owner of the current selection.
4927 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004928 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004929clip_mch_lose_selection(Clipboard_T *cbd)
4930{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004931 // Nothing needs to be done here
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004932}
4933
4934/*
4935 * Make vim the owner of the current selection. Return OK upon success.
4936 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004937 int
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004938clip_mch_own_selection(Clipboard_T *cbd)
4939{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004940 /*
4941 * Never actually own the clipboard. If another application sets the
4942 * clipboard, we don't want to think that we still own it.
4943 */
4944 return FAIL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004945}
4946
4947/*
4948 * Send the current selection to the clipboard.
4949 */
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004950 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004951clip_mch_set_selection(Clipboard_T *cbd)
4952{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004953 if (be_clipboard->Lock())
4954 {
4955 be_clipboard->Clear();
4956 BMessage *m = be_clipboard->Data();
4957 assert(m);
4958
4959 // If the '*' register isn't already filled in, fill it in now
4960 cbd->owned = TRUE;
4961 clip_get_selection(cbd);
4962 cbd->owned = FALSE;
4963
4964 char_u *str = NULL;
4965 long_u count;
4966 int type;
4967
4968 type = clip_convert_selection(&str, &count, cbd);
4969
4970 if (type < 0)
4971 return;
4972
4973 m->AddData(textplain, B_MIME_TYPE, (void *)str, count);
4974
4975 // Add type of selection
4976 char vtype;
4977 switch (type)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004978 {
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004979 default:
4980 case MLINE: vtype = 'L'; break;
4981 case MCHAR: vtype = 'C'; break;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004982#ifdef FEAT_VISUAL
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004983 case MBLOCK: vtype = 'B'; break;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004984#endif
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004985 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02004986 m->AddData(vimselectiontype, B_MIME_TYPE, (void *)&vtype, 1);
4987
4988 vim_free(str);
4989
4990 be_clipboard->Commit();
4991 be_clipboard->Unlock();
4992 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004993}
4994
4995#endif // FEAT_CLIPBOARD
4996
4997#ifdef FEAT_BROWSE
4998/*
4999 * Pop open a file browser and return the file selected, in allocated memory,
5000 * or NULL if Cancel is hit.
5001 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
5002 * title - Title message for the file browser dialog.
5003 * dflt - Default name of file.
5004 * ext - Default extension to be added to files without extensions.
5005 * initdir - directory in which to open the browser (NULL = current dir)
5006 * filter - Filter for matched files to choose from.
5007 * Has a format like this:
5008 * "C Files (*.c)\0*.c\0"
5009 * "All Files\0*.*\0\0"
5010 * If these two strings were concatenated, then a choice of two file
5011 * filters will be selectable to the user. Then only matching files will
5012 * be shown in the browser. If NULL, the default allows all files.
5013 *
5014 * *NOTE* - the filter string must be terminated with TWO nulls.
5015 */
5016char_u *
5017gui_mch_browse(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005018 int saving,
5019 char_u *title,
5020 char_u *dflt,
5021 char_u *ext,
5022 char_u *initdir,
5023 char_u *filter)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005024{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005025 gui.vimApp->fFilePanel = new BFilePanel((saving == TRUE) ? B_SAVE_PANEL : B_OPEN_PANEL,
5026 NULL, NULL, 0, false,
5027 new BMessage((saving == TRUE) ? 'save' : 'open'), NULL, true);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005028
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005029 gui.vimApp->fBrowsedPath.Unset();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005030
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005031 gui.vimApp->fFilePanel->Window()->SetTitle((char*)title);
5032 gui.vimApp->fFilePanel->SetPanelDirectory((const char*)initdir);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005033
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005034 gui.vimApp->fFilePanel->Show();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005035
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005036 gui.vimApp->fFilePanelSem = create_sem(0, "FilePanelSem");
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005037
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005038 while (acquire_sem(gui.vimApp->fFilePanelSem) == B_INTERRUPTED);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005039
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005040 char_u *fileName = NULL;
5041 status_t result = gui.vimApp->fBrowsedPath.InitCheck();
5042 if (result == B_OK) {
5043 fileName = vim_strsave((char_u*)gui.vimApp->fBrowsedPath.Path());
5044 } else
5045 if (result != B_NO_INIT) {
5046 fprintf(stderr, "gui_mch_browse: BPath error: %#08x (%s)\n",
5047 result, strerror(result));
5048 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005049
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005050 delete gui.vimApp->fFilePanel;
5051 gui.vimApp->fFilePanel = NULL;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005052
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005053 return fileName;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005054}
5055#endif // FEAT_BROWSE
5056
5057
5058#if defined(FEAT_GUI_DIALOG)
5059
5060/*
5061 * Create a dialog dynamically from the parameter strings.
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005062 * type = type of dialog (question, alert, etc.)
5063 * title = dialog title. may be NULL for default title.
5064 * message = text to display. Dialog sizes to accommodate it.
5065 * buttons = '\n' separated list of button captions, default first.
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005066 * dfltbutton = number of default button.
5067 *
5068 * This routine returns 1 if the first button is pressed,
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005069 * 2 for the second, etc.
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005070 *
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005071 * 0 indicates Esc was pressed.
5072 * -1 for unexpected error
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005073 *
5074 * If stubbing out this fn, return 1.
5075 */
5076
5077int
5078gui_mch_dialog(
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005079 int type,
5080 char_u *title,
5081 char_u *message,
5082 char_u *buttons,
5083 int dfltbutton,
5084 char_u *textfield,
5085 int ex_cmd)
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005086{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005087 VimDialog *dialog = new VimDialog(type, (char*)title, (char*)message,
5088 (char*)buttons, dfltbutton, (char*)textfield, ex_cmd);
5089 return dialog->Go();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005090}
5091
5092#endif // FEAT_GUI_DIALOG
5093
5094
5095/*
5096 * Return the RGB value of a pixel as long.
5097 */
5098 guicolor_T
5099gui_mch_get_rgb(guicolor_T pixel)
5100{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005101 rgb_color rgb = GUI_TO_RGB(pixel);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005102
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005103 return ((rgb.red & 0xff) << 16) + ((rgb.green & 0xff) << 8)
5104 + (rgb.blue & 0xff);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005105}
5106
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005107 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005108gui_mch_setmouse(int x, int y)
5109{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005110 TRACE();
5111 // TODO
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005112}
5113
5114#ifdef FEAT_MBYTE_IME
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005115 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005116im_set_position(int row, int col)
5117{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005118 if (gui.vimWindow->Lock())
5119 {
5120 gui.vimTextArea->DrawIMString();
5121 gui.vimWindow->Unlock();
5122 }
5123 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005124}
5125#endif
5126
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005127 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005128gui_mch_show_toolbar(int showit)
5129{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005130 VimToolbar *toolbar = gui.vimForm->ToolBar();
5131 gui.toolbar_height = (toolbar && showit) ? toolbar->ToolbarHeight() : 0.;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005132}
5133
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005134 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005135gui_mch_set_toolbar_pos(int x, int y, int w, int h)
5136{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005137 VimToolbar *toolbar = gui.vimForm->ToolBar();
5138 if (toolbar != NULL) {
5139 if (gui.vimWindow->Lock()) {
5140 toolbar->MoveTo(x, y);
5141 toolbar->ResizeTo(w - 1, h - 1);
5142 gui.vimWindow->Unlock();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005143 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005144 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005145}
5146
5147#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
5148
5149/*
5150 * Show or hide the tabline.
5151 */
5152 void
5153gui_mch_show_tabline(int showit)
5154{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005155 VimTabLine *tabLine = gui.vimForm->TabLine();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005156
5157 if (tabLine == NULL)
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005158 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005159
5160 if (!showit != !gui.vimForm->IsShowingTabLine()) {
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005161 gui.vimForm->SetShowingTabLine(showit != 0);
5162 gui.tabline_height = gui.vimForm->TablineHeight();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005163 }
5164}
5165
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005166 void
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005167gui_mch_set_tabline_pos(int x, int y, int w, int h)
5168{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005169 VimTabLine *tabLine = gui.vimForm->TabLine();
5170 if (tabLine != NULL) {
5171 if (gui.vimWindow->Lock()) {
5172 tabLine->MoveTo(x, y);
5173 tabLine->ResizeTo(w - 1, h - 1);
5174 gui.vimWindow->Unlock();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005175 }
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005176 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005177}
5178
5179/*
5180 * Return TRUE when tabline is displayed.
5181 */
5182 int
5183gui_mch_showing_tabline()
5184{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005185 VimTabLine *tabLine = gui.vimForm->TabLine();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005186 return tabLine != NULL && gui.vimForm->IsShowingTabLine();
5187}
5188
5189/*
5190 * Update the labels of the tabline.
5191 */
5192 void
5193gui_mch_update_tabline()
5194{
5195 tabpage_T *tp;
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005196 int nr = 0;
5197 int curtabidx = 0;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005198
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005199 VimTabLine *tabLine = gui.vimForm->TabLine();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005200
5201 if (tabLine == NULL)
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005202 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005203
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005204 gui.vimWindow->Lock();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005205
5206 // Add a label for each tab page. They all contain the same text area.
5207 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr) {
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005208 if (tp == curtab)
5209 curtabidx = nr;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005210
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005211 BTab* tab = tabLine->TabAt(nr);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005212
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005213 if (tab == NULL) {
5214 tab = new VimTabLine::VimTab();
5215 tabLine->AddTab(NULL, tab);
5216 }
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005217
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005218 get_tabline_label(tp, FALSE);
5219 tab->SetLabel((const char*)NameBuff);
5220 tabLine->Invalidate();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005221 }
5222
5223 // Remove any old labels.
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005224 while (nr < tabLine->CountTabs())
5225 tabLine->RemoveTab(nr);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005226
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005227 if (tabLine->Selection() != curtabidx)
5228 tabLine->Select(curtabidx);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005229
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005230 gui.vimWindow->Unlock();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005231}
5232
5233/*
5234 * Set the current tab to "nr". First tab is 1.
5235 */
5236 void
5237gui_mch_set_curtab(int nr)
5238{
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005239 VimTabLine *tabLine = gui.vimForm->TabLine();
5240 if (tabLine == NULL)
5241 return;
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005242
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005243 gui.vimWindow->Lock();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005244
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005245 if (tabLine->Selection() != nr -1)
5246 tabLine->Select(nr -1);
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005247
Bram Moolenaarb52575f2020-04-24 22:16:13 +02005248 gui.vimWindow->Unlock();
Bram Moolenaarb3f74062020-02-26 16:16:53 +01005249}
5250
5251#endif // FEAT_GUI_TABLINE