7
|
1 /* 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.
|
|
5 * All Rights Reserved.
|
|
6 *
|
|
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 * BeOS GUI.
|
|
11 *
|
|
12 * GUI support for the Buzzword Enhanced Operating System.
|
|
13 *
|
|
14 * Ported to R4 by Richard Offer <richard@whitequeen.com> Jul 99
|
|
15 *
|
|
16 */
|
|
17
|
|
18 /*
|
|
19 * Structure of the BeOS 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 extern "C" {
|
|
71
|
|
72 #define new xxx_new_xxx
|
|
73
|
|
74 #include <float.h>
|
|
75 #include <assert.h>
|
|
76 #include "vim.h"
|
|
77 #include "globals.h"
|
|
78 #include "proto.h"
|
|
79 #include "option.h"
|
|
80
|
|
81 #undef new
|
|
82
|
|
83 } /* extern "C" */
|
|
84
|
|
85 /* ---------------- start of header part ---------------- */
|
|
86
|
|
87 #include <be/app/MessageQueue.h>
|
|
88 #include <be/app/Clipboard.h>
|
|
89 #include <be/kernel/OS.h>
|
|
90 #include <be/support/Beep.h>
|
|
91 #include <be/interface/View.h>
|
|
92 #include <be/interface/Window.h>
|
|
93 #include <be/interface/MenuBar.h>
|
|
94 #include <be/interface/MenuItem.h>
|
|
95 #include <be/interface/ScrollBar.h>
|
|
96 #include <be/interface/Region.h>
|
|
97 #include <be/interface/Screen.h>
|
|
98 #include <be/storage/Path.h>
|
|
99 #include <be/storage/Directory.h>
|
|
100 #include <be/storage/Entry.h>
|
|
101 #include <be/app/Application.h>
|
|
102 #include <be/support/Debug.h>
|
|
103
|
|
104 /*
|
|
105 * The macro B_PIXEL_ALIGNMENT shows us which version
|
|
106 * of the header files we're using.
|
|
107 */
|
|
108 #if defined(B_PIXEL_ALIGNMENT)
|
|
109 #define HAVE_R3_OR_LATER 1
|
|
110 #else
|
|
111 #define HAVE_R3_OR_LATER 0
|
|
112 #endif
|
|
113
|
|
114 class VimApp;
|
|
115 class VimFormView;
|
|
116 class VimTextAreaView;
|
|
117 class VimWindow;
|
|
118
|
|
119 extern key_map *keyMap;
|
|
120 extern char *keyMapChars;
|
|
121
|
|
122 extern int main(int argc, char **argv);
|
|
123
|
|
124 #ifndef B_MAX_PORT_COUNT
|
|
125 #define B_MAX_PORT_COUNT 100
|
|
126 #endif
|
|
127
|
|
128 /*
|
|
129 * VimApp seems comparable to the X "vimShell"
|
|
130 */
|
|
131 class VimApp: public BApplication
|
|
132 {
|
|
133 typedef BApplication Inherited;
|
|
134 public:
|
|
135 VimApp(const char *appsig);
|
|
136 ~VimApp();
|
|
137
|
|
138 // callbacks:
|
|
139 #if 0
|
|
140 virtual void DispatchMessage(BMessage *m, BHandler *h)
|
|
141 {
|
|
142 m->PrintToStream();
|
|
143 Inherited::DispatchMessage(m, h);
|
|
144 }
|
|
145 #endif
|
|
146 virtual void ReadyToRun();
|
|
147 virtual void ArgvReceived(int32 argc, char **argv);
|
|
148 virtual void RefsReceived(BMessage *m);
|
|
149 virtual bool QuitRequested();
|
|
150
|
|
151 static void SendRefs(BMessage *m, bool changedir);
|
|
152 private:
|
|
153 };
|
|
154
|
|
155 class VimWindow: public BWindow
|
|
156 {
|
|
157 typedef BWindow Inherited;
|
|
158 public:
|
|
159 VimWindow();
|
|
160 ~VimWindow();
|
|
161
|
|
162 virtual void DispatchMessage(BMessage *m, BHandler *h);
|
|
163 virtual void WindowActivated(bool active);
|
|
164 virtual bool QuitRequested();
|
|
165
|
|
166 VimFormView *formView;
|
|
167
|
|
168 private:
|
|
169 void init();
|
|
170
|
|
171 };
|
|
172
|
|
173 class VimFormView: public BView
|
|
174 {
|
|
175 typedef BView Inherited;
|
|
176 public:
|
|
177 VimFormView(BRect frame);
|
|
178 ~VimFormView();
|
|
179
|
|
180 // callbacks:
|
|
181 virtual void AllAttached();
|
|
182 virtual void FrameResized(float new_width, float new_height);
|
|
183
|
|
184 #define MENUBAR_MARGIN 1
|
|
185 float MenuHeight() const
|
|
186 { return menuBar ? menuBar->Frame().Height() + MENUBAR_MARGIN: 0; }
|
|
187 BMenuBar *MenuBar() const
|
|
188 { return menuBar; }
|
|
189
|
|
190 private:
|
|
191 void init(BRect);
|
|
192
|
|
193 BMenuBar *menuBar;
|
|
194 VimTextAreaView *textArea;
|
|
195 };
|
|
196
|
|
197 class VimTextAreaView: public BView
|
|
198 {
|
|
199 typedef BView Inherited;
|
|
200 public:
|
|
201 VimTextAreaView(BRect frame);
|
|
202 ~VimTextAreaView();
|
|
203
|
|
204 // callbacks:
|
|
205 virtual void Draw(BRect updateRect);
|
|
206 virtual void KeyDown(const char *bytes, int32 numBytes);
|
|
207 virtual void MouseDown(BPoint point);
|
|
208 virtual void MouseUp(BPoint point);
|
|
209 virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *message);
|
|
210 virtual void MessageReceived(BMessage *m);
|
|
211
|
|
212 // own functions:
|
|
213 int mchInitFont(char_u *name);
|
|
214 void mchDrawString(int row, int col, char_u *s, int len, int flags);
|
|
215 void mchClearBlock(int row1, int col1, int row2, int col2);
|
|
216 void mchClearAll();
|
|
217 void mchDeleteLines(int row, int num_lines);
|
|
218 void mchInsertLines(int row, int num_lines);
|
|
219
|
|
220 static void guiSendMouseEvent(int button, int x, int y, int repeated_click, int_u modifiers);
|
|
221 static void guiBlankMouse(bool should_hide);
|
|
222 static int_u mouseModifiersToVim(int32 beModifiers);
|
|
223
|
|
224 int32 mouseDragEventCount;
|
|
225
|
|
226 private:
|
|
227 void init(BRect);
|
|
228
|
|
229 int_u vimMouseButton;
|
|
230 int_u vimMouseModifiers;
|
|
231 };
|
|
232
|
|
233 class VimScrollBar: public BScrollBar
|
|
234 {
|
|
235 typedef BScrollBar Inherited;
|
|
236 public:
|
|
237 VimScrollBar(scrollbar_T *gsb, orientation posture);
|
|
238 ~VimScrollBar();
|
|
239
|
|
240 virtual void ValueChanged(float newValue);
|
|
241 virtual void MouseUp(BPoint where);
|
|
242 void SetValue(float newval);
|
|
243 scrollbar_T *getGsb()
|
|
244 { return gsb; }
|
|
245
|
|
246 int32 scrollEventCount;
|
|
247
|
|
248 private:
|
|
249 scrollbar_T *gsb;
|
|
250 float ignoreValue;
|
|
251 };
|
|
252
|
|
253
|
|
254 /*
|
|
255 * For caching the fonts that are used;
|
|
256 * Vim seems rather sloppy in this regard.
|
|
257 */
|
|
258 class VimFont: public BFont
|
|
259 {
|
|
260 typedef BFont Inherited;
|
|
261 public:
|
|
262 VimFont();
|
|
263 VimFont(const VimFont *rhs);
|
|
264 VimFont(const BFont *rhs);
|
|
265 VimFont(const VimFont &rhs);
|
|
266 ~VimFont();
|
|
267
|
|
268 VimFont *next;
|
|
269 int refcount;
|
|
270 char_u *name;
|
|
271
|
|
272 private:
|
|
273 void init();
|
|
274 };
|
|
275
|
|
276 /* ---------------- end of GUI classes ---------------- */
|
|
277
|
|
278 struct MainArgs {
|
|
279 int argc;
|
|
280 char **argv;
|
|
281 };
|
|
282
|
|
283 /*
|
|
284 * These messages are copied through the VDCMP.
|
|
285 * Therefore they ought not to have anything fancy.
|
|
286 * They must be of POD type (Plain Old Data)
|
|
287 * as the C++ standard calls them.
|
|
288 */
|
|
289
|
|
290 #define KEY_MSG_BUFSIZ 7
|
|
291 #if KEY_MSG_BUFSIZ < MAX_KEY_CODE_LEN
|
|
292 #error Increase KEY_MSG_BUFSIZ!
|
|
293 #endif
|
|
294
|
|
295 struct VimKeyMsg {
|
|
296 char_u length;
|
|
297 char_u chars[KEY_MSG_BUFSIZ]; /* contains Vim encoding */
|
|
298 };
|
|
299
|
|
300 struct VimResizeMsg {
|
|
301 int width;
|
|
302 int height;
|
|
303 };
|
|
304
|
|
305 struct VimScrollBarMsg {
|
|
306 VimScrollBar *sb;
|
|
307 long value;
|
|
308 int stillDragging;
|
|
309 };
|
|
310
|
|
311 struct VimMenuMsg {
|
|
312 vimmenu_T *guiMenu;
|
|
313 };
|
|
314
|
|
315 struct VimMouseMsg {
|
|
316 int button;
|
|
317 int x;
|
|
318 int y;
|
|
319 int repeated_click;
|
|
320 int_u modifiers;
|
|
321 };
|
|
322
|
|
323 struct VimFocusMsg {
|
|
324 bool active;
|
|
325 };
|
|
326
|
|
327 struct VimRefsMsg {
|
|
328 BMessage *message;
|
|
329 bool changedir;
|
|
330 };
|
|
331
|
|
332 struct VimMsg {
|
|
333 enum VimMsgType {
|
|
334 Key, Resize, ScrollBar, Menu, Mouse, Focus, Refs
|
|
335 };
|
|
336
|
|
337 union {
|
|
338 struct VimKeyMsg Key;
|
|
339 struct VimResizeMsg NewSize;
|
|
340 struct VimScrollBarMsg Scroll;
|
|
341 struct VimMenuMsg Menu;
|
|
342 struct VimMouseMsg Mouse;
|
|
343 struct VimFocusMsg Focus;
|
|
344 struct VimRefsMsg Refs;
|
|
345 } u;
|
|
346 };
|
|
347
|
|
348 #define RGB(r, g, b) ((char_u)(r) << 16 | (char_u)(g) << 8 | (char_u)(b) << 0)
|
|
349 #define GUI_TO_RGB(g) { (g) >> 16, (g) >> 8, (g) >> 0, 255 }
|
|
350
|
|
351 /* ---------------- end of header part ---------------- */
|
|
352
|
|
353 static struct specialkey
|
|
354 {
|
|
355 uint16 BeKeys;
|
|
356 #define KEY(a,b) ((a)<<8|(b))
|
|
357 #define K(a) KEY(0,a) // for ASCII codes
|
|
358 #define F(b) KEY(1,b) // for scancodes
|
|
359 char_u vim_code0;
|
|
360 char_u vim_code1;
|
|
361 } special_keys[] =
|
|
362 {
|
|
363 {K(B_UP_ARROW), 'k', 'u'},
|
|
364 {K(B_DOWN_ARROW), 'k', 'd'},
|
|
365 {K(B_LEFT_ARROW), 'k', 'l'},
|
|
366 {K(B_RIGHT_ARROW), 'k', 'r'},
|
|
367 {K(B_BACKSPACE), 'k', 'b'},
|
|
368 {K(B_INSERT), 'k', 'I'},
|
|
369 {K(B_DELETE), 'k', 'D'},
|
|
370 {K(B_HOME), 'k', 'h'},
|
|
371 {K(B_END), '@', '7'},
|
|
372 {K(B_PAGE_UP), 'k', 'P'}, /* XK_Prior */
|
|
373 {K(B_PAGE_DOWN), 'k', 'N'}, /* XK_Next, */
|
|
374
|
|
375 #define FIRST_FUNCTION_KEY 11
|
|
376 {F(B_F1_KEY), 'k', '1'},
|
|
377 {F(B_F2_KEY), 'k', '2'},
|
|
378 {F(B_F3_KEY), 'k', '3'},
|
|
379 {F(B_F4_KEY), 'k', '4'},
|
|
380 {F(B_F5_KEY), 'k', '5'},
|
|
381 {F(B_F6_KEY), 'k', '6'},
|
|
382 {F(B_F7_KEY), 'k', '7'},
|
|
383 {F(B_F8_KEY), 'k', '8'},
|
|
384 {F(B_F9_KEY), 'k', '9'},
|
|
385 {F(B_F10_KEY), 'k', ';'},
|
|
386
|
|
387 {F(B_F11_KEY), 'F', '1'},
|
|
388 {F(B_F12_KEY), 'F', '2'},
|
|
389 // {XK_F13, 'F', '3'}, /* would be print screen/ */
|
|
390 /* sysreq */
|
|
391 {F(0x0F), 'F', '4'}, /* scroll lock */
|
|
392 {F(0x10), 'F', '5'}, /* pause/break */
|
|
393 // {XK_F16, 'F', '6'},
|
|
394 // {XK_F17, 'F', '7'},
|
|
395 // {XK_F18, 'F', '8'},
|
|
396 // {XK_F19, 'F', '9'},
|
|
397 // {XK_F20, 'F', 'A'},
|
|
398 //
|
|
399 // {XK_F21, 'F', 'B'},
|
|
400 // {XK_F22, 'F', 'C'},
|
|
401 // {XK_F23, 'F', 'D'},
|
|
402 // {XK_F24, 'F', 'E'},
|
|
403 // {XK_F25, 'F', 'F'},
|
|
404 // {XK_F26, 'F', 'G'},
|
|
405 // {XK_F27, 'F', 'H'},
|
|
406 // {XK_F28, 'F', 'I'},
|
|
407 // {XK_F29, 'F', 'J'},
|
|
408 // {XK_F30, 'F', 'K'},
|
|
409 //
|
|
410 // {XK_F31, 'F', 'L'},
|
|
411 // {XK_F32, 'F', 'M'},
|
|
412 // {XK_F33, 'F', 'N'},
|
|
413 // {XK_F34, 'F', 'O'},
|
|
414 // {XK_F35, 'F', 'P'}, /* keysymdef.h defines up to F35 */
|
|
415
|
|
416 // {XK_Help, '%', '1'}, /* XK_Help */
|
|
417 {F(B_PRINT_KEY), '%', '9'},
|
|
418
|
|
419 #if 0
|
|
420 /* Keypad keys: */
|
|
421 {F(0x48), 'k', 'l'}, /* XK_KP_Left */
|
|
422 {F(0x4A), 'k', 'r'}, /* XK_KP_Right */
|
|
423 {F(0x38), 'k', 'u'}, /* XK_KP_Up */
|
|
424 {F(0x59), 'k', 'd'}, /* XK_KP_Down */
|
|
425 {F(0x64), 'k', 'I'}, /* XK_KP_Insert */
|
|
426 {F(0x65), 'k', 'D'}, /* XK_KP_Delete */
|
|
427 {F(0x37), 'k', 'h'}, /* XK_KP_Home */
|
|
428 {F(0x58), '@', '7'}, /* XK_KP_End */
|
|
429 {F(0x39), 'k', 'P'}, /* XK_KP_Prior */
|
|
430 {F(0x60), 'k', 'N'}, /* XK_KP_Next */
|
|
431 {F(0x49), '&', '8'}, /* XK_Undo, keypad 5 */
|
|
432 #endif
|
|
433
|
|
434 /* End of list marker: */
|
|
435 {0, 0, 0}
|
|
436 };
|
|
437
|
|
438 #define NUM_SPECIAL_KEYS (sizeof(special_keys)/sizeof(special_keys[0]))
|
|
439
|
|
440 /* ---------------- VimApp ---------------- */
|
|
441
|
|
442 static void
|
|
443 docd(BPath &path)
|
|
444 {
|
|
445 mch_chdir(path.Path());
|
|
446 /* Do this to get the side effects of a :cd command */
|
|
447 do_cmdline_cmd((char_u *)"cd .");
|
|
448 }
|
|
449
|
|
450 /*
|
|
451 * Really handle dropped files and folders.
|
|
452 */
|
|
453 static void
|
|
454 RefsReceived(BMessage *m, bool changedir)
|
|
455 {
|
|
456 uint32 type;
|
|
457 int32 count;
|
|
458
|
|
459 //m->PrintToStream();
|
|
460 switch (m->what) {
|
|
461 case B_REFS_RECEIVED:
|
|
462 case B_SIMPLE_DATA:
|
|
463 m->GetInfo("refs", &type, &count);
|
|
464 if (type != B_REF_TYPE)
|
|
465 goto bad;
|
|
466 break;
|
|
467 case B_ARGV_RECEIVED:
|
|
468 m->GetInfo("argv", &type, &count);
|
|
469 if (type != B_STRING_TYPE)
|
|
470 goto bad;
|
|
471 if (changedir) {
|
|
472 char *dirname;
|
|
473 if (m->FindString("cwd", (const char **) &dirname) == B_OK) {
|
|
474 chdir(dirname);
|
|
475 do_cmdline_cmd((char_u *)"cd .");
|
|
476 }
|
|
477 }
|
|
478 break;
|
|
479 default:
|
|
480 bad:
|
|
481 //fprintf(stderr, "bad!\n");
|
|
482 delete m;
|
|
483 return;
|
|
484 }
|
|
485
|
|
486 #ifdef FEAT_VISUAL
|
|
487 reset_VIsual();
|
|
488 #endif
|
|
489
|
|
490 char_u **fnames;
|
|
491 fnames = (char_u **) alloc(count * sizeof(char_u *));
|
|
492 int fname_index = 0;
|
|
493
|
|
494 switch (m->what) {
|
|
495 case B_REFS_RECEIVED:
|
|
496 case B_SIMPLE_DATA:
|
|
497 //fprintf(stderr, "case B_REFS_RECEIVED\n");
|
|
498 for (int i = 0; i < count; ++i)
|
|
499 {
|
|
500 entry_ref ref;
|
|
501 if (m->FindRef("refs", i, &ref) == B_OK) {
|
|
502 BEntry entry(&ref, false);
|
|
503 BPath path;
|
|
504 entry.GetPath(&path);
|
|
505
|
|
506 /* Change to parent directory? */
|
|
507 if (changedir) {
|
|
508 BPath parentpath;
|
|
509 path.GetParent(&parentpath);
|
|
510 docd(parentpath);
|
|
511 }
|
|
512
|
|
513 /* Is it a directory? If so, cd into it. */
|
|
514 BDirectory bdir(&ref);
|
|
515 if (bdir.InitCheck() == B_OK) {
|
|
516 /* don't cd if we already did it */
|
|
517 if (!changedir)
|
|
518 docd(path);
|
|
519 } else {
|
|
520 mch_dirname(IObuff, IOSIZE);
|
|
521 char_u *fname = shorten_fname((char_u *)path.Path(), IObuff);
|
|
522 if (fname == NULL)
|
|
523 fname = (char_u *)path.Path();
|
|
524 fnames[fname_index++] = vim_strsave(fname);
|
|
525 //fprintf(stderr, "%s\n", fname);
|
|
526 }
|
|
527
|
|
528 /* Only do it for the first file/dir */
|
|
529 changedir = false;
|
|
530 }
|
|
531 }
|
|
532 break;
|
|
533 case B_ARGV_RECEIVED:
|
|
534 //fprintf(stderr, "case B_ARGV_RECEIVED\n");
|
|
535 for (int i = 1; i < count; ++i)
|
|
536 {
|
|
537 char *fname;
|
|
538
|
|
539 if (m->FindString("argv", i, (const char **) &fname) == B_OK) {
|
|
540 fnames[fname_index++] = vim_strsave((char_u *)fname);
|
|
541 }
|
|
542 }
|
|
543 break;
|
|
544 default:
|
|
545 //fprintf(stderr, "case default\n");
|
|
546 break;
|
|
547 }
|
|
548
|
|
549 delete m;
|
|
550
|
|
551 /* Handle the drop, :edit to get to the file */
|
|
552 if (fname_index > 0) {
|
|
553 handle_drop(fname_index, fnames, FALSE);
|
|
554
|
|
555 /* Update the screen display */
|
|
556 update_screen(NOT_VALID);
|
|
557 setcursor();
|
|
558 out_flush();
|
|
559 } else {
|
|
560 vim_free(fnames);
|
|
561 }
|
|
562 }
|
|
563
|
|
564 VimApp::VimApp(const char *appsig):
|
|
565 BApplication(appsig)
|
|
566 {
|
|
567 }
|
|
568
|
|
569 VimApp::~VimApp()
|
|
570 {
|
|
571 }
|
|
572
|
|
573 void
|
|
574 VimApp::ReadyToRun()
|
|
575 {
|
|
576 /*
|
|
577 * Apparently signals are inherited by the created thread -
|
|
578 * disable the most annoying ones.
|
|
579 */
|
|
580 signal(SIGINT, SIG_IGN);
|
|
581 signal(SIGQUIT, SIG_IGN);
|
|
582 }
|
|
583
|
|
584 void
|
|
585 VimApp::ArgvReceived(int32 arg_argc, char **arg_argv)
|
|
586 {
|
|
587 if (!IsLaunching()) {
|
|
588 /*
|
|
589 * This can happen if we are set to Single or Exclusive
|
|
590 * Launch. Be nice and open the file(s).
|
|
591 */
|
|
592 if (gui.vimWindow)
|
|
593 gui.vimWindow->Minimize(false);
|
|
594 BMessage *m = CurrentMessage();
|
|
595 DetachCurrentMessage();
|
|
596 SendRefs(m, true);
|
|
597 }
|
|
598 }
|
|
599
|
|
600 void
|
|
601 VimApp::RefsReceived(BMessage *m)
|
|
602 {
|
|
603 /* Horrible hack!!! XXX XXX XXX
|
|
604 * The real problem is that b_start_ffc is set too late for
|
|
605 * the initial empty buffer. As a result the window will be
|
|
606 * split instead of abandoned.
|
|
607 */
|
|
608 int limit = 15;
|
|
609 while (--limit >= 0 && (curbuf == NULL || curbuf->b_start_ffc == 0))
|
|
610 snooze(100000); // 0.1 s
|
|
611 if (gui.vimWindow)
|
|
612 gui.vimWindow->Minimize(false);
|
|
613 DetachCurrentMessage();
|
|
614 SendRefs(m, true);
|
|
615 }
|
|
616
|
|
617 /*
|
|
618 * Pass a BMessage on to the main() thread.
|
|
619 * Caller must have detached the message.
|
|
620 */
|
|
621 void
|
|
622 VimApp::SendRefs(BMessage *m, bool changedir)
|
|
623 {
|
|
624 VimRefsMsg rm;
|
|
625 rm.message = m;
|
|
626 rm.changedir = changedir;
|
|
627
|
|
628 write_port(gui.vdcmp, VimMsg::Refs, &rm, sizeof(rm));
|
|
629 // calls ::RefsReceived
|
|
630 }
|
|
631
|
|
632 bool
|
|
633 VimApp::QuitRequested()
|
|
634 {
|
|
635 (void)Inherited::QuitRequested();
|
|
636 return false;
|
|
637 }
|
|
638
|
|
639 /* ---------------- VimWindow ---------------- */
|
|
640
|
|
641 VimWindow::VimWindow():
|
|
642 BWindow(BRect(40, 40, 150, 150),
|
|
643 "Vim",
|
|
644 B_TITLED_WINDOW,
|
|
645 0,
|
|
646 B_CURRENT_WORKSPACE)
|
|
647
|
|
648 {
|
|
649 init();
|
|
650 }
|
|
651
|
|
652 VimWindow::~VimWindow()
|
|
653 {
|
|
654 if (formView) {
|
|
655 RemoveChild(formView);
|
|
656 delete formView;
|
|
657 }
|
|
658 gui.vimWindow = NULL;
|
|
659 }
|
|
660
|
|
661 void
|
|
662 VimWindow::init()
|
|
663 {
|
|
664 /* Attach the VimFormView */
|
|
665 formView = new VimFormView(Bounds());
|
|
666 if (formView != NULL) {
|
|
667 AddChild(formView);
|
|
668 }
|
|
669 }
|
|
670
|
|
671 void
|
|
672 VimWindow::DispatchMessage(BMessage *m, BHandler *h)
|
|
673 {
|
|
674 /*
|
|
675 * Route B_MOUSE_UP messages to MouseUp(), in
|
|
676 * a manner that should be compatible with the
|
|
677 * intended future system behaviour.
|
|
678 */
|
|
679 switch (m->what) {
|
|
680 case B_MOUSE_UP:
|
|
681 // if (!h) h = PreferredHandler();
|
|
682 // gcc isn't happy without this extra set of braces, complains about
|
|
683 // jump to case label crosses init of 'class BView * v'
|
|
684 // richard@whitequeen.com jul 99
|
|
685 {
|
|
686 BView *v = dynamic_cast<BView *>(h);
|
|
687 if (v) {
|
|
688 //m->PrintToStream();
|
|
689 BPoint where;
|
|
690 m->FindPoint("where", &where);
|
|
691 v->MouseUp(where);
|
|
692 } else {
|
|
693 Inherited::DispatchMessage(m, h);
|
|
694 }
|
|
695 }
|
|
696 break;
|
|
697 default:
|
|
698 Inherited::DispatchMessage(m, h);
|
|
699 }
|
|
700 }
|
|
701
|
|
702 void
|
|
703 VimWindow::WindowActivated(bool active)
|
|
704 {
|
|
705 Inherited::WindowActivated(active);
|
|
706 /* the textArea gets the keyboard action */
|
|
707 if (active && gui.vimTextArea)
|
|
708 gui.vimTextArea->MakeFocus(true);
|
|
709
|
|
710 struct VimFocusMsg fm;
|
|
711 fm.active = active;
|
|
712
|
|
713 write_port(gui.vdcmp, VimMsg::Focus, &fm, sizeof(fm));
|
|
714 }
|
|
715
|
|
716 bool
|
|
717 VimWindow::QuitRequested()
|
|
718 {
|
|
719 struct VimKeyMsg km;
|
|
720 km.length = 5;
|
|
721 memcpy((char *)km.chars, "\033:qa\r", km.length);
|
|
722
|
|
723 write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km));
|
|
724
|
|
725 return false;
|
|
726 }
|
|
727
|
|
728 /* ---------------- VimFormView ---------------- */
|
|
729
|
|
730 VimFormView::VimFormView(BRect frame):
|
|
731 BView(frame, "VimFormView", B_FOLLOW_ALL_SIDES,
|
|
732 B_WILL_DRAW | B_FRAME_EVENTS),
|
|
733 menuBar(NULL),
|
|
734 textArea(NULL)
|
|
735 {
|
|
736 init(frame);
|
|
737 }
|
|
738
|
|
739 VimFormView::~VimFormView()
|
|
740 {
|
|
741 if (menuBar) {
|
|
742 RemoveChild(menuBar);
|
|
743 #ifdef never
|
|
744 // deleting the menuBar leads to SEGV on exit
|
|
745 // richard@whitequeen.com Jul 99
|
|
746 delete menuBar;
|
|
747 #endif
|
|
748 }
|
|
749 if (textArea) {
|
|
750 RemoveChild(textArea);
|
|
751 delete textArea;
|
|
752 }
|
|
753 gui.vimForm = NULL;
|
|
754 }
|
|
755
|
|
756 void
|
|
757 VimFormView::init(BRect frame)
|
|
758 {
|
|
759 menuBar = new BMenuBar(BRect(0,0,-MENUBAR_MARGIN,-MENUBAR_MARGIN),
|
|
760 "VimMenuBar");
|
|
761
|
|
762 AddChild(menuBar);
|
|
763
|
|
764 BRect remaining = frame;
|
|
765 textArea = new VimTextAreaView(remaining);
|
|
766 AddChild(textArea);
|
|
767 /* The textArea will be resized later when menus are added */
|
|
768
|
|
769 gui.vimForm = this;
|
|
770 }
|
|
771
|
|
772 void
|
|
773 VimFormView::AllAttached()
|
|
774 {
|
|
775 /*
|
|
776 * Apparently signals are inherited by the created thread -
|
|
777 * disable the most annoying ones.
|
|
778 */
|
|
779 signal(SIGINT, SIG_IGN);
|
|
780 signal(SIGQUIT, SIG_IGN);
|
|
781
|
|
782 if (menuBar && textArea) {
|
|
783 /*
|
|
784 * Resize the textArea to fill the space left over by the menu.
|
|
785 * This is somewhat futile since it will be done again once
|
|
786 * menus are added to the menu bar.
|
|
787 */
|
|
788 BRect remaining = Bounds();
|
|
789 remaining.top = MenuHeight();
|
|
790 textArea->ResizeTo(remaining.Width(), remaining.Height());
|
|
791 textArea->MoveTo(remaining.left, remaining.top);
|
|
792
|
|
793 #ifdef FEAT_MENU
|
|
794 menuBar->ResizeTo(remaining.right, remaining.top);
|
|
795 gui.menu_height = (int) remaining.top;
|
|
796 #endif
|
|
797 }
|
|
798 Inherited::AllAttached();
|
|
799 }
|
|
800
|
|
801 void
|
|
802 VimFormView::FrameResized(float new_width, float new_height)
|
|
803 {
|
|
804 BWindow *w = Window();
|
|
805 #if 1
|
|
806 /*
|
|
807 * Look if there are more resize messages in the queue.
|
|
808 * If so, ignore this one. The later one will be handled
|
|
809 * eventually.
|
|
810 */
|
|
811 BMessageQueue *q = w->MessageQueue();
|
|
812 if (q->FindMessage(B_VIEW_RESIZED, 0) != NULL) {
|
|
813 return;
|
|
814 }
|
|
815 #endif
|
|
816 new_width += 1; // adjust from width to number of pixels occupied
|
|
817 new_height += 1;
|
|
818
|
|
819 #if !HAVE_R3_OR_LATER
|
|
820 int adjust_h, adjust_w;
|
|
821
|
|
822 adjust_w = ((int)new_width - gui_get_base_width()) % gui.char_width;
|
|
823 adjust_h = ((int)new_height - gui_get_base_height()) % gui.char_height;
|
|
824
|
|
825 if (adjust_w > 0 || adjust_h > 0) {
|
|
826 /*
|
|
827 * This will generate a new FrameResized() message.
|
|
828 * If we're running R3 or later, SetWindowAlignment() should make
|
|
829 * sure that this does not happen.
|
|
830 */
|
|
831 w->ResizeBy(-adjust_w, -adjust_h);
|
|
832
|
|
833 return;
|
|
834 }
|
|
835 #endif
|
|
836
|
|
837 struct VimResizeMsg sm;
|
|
838 sm.width = (int) new_width;
|
|
839 sm.height = (int) new_height;
|
|
840
|
|
841 write_port(gui.vdcmp, VimMsg::Resize, &sm, sizeof(sm));
|
|
842 // calls gui_resize_shell(new_width, new_height);
|
|
843
|
|
844 return;
|
|
845
|
|
846 /*
|
|
847 * The area below the vertical scrollbar is erased to the colour
|
|
848 * set with SetViewColor() automatically, because we had set
|
|
849 * B_WILL_DRAW. Resizing the window tight around the vertical
|
|
850 * scroll bar also helps to avoid debris.
|
|
851 */
|
|
852 }
|
|
853
|
|
854 /* ---------------- VimTextAreaView ---------------- */
|
|
855
|
|
856 VimTextAreaView::VimTextAreaView(BRect frame):
|
|
857 BView(frame, "VimTextAreaView", B_FOLLOW_ALL_SIDES,
|
|
858 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
|
|
859 mouseDragEventCount(0)
|
|
860 {
|
|
861 init(frame);
|
|
862 }
|
|
863
|
|
864 VimTextAreaView::~VimTextAreaView()
|
|
865 {
|
|
866 gui.vimTextArea = NULL;
|
|
867 }
|
|
868
|
|
869 void
|
|
870 VimTextAreaView::init(BRect frame)
|
|
871 {
|
|
872 /* set up global var for fast access */
|
|
873 gui.vimTextArea = this;
|
|
874
|
|
875 /*
|
|
876 * Tell the app server not to erase the view: we will
|
|
877 * fill it in completely by ourselves.
|
|
878 * (Does this really work? Even if not, it won't harm either.)
|
|
879 */
|
|
880 SetViewColor(B_TRANSPARENT_32_BIT);
|
|
881 #define PEN_WIDTH 1
|
|
882 SetPenSize(PEN_WIDTH);
|
|
883 }
|
|
884
|
|
885 void
|
|
886 VimTextAreaView::Draw(BRect updateRect)
|
|
887 {
|
|
888 /*
|
|
889 * XXX Other ports call here:
|
|
890 * out_flush(); * make sure all output has been processed *
|
|
891 * but we can't do that, since it involves too much information
|
|
892 * that is owned by other threads...
|
|
893 */
|
|
894
|
|
895 /*
|
|
896 * No need to use gui.vimWindow->Lock(): we are locked already.
|
|
897 * However, it would not hurt.
|
|
898 */
|
|
899 gui_redraw((int) updateRect.left, (int) updateRect.top,
|
|
900 (int) (updateRect.Width() + PEN_WIDTH), (int) (updateRect.Height() + PEN_WIDTH));
|
|
901
|
|
902 /* Clear the border areas if needed */
|
|
903 rgb_color rgb = GUI_TO_RGB(gui.back_pixel);
|
|
904 SetLowColor(rgb);
|
|
905
|
|
906 if (updateRect.left < FILL_X(0)) // left border
|
|
907 FillRect(BRect(updateRect.left, updateRect.top,
|
|
908 FILL_X(0)-PEN_WIDTH, updateRect.bottom), B_SOLID_LOW);
|
|
909 if (updateRect.top < FILL_Y(0)) // top border
|
|
910 FillRect(BRect(updateRect.left, updateRect.top,
|
|
911 updateRect.right, FILL_Y(0)-PEN_WIDTH), B_SOLID_LOW);
|
|
912 if (updateRect.right >= FILL_X(Columns)) // right border
|
|
913 FillRect(BRect(FILL_X((int)Columns), updateRect.top,
|
|
914 updateRect.right, updateRect.bottom), B_SOLID_LOW);
|
|
915 if (updateRect.bottom >= FILL_Y(Rows)) // bottom border
|
|
916 FillRect(BRect(updateRect.left, FILL_Y((int)Rows),
|
|
917 updateRect.right, updateRect.bottom), B_SOLID_LOW);
|
|
918 }
|
|
919
|
|
920 void
|
|
921 VimTextAreaView::KeyDown(const char *bytes, int32 numBytes)
|
|
922 {
|
|
923 struct VimKeyMsg km;
|
|
924 char_u *dest = km.chars;
|
|
925
|
|
926 BMessage *msg = Window()->CurrentMessage();
|
|
927 assert(msg);
|
|
928 //msg->PrintToStream();
|
|
929
|
|
930 /*
|
|
931 * Convert special keys to Vim codes.
|
|
932 * I think it is better to do it in the window thread
|
|
933 * so we use at least a little bit of the potential
|
|
934 * of our 2 CPUs. Besides, due to the fantastic mapping
|
|
935 * of special keys to UTF-8, we have quite some work to
|
|
936 * do...
|
|
937 * TODO: I'm not quite happy with detection of special
|
|
938 * keys. Perhaps I should use scan codes after all...
|
|
939 */
|
|
940 if (numBytes > 1) {
|
|
941 /* This cannot be a special key */
|
|
942 if (numBytes > KEY_MSG_BUFSIZ)
|
|
943 numBytes = KEY_MSG_BUFSIZ; // should never happen... ???
|
|
944 km.length = numBytes;
|
|
945 memcpy((char *)dest, bytes, numBytes);
|
|
946 } else {
|
|
947 int32 scancode = 0;
|
|
948 msg->FindInt32("key", &scancode);
|
|
949
|
|
950 int32 beModifiers = 0;
|
|
951 msg->FindInt32("modifiers", &beModifiers);
|
|
952
|
|
953 char_u string[3];
|
|
954 int len = 0;
|
|
955 km.length = 0;
|
|
956
|
|
957 bool canHaveVimModifiers = false;
|
|
958
|
|
959 /*
|
|
960 * For normal, printable ASCII characters, don't look them up
|
|
961 * to check if they might be a special key. They aren't.
|
|
962 */
|
|
963 assert(B_BACKSPACE <= 0x20);
|
|
964 assert(B_DELETE == 0x7F);
|
|
965 if (((char_u)bytes[0] <= 0x20 || (char_u)bytes[0] == 0x7F) &&
|
|
966 numBytes == 1) {
|
|
967 /*
|
|
968 * Due to the great nature of Be's mapping of special keys,
|
|
969 * viz. into the range of the control characters,
|
|
970 * we can only be sure it is *really* a special key if
|
|
971 * if it is special without using ctrl. So, only if ctrl is
|
|
972 * used, we need to check it unmodified.
|
|
973 */
|
|
974 if (beModifiers & B_CONTROL_KEY) {
|
|
975 int index = keyMap->normal_map[scancode];
|
|
976 int newNumBytes = keyMapChars[index];
|
|
977 char_u *newBytes = (char_u *)&keyMapChars[index + 1];
|
|
978
|
|
979 /*
|
|
980 * Check if still special without the control key.
|
|
981 * This is needed for BACKSPACE: that key does produce
|
|
982 * different values with modifiers (DEL).
|
|
983 * Otherwise we could simply have checked for equality.
|
|
984 */
|
|
985 if (newNumBytes != 1 || (*newBytes > 0x20 &&
|
|
986 *newBytes != 0x7F )) {
|
|
987 goto notspecial;
|
|
988 }
|
|
989 bytes = (char *)newBytes;
|
|
990 }
|
|
991 canHaveVimModifiers = true;
|
|
992
|
|
993 uint16 beoskey;
|
|
994 int first, last;
|
|
995
|
|
996 /*
|
|
997 * If numBytes == 0 that probably always indicates a special key.
|
|
998 * (does not happen yet)
|
|
999 */
|
|
1000 if (numBytes == 0 || bytes[0] == B_FUNCTION_KEY) {
|
|
1001 beoskey = F(scancode);
|
|
1002 first = FIRST_FUNCTION_KEY;
|
|
1003 last = NUM_SPECIAL_KEYS;
|
|
1004 } else if (*bytes == '\n' && scancode == 0x47) {
|
|
1005 /* remap the (non-keypad) ENTER key from \n to \r. */
|
|
1006 string[0] = '\r';
|
|
1007 len = 1;
|
|
1008 first = last = 0;
|
|
1009 } else {
|
|
1010 beoskey = K(bytes[0]);
|
|
1011 first = 0;
|
|
1012 last = FIRST_FUNCTION_KEY;
|
|
1013 }
|
|
1014
|
|
1015 for (int i = first; i < last; i++) {
|
|
1016 if (special_keys[i].BeKeys == beoskey) {
|
|
1017 string[0] = CSI;
|
|
1018 string[1] = special_keys[i].vim_code0;
|
|
1019 string[2] = special_keys[i].vim_code1;
|
|
1020 len = 3;
|
|
1021 }
|
|
1022 }
|
|
1023 }
|
|
1024 notspecial:
|
|
1025 if (len == 0) {
|
|
1026 string[0] = bytes[0];
|
|
1027 len = 1;
|
|
1028 }
|
|
1029
|
|
1030 /* Special keys (and a few others) may have modifiers */
|
|
1031 #if 0
|
|
1032 if (len == 3 ||
|
|
1033 bytes[0] == B_SPACE || bytes[0] == B_TAB ||
|
|
1034 bytes[0] == B_RETURN || bytes[0] == '\r' ||
|
|
1035 bytes[0] == B_ESCAPE)
|
|
1036 #else
|
|
1037 if (canHaveVimModifiers)
|
|
1038 #endif
|
|
1039 {
|
|
1040 int modifiers;
|
|
1041 modifiers = 0;
|
|
1042 if (beModifiers & B_SHIFT_KEY)
|
|
1043 modifiers |= MOD_MASK_SHIFT;
|
|
1044 if (beModifiers & B_CONTROL_KEY)
|
|
1045 modifiers |= MOD_MASK_CTRL;
|
|
1046 if (beModifiers & B_OPTION_KEY)
|
|
1047 modifiers |= MOD_MASK_ALT;
|
|
1048
|
|
1049 /*
|
|
1050 * For some keys a shift modifier is translated into another key
|
|
1051 * code. Do we need to handle the case where len != 1 and
|
|
1052 * string[0] != CSI? (Not for BeOS, since len == 3 implies
|
|
1053 * string[0] == CSI...)
|
|
1054 */
|
|
1055 int key;
|
|
1056 if (string[0] == CSI && len == 3)
|
|
1057 key = TO_SPECIAL(string[1], string[2]);
|
|
1058 else
|
|
1059 key = string[0];
|
|
1060 key = simplify_key(key, &modifiers);
|
|
1061 if (IS_SPECIAL(key))
|
|
1062 {
|
|
1063 string[0] = CSI;
|
|
1064 string[1] = K_SECOND(key);
|
|
1065 string[2] = K_THIRD(key);
|
|
1066 len = 3;
|
|
1067 }
|
|
1068 else
|
|
1069 {
|
|
1070 string[0] = key;
|
|
1071 len = 1;
|
|
1072 }
|
|
1073
|
|
1074 if (modifiers)
|
|
1075 {
|
|
1076 *dest++ = CSI;
|
|
1077 *dest++ = KS_MODIFIER;
|
|
1078 *dest++ = modifiers;
|
|
1079 km.length = 3;
|
|
1080 }
|
|
1081 }
|
|
1082 memcpy((char *)dest, string, len);
|
|
1083 km.length += len;
|
|
1084 }
|
|
1085
|
|
1086 write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km));
|
|
1087
|
|
1088 /*
|
|
1089 * blank out the pointer if necessary
|
|
1090 */
|
|
1091 if (p_mh && !gui.pointer_hidden)
|
|
1092 {
|
|
1093 guiBlankMouse(true);
|
|
1094 gui.pointer_hidden = TRUE;
|
|
1095 }
|
|
1096 }
|
|
1097 void
|
|
1098 VimTextAreaView::guiSendMouseEvent(
|
|
1099 int button,
|
|
1100 int x,
|
|
1101 int y,
|
|
1102 int repeated_click,
|
|
1103 int_u modifiers)
|
|
1104 {
|
|
1105 VimMouseMsg mm;
|
|
1106
|
|
1107 mm.button = button;
|
|
1108 mm.x = x;
|
|
1109 mm.y = y;
|
|
1110 mm.repeated_click = repeated_click;
|
|
1111 mm.modifiers = modifiers;
|
|
1112
|
|
1113 write_port(gui.vdcmp, VimMsg::Mouse, &mm, sizeof(mm));
|
|
1114 // calls gui_send_mouse_event()
|
|
1115
|
|
1116 /*
|
|
1117 * if our pointer is currently hidden, then we should show it.
|
|
1118 */
|
|
1119 if (gui.pointer_hidden)
|
|
1120 {
|
|
1121 guiBlankMouse(false);
|
|
1122 gui.pointer_hidden = FALSE;
|
|
1123 }
|
|
1124 }
|
|
1125
|
|
1126 void
|
|
1127 VimTextAreaView::guiBlankMouse(bool should_hide)
|
|
1128 {
|
|
1129 if (should_hide) {
|
|
1130 //gui.vimApp->HideCursor();
|
|
1131 gui.vimApp->ObscureCursor();
|
|
1132 /*
|
|
1133 * ObscureCursor() would even be easier, but then
|
|
1134 * Vim's idea of mouse visibility does not necessarily
|
|
1135 * correspond to reality.
|
|
1136 */
|
|
1137 } else {
|
|
1138 //gui.vimApp->ShowCursor();
|
|
1139 }
|
|
1140 }
|
|
1141
|
|
1142 int_u
|
|
1143 VimTextAreaView::mouseModifiersToVim(int32 beModifiers)
|
|
1144 {
|
|
1145 int_u vim_modifiers = 0x0;
|
|
1146
|
|
1147 if (beModifiers & B_SHIFT_KEY)
|
|
1148 vim_modifiers |= MOUSE_SHIFT;
|
|
1149 if (beModifiers & B_CONTROL_KEY)
|
|
1150 vim_modifiers |= MOUSE_CTRL;
|
|
1151 if (beModifiers & B_OPTION_KEY) /* Alt or Meta key */
|
|
1152 vim_modifiers |= MOUSE_ALT;
|
|
1153
|
|
1154 return vim_modifiers;
|
|
1155 }
|
|
1156
|
|
1157 void
|
|
1158 VimTextAreaView::MouseDown(BPoint point)
|
|
1159 {
|
|
1160 BMessage *m = Window()->CurrentMessage();
|
|
1161 assert(m);
|
|
1162
|
|
1163 int32 buttons = 0;
|
|
1164 m->FindInt32("buttons", &buttons);
|
|
1165
|
|
1166 int vimButton;
|
|
1167
|
|
1168 if (buttons & B_PRIMARY_MOUSE_BUTTON)
|
|
1169 vimButton = MOUSE_LEFT;
|
|
1170 else if (buttons & B_SECONDARY_MOUSE_BUTTON)
|
|
1171 vimButton = MOUSE_RIGHT;
|
|
1172 else if (buttons & B_TERTIARY_MOUSE_BUTTON)
|
|
1173 vimButton = MOUSE_MIDDLE;
|
|
1174 else
|
|
1175 return; /* Unknown button */
|
|
1176
|
|
1177 vimMouseButton = 1; /* don't care which one */
|
|
1178
|
|
1179 /* Handle multiple clicks */
|
|
1180 int32 clicks = 0;
|
|
1181 m->FindInt32("clicks", &clicks);
|
|
1182
|
|
1183 int32 modifiers = 0;
|
|
1184 m->FindInt32("modifiers", &modifiers);
|
|
1185
|
|
1186 vimMouseModifiers = mouseModifiersToVim(modifiers);
|
|
1187
|
|
1188 guiSendMouseEvent(vimButton, point.x, point.y,
|
|
1189 clicks > 1 /* = repeated_click*/, vimMouseModifiers);
|
|
1190 }
|
|
1191
|
|
1192 void
|
|
1193 VimTextAreaView::MouseUp(BPoint point)
|
|
1194 {
|
|
1195 vimMouseButton = 0;
|
|
1196
|
|
1197 BMessage *m = Window()->CurrentMessage();
|
|
1198 assert(m);
|
|
1199 //m->PrintToStream();
|
|
1200
|
|
1201 int32 modifiers = 0;
|
|
1202 m->FindInt32("modifiers", &modifiers);
|
|
1203
|
|
1204 vimMouseModifiers = mouseModifiersToVim(modifiers);
|
|
1205
|
|
1206 guiSendMouseEvent(MOUSE_RELEASE, point.x, point.y,
|
|
1207 0 /* = repeated_click*/, vimMouseModifiers);
|
|
1208
|
|
1209 Inherited::MouseUp(point);
|
|
1210 }
|
|
1211
|
|
1212 void
|
|
1213 VimTextAreaView::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
|
|
1214 {
|
|
1215 /*
|
|
1216 * if our pointer is currently hidden, then we should show it.
|
|
1217 */
|
|
1218 if (gui.pointer_hidden)
|
|
1219 {
|
|
1220 guiBlankMouse(false);
|
|
1221 gui.pointer_hidden = FALSE;
|
|
1222 }
|
|
1223
|
|
1224 if (!vimMouseButton) /* could also check m->"buttons" */
|
|
1225 return;
|
|
1226
|
|
1227 atomic_add(&mouseDragEventCount, 1);
|
|
1228
|
|
1229 /* Don't care much about "transit" */
|
|
1230 guiSendMouseEvent(MOUSE_DRAG, point.x, point.y, 0, vimMouseModifiers);
|
|
1231 }
|
|
1232
|
|
1233 void
|
|
1234 VimTextAreaView::MessageReceived(BMessage *m)
|
|
1235 {
|
|
1236 switch (m->what) {
|
|
1237 case 'menu':
|
|
1238 {
|
|
1239 VimMenuMsg mm;
|
|
1240 mm.guiMenu = NULL; /* in case no pointer in msg */
|
|
1241 m->FindPointer("VimMenu", (void **)&mm.guiMenu);
|
|
1242
|
|
1243 write_port(gui.vdcmp, VimMsg::Menu, &mm, sizeof(mm));
|
|
1244 }
|
|
1245 break;
|
|
1246 default:
|
|
1247 if (m->WasDropped()) {
|
|
1248 BWindow *w = Window();
|
|
1249 w->DetachCurrentMessage();
|
|
1250 w->Minimize(false);
|
|
1251 VimApp::SendRefs(m, (modifiers() & B_SHIFT_KEY) != 0);
|
|
1252 } else {
|
|
1253 Inherited::MessageReceived(m);
|
|
1254 }
|
|
1255 break;
|
|
1256 }
|
|
1257 }
|
|
1258
|
|
1259 int
|
|
1260 VimTextAreaView::mchInitFont(char_u *name)
|
|
1261 {
|
|
1262 VimFont *newFont = (VimFont *)gui_mch_get_font(name, 0);
|
|
1263
|
|
1264 gui.norm_font = (GuiFont)newFont;
|
|
1265 gui_mch_set_font((GuiFont)newFont);
|
|
1266 if (name)
|
|
1267 hl_set_font_name(name);
|
|
1268
|
|
1269 SetDrawingMode(B_OP_COPY);
|
|
1270
|
|
1271 /*
|
|
1272 * Try to load other fonts for bold, italic, and bold-italic.
|
|
1273 * We should also try to work out what font to use for these when they are
|
|
1274 * not specified by X resources, but we don't yet.
|
|
1275 */
|
|
1276
|
|
1277 return OK;
|
|
1278 }
|
|
1279
|
|
1280 void
|
|
1281 VimTextAreaView::mchDrawString(int row, int col, char_u *s, int len, int flags)
|
|
1282 {
|
|
1283 /*
|
|
1284 * First we must erase the area, because DrawString won't do
|
|
1285 * that for us. XXX Most of the time this is a waste of effort
|
|
1286 * since the bachground has been erased already... DRAW_TRANSP
|
|
1287 * should be set when appropriate!!!
|
|
1288 * (Rectangles include the bottom and right edge)
|
|
1289 */
|
|
1290 if (!(flags & DRAW_TRANSP)) {
|
|
1291 BRect r(FILL_X(col), FILL_Y(row),
|
|
1292 FILL_X(col + len) - PEN_WIDTH, FILL_Y(row + 1) - PEN_WIDTH);
|
|
1293 FillRect(r, B_SOLID_LOW);
|
|
1294 }
|
|
1295 BPoint where(TEXT_X(col), TEXT_Y(row));
|
|
1296 DrawString((char *)s, len, where);
|
|
1297
|
|
1298 if (flags & DRAW_BOLD) {
|
|
1299 where.x += 1.0;
|
|
1300 SetDrawingMode(B_OP_BLEND);
|
|
1301 DrawString((char *)s, len, where);
|
|
1302 SetDrawingMode(B_OP_COPY);
|
|
1303 }
|
|
1304 if (flags & DRAW_UNDERL) {
|
|
1305 BPoint start(FILL_X(col), FILL_Y(row + 1) - PEN_WIDTH);
|
|
1306 BPoint end(FILL_X(col + len) - PEN_WIDTH, start.y);
|
|
1307
|
|
1308 StrokeLine(start, end);
|
|
1309 }
|
|
1310 }
|
|
1311
|
|
1312 void
|
|
1313 VimTextAreaView::mchClearBlock(
|
|
1314 int row1,
|
|
1315 int col1,
|
|
1316 int row2,
|
|
1317 int col2)
|
|
1318 {
|
|
1319 BRect r(FILL_X(col1), FILL_Y(row1),
|
|
1320 FILL_X(col2 + 1) - PEN_WIDTH, FILL_Y(row2 + 1) - PEN_WIDTH);
|
|
1321 gui_mch_set_bg_color(gui.back_pixel);
|
|
1322 FillRect(r, B_SOLID_LOW);
|
|
1323 }
|
|
1324
|
|
1325 void
|
|
1326 VimTextAreaView::mchClearAll()
|
|
1327 {
|
|
1328 gui_mch_set_bg_color(gui.back_pixel);
|
|
1329 FillRect(Bounds(), B_SOLID_LOW);
|
|
1330 }
|
|
1331
|
|
1332 /*
|
|
1333 * mchDeleteLines() Lock()s the window by itself.
|
|
1334 */
|
|
1335 void
|
|
1336 VimTextAreaView::mchDeleteLines(int row, int num_lines)
|
|
1337 {
|
|
1338 if (row + num_lines > gui.scroll_region_bot)
|
|
1339 {
|
|
1340 /* Scrolled out of region, just blank the lines out */
|
|
1341 gui_clear_block(row, gui.scroll_region_left,
|
|
1342 gui.scroll_region_bot, gui.scroll_region_right);
|
|
1343 }
|
|
1344 else
|
|
1345 {
|
|
1346 /* copy one extra pixel, for when bold has spilled over */
|
|
1347 int width = gui.char_width * (gui.scroll_region_right
|
|
1348 - gui.scroll_region_left + 1) + 1 - PEN_WIDTH;
|
|
1349 int height = gui.char_height *
|
|
1350 (gui.scroll_region_bot - row - num_lines + 1) - PEN_WIDTH;
|
|
1351
|
|
1352 BRect source, dest;
|
|
1353
|
|
1354 source.left = FILL_X(gui.scroll_region_left);
|
|
1355 source.top = FILL_Y(row + num_lines);
|
|
1356 source.right = source.left + width;
|
|
1357 source.bottom = source.top + height;
|
|
1358
|
|
1359 dest.left = FILL_X(gui.scroll_region_left);
|
|
1360 dest.top = FILL_Y(row);
|
|
1361 dest.right = dest.left + width;
|
|
1362 dest.bottom = dest.top + height;
|
|
1363
|
|
1364 /* XXX Attempt at a hack: */
|
|
1365 gui.vimWindow->UpdateIfNeeded();
|
|
1366 #if 0
|
|
1367 /* XXX Attempt at a hack: */
|
|
1368 if (gui.vimWindow->NeedsUpdate()) {
|
|
1369 fprintf(stderr, "mchDeleteLines: NeedsUpdate!\n");
|
|
1370 gui.vimWindow->UpdateIfNeeded();
|
|
1371 while (gui.vimWindow->NeedsUpdate()) {
|
|
1372 if (false && gui.vimWindow->Lock()) {
|
|
1373 Sync();
|
|
1374 gui.vimWindow->Unlock();
|
|
1375 }
|
|
1376 snooze(2);
|
|
1377 }
|
|
1378 }
|
|
1379 #endif
|
|
1380
|
|
1381 if (gui.vimWindow->Lock()) {
|
|
1382 Sync();
|
|
1383 CopyBits(source, dest);
|
|
1384 //Sync();
|
|
1385
|
|
1386 /* Update gui.cursor_row if the cursor scrolled or copied over */
|
|
1387 if (gui.cursor_row >= row
|
|
1388 && gui.cursor_col >= gui.scroll_region_left
|
|
1389 && gui.cursor_col <= gui.scroll_region_right)
|
|
1390 {
|
|
1391 if (gui.cursor_row < row + num_lines)
|
|
1392 gui.cursor_is_valid = FALSE;
|
|
1393 else if (gui.cursor_row <= gui.scroll_region_bot)
|
|
1394 gui.cursor_row -= num_lines;
|
|
1395 }
|
|
1396
|
|
1397 /* Clear one column more for when bold has spilled over */
|
|
1398 gui_clear_block(gui.scroll_region_bot - num_lines + 1,
|
|
1399 gui.scroll_region_left,
|
|
1400 gui.scroll_region_bot, gui.scroll_region_right);
|
|
1401
|
|
1402 gui.vimWindow->Unlock();
|
|
1403 /*
|
|
1404 * The Draw() callback will be called now if some of the source
|
|
1405 * bits were not in the visible region.
|
|
1406 */
|
|
1407
|
|
1408 //gui_x11_check_copy_area();
|
|
1409 }
|
|
1410 }
|
|
1411 }
|
|
1412
|
|
1413 /*
|
|
1414 * mchInsertLines() Lock()s the window by itself.
|
|
1415 */
|
|
1416 void
|
|
1417 VimTextAreaView::mchInsertLines(int row, int num_lines)
|
|
1418 {
|
|
1419 if (row + num_lines > gui.scroll_region_bot)
|
|
1420 {
|
|
1421 /* Scrolled out of region, just blank the lines out */
|
|
1422 gui_clear_block(row, gui.scroll_region_left,
|
|
1423 gui.scroll_region_bot, gui.scroll_region_right);
|
|
1424 }
|
|
1425 else
|
|
1426 {
|
|
1427 /* copy one extra pixel, for when bold has spilled over */
|
|
1428 int width = gui.char_width * (gui.scroll_region_right
|
|
1429 - gui.scroll_region_left + 1) + 1 - PEN_WIDTH;
|
|
1430 int height = gui.char_height *
|
|
1431 (gui.scroll_region_bot - row - num_lines + 1) - PEN_WIDTH;
|
|
1432
|
|
1433 BRect source, dest;
|
|
1434
|
|
1435 source.left = FILL_X(gui.scroll_region_left);
|
|
1436 source.top = FILL_Y(row);
|
|
1437 source.right = source.left + width;
|
|
1438 source.bottom = source.top + height;
|
|
1439
|
|
1440 dest.left = FILL_X(gui.scroll_region_left);
|
|
1441 dest.top = FILL_Y(row + num_lines);
|
|
1442 dest.right = dest.left + width;
|
|
1443 dest.bottom = dest.top + height;
|
|
1444
|
|
1445 /* XXX Attempt at a hack: */
|
|
1446 gui.vimWindow->UpdateIfNeeded();
|
|
1447 #if 0
|
|
1448 /* XXX Attempt at a hack: */
|
|
1449 if (gui.vimWindow->NeedsUpdate())
|
|
1450 fprintf(stderr, "mchInsertLines: NeedsUpdate!\n");
|
|
1451 gui.vimWindow->UpdateIfNeeded();
|
|
1452 while (gui.vimWindow->NeedsUpdate())
|
|
1453 snooze(2);
|
|
1454 #endif
|
|
1455
|
|
1456 if (gui.vimWindow->Lock()) {
|
|
1457 Sync();
|
|
1458 CopyBits(source, dest);
|
|
1459 //Sync();
|
|
1460
|
|
1461 /* Update gui.cursor_row if the cursor scrolled or copied over */
|
|
1462 if (gui.cursor_row >= gui.row
|
|
1463 && gui.cursor_col >= gui.scroll_region_left
|
|
1464 && gui.cursor_col <= gui.scroll_region_right)
|
|
1465 {
|
|
1466 if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
|
|
1467 gui.cursor_row += num_lines;
|
|
1468 else if (gui.cursor_row <= gui.scroll_region_bot)
|
|
1469 gui.cursor_is_valid = FALSE;
|
|
1470 }
|
|
1471 /* Clear one column more for when bold has spilled over */
|
|
1472 gui_clear_block(row, gui.scroll_region_left,
|
|
1473 row + num_lines - 1, gui.scroll_region_right);
|
|
1474
|
|
1475 gui.vimWindow->Unlock();
|
|
1476 /*
|
|
1477 * The Draw() callback will be called now if some of the source
|
|
1478 * bits were not in the visible region.
|
|
1479 * However, if we scroll too fast it can't keep up and the
|
|
1480 * update region gets messed up. This seems to be because copying
|
|
1481 * un-Draw()n bits does not generate Draw() calls for the copy...
|
|
1482 * I moved the hack to before the CopyBits() to reduce the
|
|
1483 * amount of additional waiting needed.
|
|
1484 */
|
|
1485
|
|
1486 //gui_x11_check_copy_area();
|
|
1487 }
|
|
1488 }
|
|
1489
|
|
1490 }
|
|
1491
|
|
1492 /* ---------------- VimScrollBar ---------------- */
|
|
1493
|
|
1494 /* BUG: XXX
|
|
1495 * It seems that BScrollBar determine their direction not from
|
|
1496 * "posture" but from if they are "tall" or "wide" in shape...
|
|
1497 *
|
|
1498 * Also, place them out of sight, because Vim enables them before
|
|
1499 * they are positioned.
|
|
1500 */
|
|
1501 VimScrollBar::VimScrollBar(scrollbar_T *g, orientation posture):
|
|
1502 BScrollBar(posture == B_HORIZONTAL ? BRect(-100,-100,-10,-90) :
|
|
1503 BRect(-100,-100,-90,-10),
|
|
1504 "vim scrollbar", (BView *)NULL,
|
|
1505 0.0, 10.0, posture),
|
|
1506 ignoreValue(-1),
|
|
1507 scrollEventCount(0)
|
|
1508 {
|
|
1509 gsb = g;
|
|
1510 SetResizingMode(B_FOLLOW_NONE);
|
|
1511 }
|
|
1512
|
|
1513 VimScrollBar::~VimScrollBar()
|
|
1514 {
|
|
1515 }
|
|
1516
|
|
1517 void
|
|
1518 VimScrollBar::ValueChanged(float newValue)
|
|
1519 {
|
|
1520 if (ignoreValue >= 0.0 && newValue == ignoreValue) {
|
|
1521 ignoreValue = -1;
|
|
1522 return;
|
|
1523 }
|
|
1524 ignoreValue = -1;
|
|
1525 /*
|
|
1526 * We want to throttle the amount of scroll messages generated.
|
|
1527 * Normally I presume you won't get a new message before we've
|
|
1528 * handled the previous one, but because we're passing them on this
|
|
1529 * happens very quickly. So instead we keep a counter of how many
|
|
1530 * scroll events there are (or will be) in the VDCMP, and the
|
|
1531 * throttling happens at the receiving end.
|
|
1532 */
|
|
1533 atomic_add(&scrollEventCount, 1);
|
|
1534
|
|
1535 struct VimScrollBarMsg sm;
|
|
1536
|
|
1537 sm.sb = this;
|
|
1538 sm.value = (long) newValue;
|
|
1539 sm.stillDragging = TRUE;
|
|
1540
|
|
1541 write_port(gui.vdcmp, VimMsg::ScrollBar, &sm, sizeof(sm));
|
|
1542
|
|
1543 // calls gui_drag_scrollbar(sb, newValue, TRUE);
|
|
1544 }
|
|
1545
|
|
1546 /*
|
|
1547 * When the mouse goes up, report that scrolling has stopped.
|
|
1548 * MouseUp() is NOT called when the mouse-up occurs outside
|
|
1549 * the window, even though the thumb does move while the mouse
|
|
1550 * is outside... This has some funny effects... XXX
|
|
1551 * So we do special processing when the window de/activates.
|
|
1552 */
|
|
1553 void
|
|
1554 VimScrollBar::MouseUp(BPoint where)
|
|
1555 {
|
|
1556 //BMessage *m = Window()->CurrentMessage();
|
|
1557 //m->PrintToStream();
|
|
1558
|
|
1559 atomic_add(&scrollEventCount, 1);
|
|
1560
|
|
1561 struct VimScrollBarMsg sm;
|
|
1562
|
|
1563 sm.sb = this;
|
|
1564 sm.value = (long) Value();
|
|
1565 sm.stillDragging = FALSE;
|
|
1566
|
|
1567 write_port(gui.vdcmp, VimMsg::ScrollBar, &sm, sizeof(sm));
|
|
1568
|
|
1569 // calls gui_drag_scrollbar(sb, newValue, FALSE);
|
|
1570
|
|
1571 Inherited::MouseUp(where);
|
|
1572 }
|
|
1573
|
|
1574 void
|
|
1575 VimScrollBar::SetValue(float newValue)
|
|
1576 {
|
|
1577 if (newValue == Value())
|
|
1578 return;
|
|
1579
|
|
1580 ignoreValue = newValue;
|
|
1581 Inherited::SetValue(newValue);
|
|
1582 }
|
|
1583
|
|
1584 /* ---------------- VimFont ---------------- */
|
|
1585
|
|
1586 VimFont::VimFont(): BFont()
|
|
1587 {
|
|
1588 init();
|
|
1589 }
|
|
1590
|
|
1591 VimFont::VimFont(const VimFont *rhs): BFont(rhs)
|
|
1592 {
|
|
1593 init();
|
|
1594 }
|
|
1595
|
|
1596 VimFont::VimFont(const BFont *rhs): BFont(rhs)
|
|
1597 {
|
|
1598 init();
|
|
1599 }
|
|
1600
|
|
1601 VimFont::VimFont(const VimFont &rhs): BFont(rhs)
|
|
1602 {
|
|
1603 init();
|
|
1604 }
|
|
1605
|
|
1606 VimFont::~VimFont()
|
|
1607 {
|
|
1608 }
|
|
1609
|
|
1610 void
|
|
1611 VimFont::init()
|
|
1612 {
|
|
1613 next = NULL;
|
|
1614 refcount = 1;
|
|
1615 name = NULL;
|
|
1616 }
|
|
1617
|
|
1618 /* ---------------- ---------------- */
|
|
1619
|
|
1620 // some global variables
|
|
1621 static char appsig[] = "application/x-vnd.Rhialto-Vim-5";
|
|
1622 key_map *keyMap;
|
|
1623 char *keyMapChars;
|
|
1624 int main_exitcode = 127;
|
|
1625
|
|
1626 status_t
|
|
1627 gui_beos_process_event(bigtime_t timeout)
|
|
1628 {
|
|
1629 struct VimMsg vm;
|
|
1630 long what;
|
|
1631 ssize_t size;
|
|
1632
|
|
1633 size = read_port_etc(gui.vdcmp, &what, &vm, sizeof(vm),
|
|
1634 B_TIMEOUT, timeout);
|
|
1635
|
|
1636 if (size >= 0) {
|
|
1637 switch (what) {
|
|
1638 case VimMsg::Key:
|
|
1639 {
|
|
1640 char_u *string = vm.u.Key.chars;
|
|
1641 int len = vm.u.Key.length;
|
|
1642 if (len == 1 && string[0] == Ctrl_chr('C')) {
|
|
1643 trash_input_buf();
|
|
1644 got_int = TRUE;
|
|
1645 }
|
|
1646 add_to_input_buf(string, len);
|
|
1647 }
|
|
1648 break;
|
|
1649 case VimMsg::Resize:
|
|
1650 gui_resize_shell(vm.u.NewSize.width, vm.u.NewSize.height);
|
|
1651 break;
|
|
1652 case VimMsg::ScrollBar:
|
|
1653 {
|
|
1654 /*
|
|
1655 * If loads of scroll messages queue up, use only the last
|
|
1656 * one. Always report when the scrollbar stops dragging.
|
|
1657 * This is not perfect yet anyway: these events are queued
|
|
1658 * yet again, this time in the keyboard input buffer.
|
|
1659 */
|
|
1660 int32 oldCount =
|
|
1661 atomic_add(&vm.u.Scroll.sb->scrollEventCount, -1);
|
|
1662 if (oldCount <= 1 || !vm.u.Scroll.stillDragging)
|
|
1663 gui_drag_scrollbar(vm.u.Scroll.sb->getGsb(),
|
|
1664 vm.u.Scroll.value, vm.u.Scroll.stillDragging);
|
|
1665 }
|
|
1666 break;
|
|
1667 case VimMsg::Menu:
|
|
1668 gui_menu_cb(vm.u.Menu.guiMenu);
|
|
1669 break;
|
|
1670 case VimMsg::Mouse:
|
|
1671 {
|
|
1672 int32 oldCount;
|
|
1673 if (vm.u.Mouse.button == MOUSE_DRAG)
|
|
1674 oldCount =
|
|
1675 atomic_add(&gui.vimTextArea->mouseDragEventCount, -1);
|
|
1676 else
|
|
1677 oldCount = 0;
|
|
1678 if (oldCount <= 1)
|
|
1679 gui_send_mouse_event(vm.u.Mouse.button, vm.u.Mouse.x,
|
|
1680 vm.u.Mouse.y, vm.u.Mouse.repeated_click,
|
|
1681 vm.u.Mouse.modifiers);
|
|
1682 }
|
|
1683 break;
|
|
1684 case VimMsg::Focus:
|
|
1685 gui.in_focus = vm.u.Focus.active;
|
|
1686 /* XXX Signal that scrollbar dragging has stopped?
|
|
1687 * This is needed because we don't get a MouseUp if
|
|
1688 * that happens while outside the window... :-(
|
|
1689 */
|
|
1690 if (gui.dragged_sb) {
|
|
1691 gui.dragged_sb = SBAR_NONE;
|
|
1692 }
|
|
1693 gui_update_cursor(TRUE, FALSE);
|
|
1694 break;
|
|
1695 case VimMsg::Refs:
|
|
1696 ::RefsReceived(vm.u.Refs.message, vm.u.Refs.changedir);
|
|
1697 break;
|
|
1698 default:
|
|
1699 // unrecognised message, ignore it
|
|
1700 break;
|
|
1701 }
|
|
1702 }
|
|
1703
|
|
1704 /*
|
|
1705 * If size < B_OK, it is an error code.
|
|
1706 */
|
|
1707 return size;
|
|
1708 }
|
|
1709
|
|
1710 /*
|
|
1711 * Here are some functions to protect access to ScreenLines[] and
|
|
1712 * LineOffset[]. These are used from the window thread to respond
|
|
1713 * to a Draw() callback. When that occurs, the window is already
|
|
1714 * locked by the system.
|
|
1715 *
|
|
1716 * Other code that needs to lock is any code that changes these
|
|
1717 * variables. Other read-only access, or access merely to the
|
|
1718 * contents of the screen buffer, need not be locked.
|
|
1719 *
|
|
1720 * If there is no window, don't call Lock() but do succeed.
|
|
1721 */
|
|
1722
|
|
1723 int
|
|
1724 vim_lock_screen()
|
|
1725 {
|
|
1726 return !gui.vimWindow || gui.vimWindow->Lock();
|
|
1727 }
|
|
1728
|
|
1729 void
|
|
1730 vim_unlock_screen()
|
|
1731 {
|
|
1732 if (gui.vimWindow)
|
|
1733 gui.vimWindow->Unlock();
|
|
1734 }
|
|
1735
|
|
1736 #define RUN_BAPPLICATION_IN_NEW_THREAD 0
|
|
1737
|
|
1738 #if RUN_BAPPLICATION_IN_NEW_THREAD
|
|
1739
|
|
1740 int32
|
|
1741 run_vimapp(void *args)
|
|
1742 {
|
|
1743 VimApp app(appsig);
|
|
1744
|
|
1745 gui.vimApp = &app;
|
|
1746 app.Run(); /* Run until Quit() called */
|
|
1747
|
|
1748 return 0;
|
|
1749 }
|
|
1750
|
|
1751 #else
|
|
1752
|
|
1753 int32
|
|
1754 call_main(void *args)
|
|
1755 {
|
|
1756 struct MainArgs *ma = (MainArgs *)args;
|
|
1757
|
|
1758 return main(ma->argc, ma->argv);
|
|
1759 }
|
|
1760 #endif
|
|
1761
|
|
1762 extern "C" {
|
|
1763
|
|
1764 /*
|
|
1765 * Parse the GUI related command-line arguments. Any arguments used are
|
|
1766 * deleted from argv, and *argc is decremented accordingly. This is called
|
|
1767 * when vim is started, whether or not the GUI has been started.
|
|
1768 */
|
|
1769 void
|
|
1770 gui_mch_prepare(
|
|
1771 int *argc,
|
|
1772 char **argv)
|
|
1773 {
|
|
1774 /*
|
|
1775 * We don't have any command line arguments for the BeOS GUI yet,
|
|
1776 * but this is an excellent place to create our Application object.
|
|
1777 */
|
|
1778 if (!gui.vimApp) {
|
|
1779 thread_info tinfo;
|
|
1780 get_thread_info(find_thread(NULL), &tinfo);
|
|
1781
|
|
1782 /* May need the port very early on to process RefsReceived() */
|
|
1783 gui.vdcmp = create_port(B_MAX_PORT_COUNT, "vim VDCMP");
|
|
1784
|
|
1785 #if RUN_BAPPLICATION_IN_NEW_THREAD
|
|
1786 thread_id tid = spawn_thread(run_vimapp, "vim VimApp",
|
|
1787 tinfo.priority, NULL);
|
|
1788 if (tid >= B_OK) {
|
|
1789 resume_thread(tid);
|
|
1790 } else {
|
|
1791 getout(1);
|
|
1792 }
|
|
1793 #else
|
|
1794 MainArgs ma = { *argc, argv };
|
|
1795 thread_id tid = spawn_thread(call_main, "vim main()",
|
|
1796 tinfo.priority, &ma);
|
|
1797 if (tid >= B_OK) {
|
|
1798 VimApp app(appsig);
|
|
1799
|
|
1800 gui.vimApp = &app;
|
|
1801 resume_thread(tid);
|
|
1802 /*
|
|
1803 * This is rather horrible.
|
|
1804 * call_main will call main() again...
|
|
1805 * There will be no infinite recursion since
|
|
1806 * gui.vimApp is set now.
|
|
1807 */
|
|
1808 app.Run(); /* Run until Quit() called */
|
|
1809 //fprintf(stderr, "app.Run() returned...\n");
|
|
1810 status_t dummy_exitcode;
|
|
1811 (void)wait_for_thread(tid, &dummy_exitcode);
|
|
1812
|
|
1813 /*
|
|
1814 * This path should be the normal one taken to exit Vim.
|
|
1815 * The main() thread calls mch_exit() which calls
|
|
1816 * gui_mch_exit() which terminates its thread.
|
|
1817 */
|
|
1818 exit(main_exitcode);
|
|
1819 }
|
|
1820 #endif
|
|
1821 }
|
|
1822 /* Don't fork() when starting the GUI. Spawned threads are not
|
|
1823 * duplicated with a fork(). The result is a mess.
|
|
1824 */
|
|
1825 gui.dofork = FALSE;
|
|
1826 /*
|
|
1827 * XXX Try to determine whether we were started from
|
|
1828 * the Tracker or the terminal.
|
|
1829 * It would be nice to have this work, because the Tracker
|
|
1830 * follows symlinks, so even if you double-click on gvim,
|
|
1831 * when it is a link to vim it will still pass a command name
|
|
1832 * of vim...
|
|
1833 * We try here to see if stdin comes from /dev/null. If so,
|
|
1834 * (or if there is an error, which should never happen) start the GUI.
|
|
1835 * This does the wrong thing for vim - </dev/null, and we're
|
|
1836 * too early to see the command line parsing. Tough.
|
|
1837 * On the other hand, it starts the gui for vim file & which is nice.
|
|
1838 */
|
|
1839 if (!isatty(0)) {
|
|
1840 struct stat stat_stdin, stat_dev_null;
|
|
1841
|
|
1842 if (fstat(0, &stat_stdin) == -1 ||
|
|
1843 stat("/dev/null", &stat_dev_null) == -1 ||
|
|
1844 (stat_stdin.st_dev == stat_dev_null.st_dev &&
|
|
1845 stat_stdin.st_ino == stat_dev_null.st_ino))
|
|
1846 gui.starting = TRUE;
|
|
1847 }
|
|
1848 }
|
|
1849
|
|
1850 /*
|
|
1851 * Check if the GUI can be started. Called before gvimrc is sourced.
|
|
1852 * Return OK or FAIL.
|
|
1853 */
|
|
1854 int
|
|
1855 gui_mch_init_check(void)
|
|
1856 {
|
|
1857 return OK; /* TODO: GUI can always be started? */
|
|
1858 }
|
|
1859
|
|
1860 /*
|
|
1861 * Initialise the GUI. Create all the windows, set up all the call-backs
|
|
1862 * etc.
|
|
1863 */
|
|
1864 int
|
|
1865 gui_mch_init()
|
|
1866 {
|
|
1867 gui.def_norm_pixel = RGB(0x00, 0x00, 0x00); // black
|
|
1868 gui.def_back_pixel = RGB(0xFF, 0xFF, 0xFF); // white
|
|
1869 gui.norm_pixel = gui.def_norm_pixel;
|
|
1870 gui.back_pixel = gui.def_back_pixel;
|
|
1871
|
|
1872 gui.scrollbar_width = (int) B_V_SCROLL_BAR_WIDTH;
|
|
1873 gui.scrollbar_height = (int) B_H_SCROLL_BAR_HEIGHT;
|
|
1874 #ifdef FEAT_MENU
|
|
1875 gui.menu_height = 19; // initial guess -
|
|
1876 // correct for my default settings
|
|
1877 #endif
|
|
1878 gui.border_offset = 3; // coordinates are inside window borders
|
|
1879
|
|
1880 if (gui.vdcmp < B_OK)
|
|
1881 return FAIL;
|
|
1882 get_key_map(&keyMap, &keyMapChars);
|
|
1883
|
|
1884 gui.vimWindow = new VimWindow(); /* hidden and locked */
|
|
1885 if (!gui.vimWindow)
|
|
1886 return FAIL;
|
|
1887
|
|
1888 gui.vimWindow->Run(); /* Run() unlocks but does not show */
|
|
1889
|
|
1890 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
|
|
1891 * file) */
|
|
1892 set_normal_colors();
|
|
1893
|
|
1894 /*
|
|
1895 * Check that none of the colors are the same as the background color
|
|
1896 */
|
|
1897 gui_check_colors();
|
|
1898
|
|
1899 /* Get the colors for the highlight groups (gui_check_colors() might have
|
|
1900 * changed them) */
|
|
1901 highlight_gui_started(); /* re-init colors and fonts */
|
|
1902
|
|
1903 gui_mch_new_colors(); /* window must exist for this */
|
|
1904
|
|
1905 return OK;
|
|
1906 }
|
|
1907
|
|
1908 /*
|
|
1909 * Called when the foreground or background color has been changed.
|
|
1910 */
|
|
1911 void
|
|
1912 gui_mch_new_colors()
|
|
1913 {
|
|
1914 rgb_color rgb = GUI_TO_RGB(gui.back_pixel);
|
|
1915
|
|
1916 if (gui.vimWindow->Lock()) {
|
|
1917 gui.vimForm->SetViewColor(rgb);
|
|
1918 // Does this not have too much effect for those small rectangles?
|
|
1919 gui.vimForm->Invalidate();
|
|
1920 gui.vimWindow->Unlock();
|
|
1921 }
|
|
1922 }
|
|
1923
|
|
1924 /*
|
|
1925 * Open the GUI window which was created by a call to gui_mch_init().
|
|
1926 */
|
|
1927 int
|
|
1928 gui_mch_open()
|
|
1929 {
|
|
1930 if (gui_win_x != -1 && gui_win_y != -1)
|
|
1931 gui_mch_set_winpos(gui_win_x, gui_win_y);
|
|
1932
|
|
1933 /* Actually open the window */
|
|
1934 if (gui.vimWindow->Lock()) {
|
|
1935 gui.vimWindow->Show();
|
|
1936 gui.vimWindow->Unlock();
|
|
1937
|
|
1938 #if USE_THREAD_FOR_INPUT_WITH_TIMEOUT
|
|
1939 /* Kill the thread that may have been created for the Terminal */
|
|
1940 beos_cleanup_read_thread();
|
|
1941 #endif
|
|
1942
|
|
1943 return OK;
|
|
1944 }
|
|
1945
|
|
1946 return FAIL;
|
|
1947 }
|
|
1948
|
|
1949 void
|
|
1950 gui_mch_exit(int vim_exitcode)
|
|
1951 {
|
|
1952 if (gui.vimWindow) {
|
|
1953 thread_id tid = gui.vimWindow->Thread();
|
|
1954 gui.vimWindow->Lock();
|
|
1955 gui.vimWindow->Quit();
|
|
1956 /* Wait until it is truely gone */
|
|
1957 int32 exitcode;
|
|
1958 wait_for_thread(tid, &exitcode);
|
|
1959 }
|
|
1960 delete_port(gui.vdcmp);
|
|
1961 #if !RUN_BAPPLICATION_IN_NEW_THREAD
|
|
1962 /*
|
|
1963 * We are in the main() thread - quit the App thread and
|
|
1964 * quit ourselves (passing on the exitcode). Use a global since the
|
|
1965 * value from exit_thread() is only used if wait_for_thread() is
|
|
1966 * called in time (race condition).
|
|
1967 */
|
|
1968 #endif
|
|
1969 if (gui.vimApp) {
|
|
1970 VimTextAreaView::guiBlankMouse(false);
|
|
1971
|
|
1972 main_exitcode = vim_exitcode;
|
|
1973 #if RUN_BAPPLICATION_IN_NEW_THREAD
|
|
1974 thread_id tid = gui.vimApp->Thread();
|
|
1975 int32 exitcode;
|
|
1976 gui.vimApp->Lock();
|
|
1977 gui.vimApp->Quit();
|
|
1978 gui.vimApp->Unlock();
|
|
1979 wait_for_thread(tid, &exitcode);
|
|
1980 #else
|
|
1981 gui.vimApp->Lock();
|
|
1982 gui.vimApp->Quit();
|
|
1983 gui.vimApp->Unlock();
|
|
1984 /* suicide */
|
|
1985 exit_thread(vim_exitcode);
|
|
1986 #endif
|
|
1987 }
|
|
1988 /* If we are somehow still here, let mch_exit() handle things. */
|
|
1989 }
|
|
1990
|
|
1991 /*
|
|
1992 * Get the position of the top left corner of the window.
|
|
1993 */
|
|
1994 int
|
|
1995 gui_mch_get_winpos(int *x, int *y)
|
|
1996 {
|
|
1997 /* TODO */
|
|
1998 return FAIL;
|
|
1999 }
|
|
2000
|
|
2001 /*
|
|
2002 * Set the position of the top left corner of the window to the given
|
|
2003 * coordinates.
|
|
2004 */
|
|
2005 void
|
|
2006 gui_mch_set_winpos(int x, int y)
|
|
2007 {
|
|
2008 /* TODO */
|
|
2009 }
|
|
2010
|
|
2011 /*
|
|
2012 * Set the size of the window to the given width and height in pixels.
|
|
2013 */
|
|
2014 void
|
|
2015 gui_mch_set_shellsize(
|
|
2016 int width,
|
|
2017 int height,
|
|
2018 int min_width,
|
|
2019 int min_height,
|
|
2020 int base_width,
|
|
2021 int base_height)
|
|
2022 {
|
|
2023 /*
|
|
2024 * We are basically given the size of the VimForm, if I understand
|
|
2025 * correctly. Since it fills the window completely, this will also
|
|
2026 * be the size of the window.
|
|
2027 */
|
|
2028 if (gui.vimWindow->Lock()) {
|
|
2029 gui.vimWindow->ResizeTo(width - PEN_WIDTH, height - PEN_WIDTH);
|
|
2030
|
|
2031 /* set size limits */
|
|
2032 float minWidth, maxWidth, minHeight, maxHeight;
|
|
2033
|
|
2034 gui.vimWindow->GetSizeLimits(&minWidth, &maxWidth,
|
|
2035 &minHeight, &maxHeight);
|
|
2036 gui.vimWindow->SetSizeLimits(min_width, maxWidth,
|
|
2037 min_height, maxHeight);
|
|
2038
|
|
2039 #if HAVE_R3_OR_LATER
|
|
2040 /*
|
|
2041 * Set the resizing alignment depending on font size.
|
|
2042 * XXX This is untested, since I don't have R3 yet.
|
|
2043 */
|
|
2044 SetWindowAlignment(
|
|
2045 B_PIXEL_ALIGNMENT, // window_alignment mode,
|
|
2046 1, // int32 h,
|
|
2047 0, // int32 hOffset = 0,
|
|
2048 gui.char_width, // int32 width = 0,
|
|
2049 base_width, // int32 widthOffset = 0,
|
|
2050 1, // int32 v = 0,
|
|
2051 0, // int32 vOffset = 0,
|
|
2052 gui.char_height, // int32 height = 0,
|
|
2053 base_height // int32 heightOffset = 0
|
|
2054 );
|
|
2055 #else
|
|
2056 /* don't know what to do with base_{width,height}. */
|
|
2057 #endif
|
|
2058
|
|
2059 gui.vimWindow->Unlock();
|
|
2060 }
|
|
2061 }
|
|
2062
|
|
2063 void
|
|
2064 gui_mch_get_screen_dimensions(
|
|
2065 int *screen_w,
|
|
2066 int *screen_h)
|
|
2067 {
|
|
2068 BRect frame;
|
|
2069
|
|
2070 {
|
|
2071 BScreen screen(gui.vimWindow);
|
|
2072
|
|
2073 if (screen.IsValid()) {
|
|
2074 frame = screen.Frame();
|
|
2075 } else {
|
|
2076 frame.right = 640;
|
|
2077 frame.bottom = 480;
|
|
2078 }
|
|
2079 }
|
|
2080
|
|
2081 /* XXX approximations... */
|
|
2082 *screen_w = (int) frame.right - 2 * gui.scrollbar_width - 20;
|
|
2083 *screen_h = (int) frame.bottom - gui.scrollbar_height
|
|
2084 #ifdef FEAT_MENU
|
|
2085 - gui.menu_height
|
|
2086 #endif
|
|
2087 - 30;
|
|
2088 }
|
|
2089
|
|
2090 void
|
|
2091 gui_mch_set_text_area_pos(
|
|
2092 int x,
|
|
2093 int y,
|
|
2094 int w,
|
|
2095 int h)
|
|
2096 {
|
|
2097 if (!gui.vimTextArea)
|
|
2098 return;
|
|
2099
|
|
2100 if (gui.vimWindow->Lock()) {
|
|
2101 gui.vimTextArea->MoveTo(x, y);
|
|
2102 gui.vimTextArea->ResizeTo(w - PEN_WIDTH, h - PEN_WIDTH);
|
|
2103 gui.vimWindow->Unlock();
|
|
2104 }
|
|
2105 }
|
|
2106
|
|
2107
|
|
2108 /*
|
|
2109 * Scrollbar stuff:
|
|
2110 */
|
|
2111
|
|
2112 void
|
|
2113 gui_mch_enable_scrollbar(
|
|
2114 scrollbar_T *sb,
|
|
2115 int flag)
|
|
2116 {
|
|
2117 VimScrollBar *vsb = sb->id;
|
|
2118 if (gui.vimWindow->Lock()) {
|
|
2119 /*
|
|
2120 * This function is supposed to be idempotent, but Show()/Hide()
|
|
2121 * is not. Therefore we test if they are needed.
|
|
2122 */
|
|
2123 if (flag) {
|
|
2124 if (vsb->IsHidden()) {
|
|
2125 vsb->Show();
|
|
2126 }
|
|
2127 } else {
|
|
2128 if (!vsb->IsHidden()) {
|
|
2129 vsb->Hide();
|
|
2130 }
|
|
2131 }
|
|
2132 gui.vimWindow->Unlock();
|
|
2133 }
|
|
2134 }
|
|
2135
|
|
2136 void
|
|
2137 gui_mch_set_scrollbar_thumb(
|
|
2138 scrollbar_T *sb,
|
|
2139 int val,
|
|
2140 int size,
|
|
2141 int max)
|
|
2142 {
|
|
2143 if (gui.vimWindow->Lock()) {
|
|
2144 VimScrollBar *s = sb->id;
|
|
2145 if (max == 0) {
|
|
2146 s->SetValue(0);
|
|
2147 s->SetRange(0.0, 0.0);
|
|
2148 } else {
|
|
2149 s->SetProportion((float)size / (max + 1.0));
|
|
2150 s->SetSteps(1.0, size > 5 ? size - 2 : size);
|
|
2151 #ifndef SCROLL_PAST_END // really only defined in gui.c...
|
|
2152 max = max + 1 - size;
|
|
2153 #endif
|
|
2154 if (max < s->Value()) {
|
|
2155 /*
|
|
2156 * If the new maximum is lower than the current value,
|
|
2157 * setting it would cause the value to be clipped and
|
|
2158 * therefore a ValueChanged() call.
|
|
2159 * We avoid this by setting the value first, because
|
|
2160 * it presumably is <= max.
|
|
2161 */
|
|
2162 s->SetValue(val);
|
|
2163 s->SetRange(0.0, max);
|
|
2164 } else {
|
|
2165 /*
|
|
2166 * In the other case, set the range first, since the
|
|
2167 * new value might be higher than the current max.
|
|
2168 */
|
|
2169 s->SetRange(0.0, max);
|
|
2170 s->SetValue(val);
|
|
2171 }
|
|
2172 }
|
|
2173 gui.vimWindow->Unlock();
|
|
2174 }
|
|
2175 }
|
|
2176
|
|
2177 void
|
|
2178 gui_mch_set_scrollbar_pos(
|
|
2179 scrollbar_T *sb,
|
|
2180 int x,
|
|
2181 int y,
|
|
2182 int w,
|
|
2183 int h)
|
|
2184 {
|
|
2185 if (gui.vimWindow->Lock()) {
|
|
2186 VimScrollBar *vsb = sb->id;
|
|
2187 vsb->MoveTo(x, y);
|
|
2188 vsb->ResizeTo(w - PEN_WIDTH, h - PEN_WIDTH);
|
|
2189 gui.vimWindow->Unlock();
|
|
2190 }
|
|
2191 }
|
|
2192
|
|
2193 void
|
|
2194 gui_mch_create_scrollbar(
|
|
2195 scrollbar_T *sb,
|
|
2196 int orient) /* SBAR_VERT or SBAR_HORIZ */
|
|
2197 {
|
|
2198 orientation posture =
|
|
2199 (orient == SBAR_HORIZ) ? B_HORIZONTAL : B_VERTICAL;
|
|
2200
|
|
2201 VimScrollBar *vsb = sb->id = new VimScrollBar(sb, posture);
|
|
2202 if (gui.vimWindow->Lock()) {
|
|
2203 vsb->SetTarget(gui.vimTextArea);
|
|
2204 vsb->Hide();
|
|
2205 gui.vimForm->AddChild(vsb);
|
|
2206 gui.vimWindow->Unlock();
|
|
2207 }
|
|
2208 }
|
|
2209
|
|
2210 #if defined(FEAT_WINDOWS) || defined(PROTO)
|
|
2211 void
|
|
2212 gui_mch_destroy_scrollbar(
|
|
2213 scrollbar_T *sb)
|
|
2214 {
|
|
2215 if (gui.vimWindow->Lock()) {
|
|
2216 sb->id->RemoveSelf();
|
|
2217 delete sb->id;
|
|
2218 gui.vimWindow->Unlock();
|
|
2219 }
|
|
2220 }
|
|
2221 #endif
|
|
2222
|
|
2223 /*
|
|
2224 * Cursor blink functions.
|
|
2225 *
|
|
2226 * This is a simple state machine:
|
|
2227 * BLINK_NONE not blinking at all
|
|
2228 * BLINK_OFF blinking, cursor is not shown
|
|
2229 * BLINK_ON blinking, cursor is shown
|
|
2230 */
|
|
2231
|
|
2232 #define BLINK_NONE 0
|
|
2233 #define BLINK_OFF 1
|
|
2234 #define BLINK_ON 2
|
|
2235
|
|
2236 static int blink_state = BLINK_NONE;
|
|
2237 static long_u blink_waittime = 700;
|
|
2238 static long_u blink_ontime = 400;
|
|
2239 static long_u blink_offtime = 250;
|
|
2240 static int blink_timer = 0;
|
|
2241
|
|
2242 void
|
|
2243 gui_mch_set_blinking(
|
|
2244 long waittime,
|
|
2245 long on,
|
|
2246 long off)
|
|
2247 {
|
|
2248 /* TODO */
|
|
2249 blink_waittime = waittime;
|
|
2250 blink_ontime = on;
|
|
2251 blink_offtime = off;
|
|
2252 }
|
|
2253
|
|
2254 /*
|
|
2255 * Stop the cursor blinking. Show the cursor if it wasn't shown.
|
|
2256 */
|
|
2257 void
|
|
2258 gui_mch_stop_blink()
|
|
2259 {
|
|
2260 /* TODO */
|
|
2261 if (blink_timer != 0)
|
|
2262 {
|
|
2263 //XtRemoveTimeOut(blink_timer);
|
|
2264 blink_timer = 0;
|
|
2265 }
|
|
2266 if (blink_state == BLINK_OFF)
|
|
2267 gui_update_cursor(TRUE, FALSE);
|
|
2268 blink_state = BLINK_NONE;
|
|
2269 }
|
|
2270
|
|
2271 /*
|
|
2272 * Start the cursor blinking. If it was already blinking, this restarts the
|
|
2273 * waiting time and shows the cursor.
|
|
2274 */
|
|
2275 void
|
|
2276 gui_mch_start_blink()
|
|
2277 {
|
|
2278 /* TODO */
|
|
2279 if (blink_timer != 0)
|
|
2280 ;//XtRemoveTimeOut(blink_timer);
|
|
2281 /* Only switch blinking on if none of the times is zero */
|
|
2282 if (blink_waittime && blink_ontime && blink_offtime && gui.in_focus)
|
|
2283 {
|
|
2284 blink_timer = 1; //XtAppAddTimeOut(app_context, blink_waittime,
|
|
2285 blink_state = BLINK_ON;
|
|
2286 gui_update_cursor(TRUE, FALSE);
|
|
2287 }
|
|
2288 }
|
|
2289
|
|
2290 /*
|
|
2291 * Initialise vim to use the font with the given name. Return FAIL if the font
|
|
2292 * could not be loaded, OK otherwise.
|
|
2293 */
|
|
2294 int
|
|
2295 gui_mch_init_font(
|
|
2296 char_u *font_name,
|
|
2297 int fontset)
|
|
2298 {
|
|
2299 if (gui.vimWindow->Lock())
|
|
2300 {
|
|
2301 int rc = gui.vimTextArea->mchInitFont(font_name);
|
|
2302 gui.vimWindow->Unlock();
|
|
2303
|
|
2304 return rc;
|
|
2305 }
|
|
2306
|
|
2307 return FAIL;
|
|
2308 }
|
|
2309
|
|
2310 int
|
|
2311 gui_mch_adjust_charsize()
|
|
2312 {
|
|
2313 return FAIL;
|
|
2314 }
|
|
2315
|
|
2316 GuiFont
|
|
2317 gui_mch_get_font(
|
|
2318 char_u *name,
|
|
2319 int giveErrorIfMissing)
|
|
2320 {
|
|
2321 VimFont *font = 0;
|
|
2322 static VimFont *fontList = NULL;
|
|
2323
|
|
2324 if (!gui.in_use) /* can't do this when GUI not running */
|
|
2325 return NOFONT;
|
|
2326
|
|
2327 if (!name)
|
|
2328 name = (char_u *)"be_fixed_font";
|
|
2329
|
|
2330 VimFont *flp;
|
|
2331 for (flp = fontList; flp; flp = flp->next) {
|
|
2332 if (STRCMP(name, flp->name) == 0) {
|
|
2333 flp->refcount++;
|
|
2334 return (GuiFont)flp;
|
|
2335 }
|
|
2336 }
|
|
2337
|
|
2338 font = new VimFont(be_fixed_font);
|
|
2339
|
|
2340 /* Set some universal features: */
|
|
2341 font->SetSpacing(B_FIXED_SPACING);
|
|
2342 font->SetEncoding(B_ISO_8859_1);
|
|
2343
|
|
2344 /* Remember font for later use */
|
|
2345 font->name = vim_strsave(name);
|
|
2346 font->next = fontList;
|
|
2347 fontList = font;
|
|
2348
|
|
2349 font_family family;
|
|
2350 font_style style;
|
|
2351 int size;
|
|
2352 int len;
|
|
2353 char_u *end;
|
|
2354
|
|
2355 #ifdef never
|
|
2356 // This leads to SEGV/BUS on R4+
|
|
2357 // Replace underscores with spaces, and I can't see why ?
|
|
2358 // richard@whitequeen.com jul 99
|
|
2359 while (end = (char_u *)strchr((char *)name, '_'))
|
|
2360 *end = ' ';
|
|
2361 #endif
|
|
2362 /*
|
|
2363 * Parse font names as Family/Style/Size.
|
|
2364 * On errors, just keep the be_fixed_font.
|
|
2365 */
|
|
2366 end = (char_u *)strchr((char *)name, '/');
|
|
2367 if (!end)
|
|
2368 goto error;
|
|
2369 strncpy(family, (char *)name, len = end - name);
|
|
2370 family[len] = '\0';
|
|
2371
|
|
2372 name = end + 1;
|
|
2373 end = (char_u *)strchr((char *)name, '/');
|
|
2374 if (!end)
|
|
2375 goto error;
|
|
2376 strncpy(style, (char *)name, len = end - name);
|
|
2377 style[len] = '\0';
|
|
2378
|
|
2379 name = end + 1;
|
|
2380 size = atoi((char *)name);
|
|
2381 if (size <= 0)
|
|
2382 goto error;
|
|
2383
|
|
2384 font->SetFamilyAndStyle(family, style);
|
|
2385 font->SetSize(size);
|
|
2386 font->SetSpacing(B_FIXED_SPACING);
|
|
2387 font->SetEncoding(B_ISO_8859_1);
|
|
2388 //font->PrintToStream();
|
|
2389
|
|
2390 return (GuiFont)font;
|
|
2391
|
|
2392 error:
|
|
2393 if (giveErrorIfMissing)
|
|
2394 EMSG2("(fe0) Unknown font: %s", name);
|
|
2395
|
|
2396 return (GuiFont)font;
|
|
2397 }
|
|
2398
|
44
|
2399 #if defined(FEAT_EVAL) || defined(PROTO)
|
7
|
2400 /*
|
37
|
2401 * Return the name of font "font" in allocated memory.
|
|
2402 */
|
|
2403 char_u *
|
|
2404 gui_mch_get_fontname(GuiFont font, char_u *name)
|
|
2405 {
|
|
2406 return vim_strsave(((VimFont *)font)->name);
|
|
2407 }
|
44
|
2408 #endif
|
37
|
2409
|
|
2410 /*
|
7
|
2411 * Set the current text font.
|
|
2412 */
|
|
2413 void
|
|
2414 gui_mch_set_font(
|
|
2415 GuiFont font)
|
|
2416 {
|
|
2417 if (gui.vimWindow->Lock()) {
|
|
2418 VimFont *vf = (VimFont *)font;
|
|
2419
|
|
2420 gui.vimTextArea->SetFont(vf);
|
|
2421
|
|
2422 gui.char_width = (int) vf->StringWidth("n");
|
|
2423 font_height fh;
|
|
2424 vf->GetHeight(&fh);
|
|
2425 gui.char_height = (int)(fh.ascent + 0.9999)
|
|
2426 + (int)(fh.descent + 0.9999) + (int)(fh.leading + 0.9999);
|
|
2427 gui.char_ascent = (int)(fh.ascent + 0.9999);
|
|
2428
|
|
2429 gui.vimWindow->Unlock();
|
|
2430 }
|
|
2431 }
|
|
2432
|
|
2433 #if 0 /* not used */
|
|
2434 /*
|
|
2435 * Return TRUE if the two fonts given are equivalent.
|
|
2436 */
|
|
2437 int
|
|
2438 gui_mch_same_font(
|
|
2439 GuiFont f1,
|
|
2440 GuiFont f2)
|
|
2441 {
|
|
2442 VimFont *vf1 = (VimFont *)f1;
|
|
2443 VimFont *vf2 = (VimFont *)f2;
|
|
2444
|
|
2445 return f1 == f2 ||
|
|
2446 (vf1->FamilyAndStyle() == vf2->FamilyAndStyle() &&
|
|
2447 vf1->Size() == vf2->Size());
|
|
2448 }
|
|
2449 #endif
|
|
2450
|
|
2451 /* XXX TODO This is apparently never called... */
|
|
2452 void
|
|
2453 gui_mch_free_font(
|
|
2454 GuiFont font)
|
|
2455 {
|
|
2456 VimFont *f = (VimFont *)font;
|
|
2457 if (--f->refcount <= 0) {
|
|
2458 if (f->refcount < 0)
|
|
2459 fprintf(stderr, "VimFont: refcount < 0\n");
|
|
2460 delete f;
|
|
2461 }
|
|
2462 }
|
|
2463
|
|
2464 static int
|
|
2465 hex_digit(int c)
|
|
2466 {
|
|
2467 if (isdigit(c))
|
|
2468 return c - '0';
|
|
2469 c = TOLOWER_ASC(c);
|
|
2470 if (c >= 'a' && c <= 'f')
|
|
2471 return c - 'a' + 10;
|
|
2472 return -1000;
|
|
2473 }
|
|
2474
|
|
2475 /*
|
|
2476 * This function has been lifted from gui_w32.c and extended a bit.
|
|
2477 *
|
|
2478 * Return the Pixel value (color) for the given color name.
|
|
2479 * Return INVALCOLOR for error.
|
|
2480 */
|
|
2481 guicolor_T
|
|
2482 gui_mch_get_color(
|
|
2483 char_u *name)
|
|
2484 {
|
|
2485 typedef struct GuiColourTable
|
|
2486 {
|
|
2487 char *name;
|
|
2488 guicolor_T colour;
|
|
2489 } GuiColourTable;
|
|
2490
|
|
2491 #define NSTATIC_COLOURS 32
|
|
2492 #define NDYNAMIC_COLOURS 33
|
|
2493 #define NCOLOURS (NSTATIC_COLOURS + NDYNAMIC_COLOURS)
|
|
2494
|
|
2495 static GuiColourTable table[NCOLOURS] =
|
|
2496 {
|
|
2497 {"Black", RGB(0x00, 0x00, 0x00)},
|
|
2498 {"DarkGray", RGB(0x80, 0x80, 0x80)},
|
|
2499 {"DarkGrey", RGB(0x80, 0x80, 0x80)},
|
|
2500 {"Gray", RGB(0xC0, 0xC0, 0xC0)},
|
|
2501 {"Grey", RGB(0xC0, 0xC0, 0xC0)},
|
|
2502 {"LightGray", RGB(0xD3, 0xD3, 0xD3)},
|
|
2503 {"LightGrey", RGB(0xD3, 0xD3, 0xD3)},
|
|
2504 {"White", RGB(0xFF, 0xFF, 0xFF)},
|
|
2505 {"DarkRed", RGB(0x80, 0x00, 0x00)},
|
|
2506 {"Red", RGB(0xFF, 0x00, 0x00)},
|
|
2507 {"LightRed", RGB(0xFF, 0xA0, 0xA0)},
|
|
2508 {"DarkBlue", RGB(0x00, 0x00, 0x80)},
|
|
2509 {"Blue", RGB(0x00, 0x00, 0xFF)},
|
|
2510 {"LightBlue", RGB(0xA0, 0xA0, 0xFF)},
|
|
2511 {"DarkGreen", RGB(0x00, 0x80, 0x00)},
|
|
2512 {"Green", RGB(0x00, 0xFF, 0x00)},
|
|
2513 {"LightGreen", RGB(0xA0, 0xFF, 0xA0)},
|
|
2514 {"DarkCyan", RGB(0x00, 0x80, 0x80)},
|
|
2515 {"Cyan", RGB(0x00, 0xFF, 0xFF)},
|
|
2516 {"LightCyan", RGB(0xA0, 0xFF, 0xFF)},
|
|
2517 {"DarkMagenta", RGB(0x80, 0x00, 0x80)},
|
|
2518 {"Magenta", RGB(0xFF, 0x00, 0xFF)},
|
|
2519 {"LightMagenta", RGB(0xFF, 0xA0, 0xFF)},
|
|
2520 {"Brown", RGB(0x80, 0x40, 0x40)},
|
|
2521 {"Yellow", RGB(0xFF, 0xFF, 0x00)},
|
|
2522 {"LightYellow", RGB(0xFF, 0xFF, 0xA0)},
|
|
2523 {"DarkYellow", RGB(0xBB, 0xBB, 0x00)},
|
|
2524 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)},
|
|
2525 {"Orange", RGB(0xFF, 0xA5, 0x00)},
|
|
2526 {"Purple", RGB(0xA0, 0x20, 0xF0)},
|
|
2527 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)},
|
|
2528 {"Violet", RGB(0xEE, 0x82, 0xEE)},
|
|
2529 };
|
|
2530
|
|
2531 static int endColour = NSTATIC_COLOURS;
|
|
2532 static int newColour = NSTATIC_COLOURS;
|
|
2533
|
|
2534 int r, g, b;
|
|
2535 int i;
|
|
2536
|
|
2537 if (name[0] == '#' && STRLEN(name) == 7)
|
|
2538 {
|
|
2539 /* Name is in "#rrggbb" format */
|
|
2540 r = hex_digit(name[1]) * 16 + hex_digit(name[2]);
|
|
2541 g = hex_digit(name[3]) * 16 + hex_digit(name[4]);
|
|
2542 b = hex_digit(name[5]) * 16 + hex_digit(name[6]);
|
|
2543 if (r < 0 || g < 0 || b < 0)
|
|
2544 return INVALCOLOR;
|
|
2545 return RGB(r, g, b);
|
|
2546 }
|
|
2547 else
|
|
2548 {
|
|
2549 /* Check if the name is one of the colours we know */
|
|
2550 for (i = 0; i < endColour; i++)
|
|
2551 if (STRICMP(name, table[i].name) == 0)
|
|
2552 return table[i].colour;
|
|
2553 }
|
|
2554
|
|
2555 /*
|
|
2556 * Last attempt. Look in the file "$VIM/rgb.txt".
|
|
2557 */
|
|
2558 {
|
|
2559 #define LINE_LEN 100
|
|
2560 FILE *fd;
|
|
2561 char line[LINE_LEN];
|
|
2562 char_u *fname;
|
|
2563
|
|
2564 fname = expand_env_save((char_u *)"$VIM/rgb.txt");
|
|
2565 if (fname == NULL)
|
|
2566 return INVALCOLOR;
|
|
2567
|
|
2568 fd = fopen((char *)fname, "rt");
|
|
2569 vim_free(fname);
|
|
2570 if (fd == NULL)
|
|
2571 return INVALCOLOR;
|
|
2572
|
|
2573 while (!feof(fd))
|
|
2574 {
|
|
2575 int len;
|
|
2576 int pos;
|
|
2577 char *colour;
|
|
2578
|
|
2579 fgets(line, LINE_LEN, fd);
|
|
2580 len = strlen(line);
|
|
2581
|
|
2582 if (len <= 1 || line[len-1] != '\n')
|
|
2583 continue;
|
|
2584
|
|
2585 line[len-1] = '\0';
|
|
2586
|
|
2587 i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos);
|
|
2588 if (i != 3)
|
|
2589 continue;
|
|
2590
|
|
2591 colour = line + pos;
|
|
2592
|
|
2593 if (STRICMP(colour, name) == 0)
|
|
2594 {
|
|
2595 fclose(fd);
|
|
2596 /*
|
|
2597 * Now remember this colour in the table.
|
|
2598 * A LRU scheme might be better but this is simpler.
|
|
2599 * Or could use a growing array.
|
|
2600 */
|
|
2601 guicolor_T gcolour = RGB(r,g,b);
|
|
2602
|
|
2603 vim_free(table[newColour].name);
|
|
2604 table[newColour].name = (char *)vim_strsave((char_u *)colour);
|
|
2605 table[newColour].colour = gcolour;
|
|
2606
|
|
2607 newColour++;
|
|
2608 if (newColour >= NCOLOURS)
|
|
2609 newColour = NSTATIC_COLOURS;
|
|
2610 if (endColour < NCOLOURS)
|
|
2611 endColour = newColour;
|
|
2612
|
|
2613 return gcolour;
|
|
2614 }
|
|
2615 }
|
|
2616
|
|
2617 fclose(fd);
|
|
2618 }
|
|
2619
|
|
2620 return INVALCOLOR;
|
|
2621 }
|
|
2622
|
|
2623 /*
|
|
2624 * Set the current text foreground color.
|
|
2625 */
|
|
2626 void
|
|
2627 gui_mch_set_fg_color(
|
|
2628 guicolor_T color)
|
|
2629 {
|
|
2630 rgb_color rgb = GUI_TO_RGB(color);
|
|
2631 if (gui.vimWindow->Lock()) {
|
|
2632 gui.vimTextArea->SetHighColor(rgb);
|
|
2633 gui.vimWindow->Unlock();
|
|
2634 }
|
|
2635 }
|
|
2636
|
|
2637 /*
|
|
2638 * Set the current text background color.
|
|
2639 */
|
|
2640 void
|
|
2641 gui_mch_set_bg_color(
|
|
2642 guicolor_T color)
|
|
2643 {
|
|
2644 rgb_color rgb = GUI_TO_RGB(color);
|
|
2645 if (gui.vimWindow->Lock()) {
|
|
2646 gui.vimTextArea->SetLowColor(rgb);
|
|
2647 gui.vimWindow->Unlock();
|
|
2648 }
|
|
2649 }
|
|
2650
|
|
2651 void
|
|
2652 gui_mch_draw_string(
|
|
2653 int row,
|
|
2654 int col,
|
|
2655 char_u *s,
|
|
2656 int len,
|
|
2657 int flags)
|
|
2658 {
|
|
2659 if (gui.vimWindow->Lock()) {
|
|
2660 gui.vimTextArea->mchDrawString(row, col, s, len, flags);
|
|
2661 gui.vimWindow->Unlock();
|
|
2662 }
|
|
2663 }
|
|
2664
|
|
2665 /*
|
|
2666 * Return OK if the key with the termcap name "name" is supported.
|
|
2667 */
|
|
2668 int
|
|
2669 gui_mch_haskey(
|
|
2670 char_u *name)
|
|
2671 {
|
|
2672 int i;
|
|
2673
|
|
2674 for (i = 0; special_keys[i].BeKeys != 0; i++)
|
|
2675 if (name[0] == special_keys[i].vim_code0 &&
|
|
2676 name[1] == special_keys[i].vim_code1)
|
|
2677 return OK;
|
|
2678 return FAIL;
|
|
2679 }
|
|
2680
|
|
2681 void
|
|
2682 gui_mch_beep()
|
|
2683 {
|
|
2684 ::beep();
|
|
2685 }
|
|
2686
|
|
2687 void
|
|
2688 gui_mch_flash(int msec)
|
|
2689 {
|
|
2690 /* Do a visual beep by reversing the foreground and background colors */
|
|
2691
|
|
2692 if (gui.vimWindow->Lock()) {
|
|
2693 BRect rect = gui.vimTextArea->Bounds();
|
|
2694
|
|
2695 gui.vimTextArea->SetDrawingMode(B_OP_INVERT);
|
|
2696 gui.vimTextArea->FillRect(rect);
|
|
2697 gui.vimTextArea->Sync();
|
|
2698 snooze(msec * 1000); /* wait for a few msec */
|
|
2699 gui.vimTextArea->FillRect(rect);
|
|
2700 gui.vimTextArea->SetDrawingMode(B_OP_COPY);
|
|
2701 gui.vimTextArea->Flush();
|
|
2702 gui.vimWindow->Unlock();
|
|
2703 }
|
|
2704 }
|
|
2705
|
|
2706 /*
|
|
2707 * Invert a rectangle from row r, column c, for nr rows and nc columns.
|
|
2708 */
|
|
2709 void
|
|
2710 gui_mch_invert_rectangle(
|
|
2711 int r,
|
|
2712 int c,
|
|
2713 int nr,
|
|
2714 int nc)
|
|
2715 {
|
|
2716 BRect rect;
|
|
2717 rect.left = FILL_X(c);
|
|
2718 rect.top = FILL_Y(r);
|
|
2719 rect.right = rect.left + nc * gui.char_width - PEN_WIDTH;
|
|
2720 rect.bottom = rect.top + nr * gui.char_height - PEN_WIDTH;
|
|
2721
|
|
2722 if (gui.vimWindow->Lock()) {
|
|
2723 gui.vimTextArea->SetDrawingMode(B_OP_INVERT);
|
|
2724 gui.vimTextArea->FillRect(rect);
|
|
2725 gui.vimTextArea->SetDrawingMode(B_OP_COPY);
|
|
2726 gui.vimWindow->Unlock();
|
|
2727 }
|
|
2728 }
|
|
2729
|
|
2730 /*
|
|
2731 * Iconify the GUI window.
|
|
2732 */
|
|
2733 void
|
|
2734 gui_mch_iconify()
|
|
2735 {
|
|
2736 if (gui.vimWindow->Lock()) {
|
|
2737 gui.vimWindow->Minimize(true);
|
|
2738 gui.vimWindow->Unlock();
|
|
2739 }
|
|
2740 }
|
|
2741
|
|
2742 #if defined(FEAT_EVAL) || defined(PROTO)
|
|
2743 /*
|
|
2744 * Bring the Vim window to the foreground.
|
|
2745 */
|
|
2746 void
|
|
2747 gui_mch_set_foreground()
|
|
2748 {
|
|
2749 /* TODO */
|
|
2750 }
|
|
2751 #endif
|
|
2752
|
|
2753 /*
|
|
2754 * Set the window title
|
|
2755 */
|
|
2756 void
|
|
2757 gui_mch_settitle(
|
|
2758 char_u *title,
|
|
2759 char_u *icon)
|
|
2760 {
|
|
2761 if (gui.vimWindow->Lock()) {
|
|
2762 gui.vimWindow->SetTitle((char *)title);
|
|
2763 gui.vimWindow->Unlock();
|
|
2764 }
|
|
2765 }
|
|
2766
|
|
2767 /*
|
|
2768 * Draw a cursor without focus.
|
|
2769 */
|
|
2770 void
|
|
2771 gui_mch_draw_hollow_cursor(guicolor_T color)
|
|
2772 {
|
|
2773 gui_mch_set_fg_color(color);
|
|
2774
|
|
2775 BRect r;
|
|
2776 r.left = FILL_X(gui.col);
|
|
2777 r.top = FILL_Y(gui.row);
|
|
2778 r.right = r.left + gui.char_width - PEN_WIDTH;
|
|
2779 r.bottom = r.top + gui.char_height - PEN_WIDTH;
|
|
2780
|
|
2781 if (gui.vimWindow->Lock()) {
|
|
2782 gui.vimTextArea->StrokeRect(r);
|
|
2783 gui.vimWindow->Unlock();
|
|
2784 //gui_mch_flush();
|
|
2785 }
|
|
2786 }
|
|
2787
|
|
2788 /*
|
|
2789 * Draw part of a cursor, only w pixels wide, and h pixels high.
|
|
2790 */
|
|
2791 void
|
|
2792 gui_mch_draw_part_cursor(
|
|
2793 int w,
|
|
2794 int h,
|
|
2795 guicolor_T color)
|
|
2796 {
|
|
2797 gui_mch_set_fg_color(color);
|
|
2798
|
|
2799 BRect r;
|
|
2800 r.left =
|
|
2801 #ifdef FEAT_RIGHTLEFT
|
|
2802 /* vertical line should be on the right of current point */
|
|
2803 CURSOR_BAR_RIGHT ? FILL_X(gui.col + 1) - w :
|
|
2804 #endif
|
|
2805 FILL_X(gui.col);
|
|
2806 r.right = r.left + w - PEN_WIDTH;
|
|
2807 r.bottom = FILL_Y(gui.row + 1) - PEN_WIDTH;
|
|
2808 r.top = r.bottom - h + PEN_WIDTH;
|
|
2809
|
|
2810 if (gui.vimWindow->Lock()) {
|
|
2811 gui.vimTextArea->FillRect(r);
|
|
2812 gui.vimWindow->Unlock();
|
|
2813 //gui_mch_flush();
|
|
2814 }
|
|
2815 }
|
|
2816
|
|
2817 /*
|
|
2818 * Catch up with any queued events. This may put keyboard input into the
|
|
2819 * input buffer, call resize call-backs, trigger timers etc. If there is
|
|
2820 * nothing in the event queue (& no timers pending), then we return
|
|
2821 * immediately.
|
|
2822 */
|
|
2823 void
|
|
2824 gui_mch_update()
|
|
2825 {
|
|
2826 gui_mch_flush();
|
|
2827 while (port_count(gui.vdcmp) > 0 &&
|
|
2828 !vim_is_input_buf_full() &&
|
|
2829 gui_beos_process_event(0) >= B_OK)
|
|
2830 /* nothing */ ;
|
|
2831 }
|
|
2832
|
|
2833 /*
|
|
2834 * GUI input routine called by gui_wait_for_chars(). Waits for a character
|
|
2835 * from the keyboard.
|
|
2836 * wtime == -1 Wait forever.
|
|
2837 * wtime == 0 This should never happen.
|
|
2838 * wtime > 0 Wait wtime milliseconds for a character.
|
|
2839 * Returns OK if a character was found to be available within the given time,
|
|
2840 * or FAIL otherwise.
|
|
2841 */
|
|
2842 int
|
|
2843 gui_mch_wait_for_chars(
|
|
2844 int wtime)
|
|
2845 {
|
|
2846 int focus;
|
|
2847 bigtime_t until, timeout;
|
|
2848 status_t st;
|
|
2849
|
|
2850 if (wtime >= 0) {
|
|
2851 timeout = wtime * 1000;
|
|
2852 until = system_time() + timeout;
|
|
2853 } else {
|
|
2854 timeout = B_INFINITE_TIMEOUT;
|
|
2855 }
|
|
2856
|
|
2857 focus = gui.in_focus;
|
|
2858 for (;;)
|
|
2859 {
|
|
2860 /* Stop or start blinking when focus changes */
|
|
2861 if (gui.in_focus != focus)
|
|
2862 {
|
|
2863 if (gui.in_focus)
|
|
2864 gui_mch_start_blink();
|
|
2865 else
|
|
2866 gui_mch_stop_blink();
|
|
2867 focus = gui.in_focus;
|
|
2868 }
|
|
2869
|
|
2870 gui_mch_flush();
|
|
2871 /*
|
|
2872 * Don't use gui_mch_update() because then we will spin-lock until a
|
|
2873 * char arrives, instead we use gui_beos_process_event() to hang until
|
|
2874 * an event arrives. No need to check for input_buf_full because we
|
|
2875 * are returning as soon as it contains a single char.
|
|
2876 */
|
|
2877 st = gui_beos_process_event(timeout);
|
|
2878
|
|
2879 if (input_available())
|
|
2880 return OK;
|
|
2881 if (st < B_OK) /* includes B_TIMED_OUT */
|
|
2882 return FAIL;
|
|
2883
|
|
2884 /*
|
|
2885 * Calculate how much longer we're willing to wait for the
|
|
2886 * next event.
|
|
2887 */
|
|
2888 if (wtime >= 0) {
|
|
2889 timeout = until - system_time();
|
|
2890 if (timeout < 0)
|
|
2891 break;
|
|
2892 }
|
|
2893 }
|
|
2894 return FAIL;
|
|
2895
|
|
2896 }
|
|
2897
|
|
2898 /*
|
|
2899 * Output routines.
|
|
2900 */
|
|
2901
|
|
2902 /*
|
|
2903 * Flush any output to the screen. This is typically called before
|
|
2904 * the app goes to sleep.
|
|
2905 */
|
|
2906 void
|
|
2907 gui_mch_flush()
|
|
2908 {
|
|
2909 // does this need to lock the window? Apparently not but be safe.
|
|
2910 if (gui.vimWindow->Lock()) {
|
|
2911 gui.vimWindow->Flush();
|
|
2912 gui.vimWindow->Unlock();
|
|
2913 }
|
|
2914 return;
|
|
2915 }
|
|
2916
|
|
2917 /*
|
|
2918 * Clear a rectangular region of the screen from text pos (row1, col1) to
|
|
2919 * (row2, col2) inclusive.
|
|
2920 */
|
|
2921 void
|
|
2922 gui_mch_clear_block(
|
|
2923 int row1,
|
|
2924 int col1,
|
|
2925 int row2,
|
|
2926 int col2)
|
|
2927 {
|
|
2928 if (gui.vimWindow->Lock()) {
|
|
2929 gui.vimTextArea->mchClearBlock(row1, col1, row2, col2);
|
|
2930 gui.vimWindow->Unlock();
|
|
2931 }
|
|
2932 }
|
|
2933
|
|
2934 void
|
|
2935 gui_mch_clear_all()
|
|
2936 {
|
|
2937 if (gui.vimWindow->Lock()) {
|
|
2938 gui.vimTextArea->mchClearAll();
|
|
2939 gui.vimWindow->Unlock();
|
|
2940 }
|
|
2941 }
|
|
2942
|
|
2943 /*
|
|
2944 * Delete the given number of lines from the given row, scrolling up any
|
|
2945 * text further down within the scroll region.
|
|
2946 */
|
|
2947 void
|
|
2948 gui_mch_delete_lines(
|
|
2949 int row,
|
|
2950 int num_lines)
|
|
2951 {
|
|
2952 gui.vimTextArea->mchDeleteLines(row, num_lines);
|
|
2953 }
|
|
2954
|
|
2955 /*
|
|
2956 * Insert the given number of lines before the given row, scrolling down any
|
|
2957 * following text within the scroll region.
|
|
2958 */
|
|
2959 void
|
|
2960 gui_mch_insert_lines(
|
|
2961 int row,
|
|
2962 int num_lines)
|
|
2963 {
|
|
2964 gui.vimTextArea->mchInsertLines(row, num_lines);
|
|
2965 }
|
|
2966
|
|
2967 #if defined(FEAT_MENU) || defined(PROTO)
|
|
2968 /*
|
|
2969 * Menu stuff.
|
|
2970 */
|
|
2971
|
|
2972 void
|
|
2973 gui_mch_enable_menu(
|
|
2974 int flag)
|
|
2975 {
|
|
2976 if (gui.vimWindow->Lock())
|
|
2977 {
|
|
2978 BMenuBar *menubar = gui.vimForm->MenuBar();
|
|
2979 menubar->SetEnabled(flag);
|
|
2980 gui.vimWindow->Unlock();
|
|
2981 }
|
|
2982 }
|
|
2983
|
|
2984 void
|
|
2985 gui_mch_set_menu_pos(
|
|
2986 int x,
|
|
2987 int y,
|
|
2988 int w,
|
|
2989 int h)
|
|
2990 {
|
|
2991 /* It will be in the right place anyway */
|
|
2992 }
|
|
2993
|
|
2994 /*
|
|
2995 * Add a sub menu to the menu bar.
|
|
2996 */
|
|
2997 void
|
|
2998 gui_mch_add_menu(
|
|
2999 vimmenu_T *menu,
|
|
3000 int idx)
|
|
3001 {
|
|
3002 vimmenu_T *parent = menu->parent;
|
|
3003
|
|
3004 if (!menu_is_menubar(menu->name)
|
|
3005 || (parent != NULL && parent->submenu_id == NULL))
|
|
3006 return;
|
|
3007
|
|
3008 if (gui.vimWindow->Lock())
|
|
3009 {
|
|
3010 /* Major re-write of the menu code, it was failing with memory corruption when
|
|
3011 * we started loading multiple files (the Buffer menu)
|
|
3012 *
|
|
3013 * Note we don't use the preference values yet, all are inserted into the
|
|
3014 * menubar on a first come-first served basis...
|
|
3015 *
|
|
3016 * richard@whitequeen.com jul 99
|
|
3017 */
|
|
3018
|
|
3019 BMenu *tmp;
|
|
3020
|
|
3021 if ( parent )
|
|
3022 tmp = parent->submenu_id;
|
|
3023 else
|
|
3024 tmp = gui.vimForm->MenuBar();
|
|
3025 // make sure we don't try and add the same menu twice. The Buffers menu tries to
|
|
3026 // do this and Be starts to crash...
|
|
3027
|
|
3028 if ( ! tmp->FindItem((const char *) menu->dname)) {
|
|
3029
|
|
3030 BMenu *bmenu = new BMenu((char *)menu->dname);
|
|
3031
|
|
3032 menu->submenu_id = bmenu;
|
|
3033
|
|
3034 // when we add a BMenu to another Menu, it creates the interconnecting BMenuItem
|
|
3035 tmp->AddItem(bmenu);
|
|
3036
|
|
3037 // Now its safe to query the menu for the associated MenuItem....
|
|
3038 menu->id = tmp->FindItem((const char *) menu->dname);
|
|
3039
|
|
3040 }
|
|
3041 gui.vimWindow->Unlock();
|
|
3042 }
|
|
3043 }
|
|
3044
|
|
3045 void
|
|
3046 gui_mch_toggle_tearoffs(int enable)
|
|
3047 {
|
|
3048 /* no tearoff menus */
|
|
3049 }
|
|
3050
|
|
3051 static BMessage *
|
|
3052 MenuMessage(vimmenu_T *menu)
|
|
3053 {
|
|
3054 BMessage *m = new BMessage('menu');
|
|
3055 m->AddPointer("VimMenu", (void *)menu);
|
|
3056
|
|
3057 return m;
|
|
3058 }
|
|
3059
|
|
3060 /*
|
|
3061 * Add a menu item to a menu
|
|
3062 */
|
|
3063 void
|
|
3064 gui_mch_add_menu_item(
|
|
3065 vimmenu_T *menu,
|
|
3066 int idx)
|
|
3067 {
|
|
3068 int mnemonic = 0;
|
|
3069 vimmenu_T *parent = menu->parent;
|
|
3070
|
|
3071 if (parent->submenu_id == NULL)
|
|
3072 return;
|
|
3073
|
|
3074 #ifdef never
|
|
3075 /* why not add separators ?
|
|
3076 * richard
|
|
3077 */
|
|
3078 /* Don't add menu separator */
|
|
3079 if (menu_is_separator(menu->name))
|
|
3080 return;
|
|
3081 #endif
|
|
3082
|
|
3083 /* TODO: use menu->actext */
|
|
3084 /* This is difficult, since on Be, an accelerator must be a single char
|
|
3085 * and a lot of Vim ones are the standard VI commands.
|
|
3086 *
|
|
3087 * Punt for Now...
|
|
3088 * richard@whiequeen.com jul 99
|
|
3089 */
|
|
3090 if (gui.vimWindow->Lock())
|
|
3091 {
|
|
3092 if ( menu_is_separator(menu->name)) {
|
|
3093 BSeparatorItem *item = new BSeparatorItem();
|
|
3094 parent->submenu_id->AddItem(item);
|
|
3095 menu->id = item;
|
|
3096 menu->submenu_id = NULL;
|
|
3097 }
|
|
3098 else {
|
|
3099 BMenuItem *item = new BMenuItem((char *)menu->dname,
|
|
3100 MenuMessage(menu));
|
|
3101 item->SetTarget(gui.vimTextArea);
|
|
3102 item->SetTrigger((char) menu->mnemonic);
|
|
3103 parent->submenu_id->AddItem(item);
|
|
3104 menu->id = item;
|
|
3105 menu->submenu_id = NULL;
|
|
3106 }
|
|
3107 gui.vimWindow->Unlock();
|
|
3108 }
|
|
3109 }
|
|
3110
|
|
3111 /*
|
|
3112 * Destroy the machine specific menu widget.
|
|
3113 */
|
|
3114 void
|
|
3115 gui_mch_destroy_menu(
|
|
3116 vimmenu_T *menu)
|
|
3117 {
|
|
3118 if (gui.vimWindow->Lock())
|
|
3119 {
|
|
3120 assert(menu->submenu_id == NULL || menu->submenu_id->CountItems() == 0);
|
|
3121 /*
|
|
3122 * Detach this menu from its parent, so that it is not deleted
|
|
3123 * twice once we get to delete that parent.
|
|
3124 * Deleting a BMenuItem also deletes the associated BMenu, if any
|
|
3125 * (which does not have any items anymore since they were
|
|
3126 * removed and deleted before).
|
|
3127 */
|
|
3128 BMenu *bmenu = menu->id->Menu();
|
|
3129 if (bmenu)
|
|
3130 {
|
|
3131 bmenu->RemoveItem(menu->id);
|
|
3132 /*
|
|
3133 * If we removed the last item from the menu bar,
|
|
3134 * resize it out of sight.
|
|
3135 */
|
|
3136 if (bmenu == gui.vimForm->MenuBar() && bmenu->CountItems() == 0)
|
|
3137 {
|
|
3138 bmenu->ResizeTo(-MENUBAR_MARGIN, -MENUBAR_MARGIN);
|
|
3139 }
|
|
3140 }
|
|
3141 delete menu->id;
|
|
3142 menu->id = NULL;
|
|
3143 menu->submenu_id = NULL;
|
|
3144
|
|
3145 gui.menu_height = (int) gui.vimForm->MenuHeight();
|
|
3146 gui.vimWindow->Unlock();
|
|
3147 }
|
|
3148 }
|
|
3149
|
|
3150 /*
|
|
3151 * Make a menu either grey or not grey.
|
|
3152 */
|
|
3153 void
|
|
3154 gui_mch_menu_grey(
|
|
3155 vimmenu_T *menu,
|
|
3156 int grey)
|
|
3157 {
|
|
3158 if (menu->id != NULL)
|
|
3159 menu->id->SetEnabled(!grey);
|
|
3160 }
|
|
3161
|
|
3162 /*
|
|
3163 * Make menu item hidden or not hidden
|
|
3164 */
|
|
3165 void
|
|
3166 gui_mch_menu_hidden(
|
|
3167 vimmenu_T *menu,
|
|
3168 int hidden)
|
|
3169 {
|
|
3170 if (menu->id != NULL)
|
|
3171 menu->id->SetEnabled(!hidden);
|
|
3172 }
|
|
3173
|
|
3174 /*
|
|
3175 * This is called after setting all the menus to grey/hidden or not.
|
|
3176 */
|
|
3177 void
|
|
3178 gui_mch_draw_menubar()
|
|
3179 {
|
|
3180 /* Nothing to do in BeOS */
|
|
3181 }
|
|
3182
|
|
3183 #endif /* FEAT_MENU */
|
|
3184
|
|
3185 /* Mouse stuff */
|
|
3186
|
|
3187 #ifdef FEAT_CLIPBOARD
|
|
3188 /*
|
|
3189 * Clipboard stuff, for cutting and pasting text to other windows.
|
|
3190 */
|
|
3191 char textplain[] = "text/plain";
|
|
3192 char vimselectiontype[] = "application/x-vnd.Rhialto-Vim-selectiontype";
|
|
3193
|
|
3194 /*
|
|
3195 * Get the current selection and put it in the clipboard register.
|
|
3196 */
|
|
3197 void
|
|
3198 clip_mch_request_selection(VimClipboard *cbd)
|
|
3199 {
|
|
3200 if (be_clipboard->Lock())
|
|
3201 {
|
|
3202 BMessage *m = be_clipboard->Data();
|
|
3203 //m->PrintToStream();
|
|
3204
|
|
3205 char_u *string = NULL;
|
|
3206 ssize_t stringlen = -1;
|
|
3207
|
|
3208 if (m->FindData(textplain, B_MIME_TYPE,
|
|
3209 (const void **)&string, &stringlen) == B_OK
|
|
3210 || m->FindString("text", (const char **)&string) == B_OK)
|
|
3211 {
|
|
3212 if (stringlen == -1)
|
|
3213 stringlen = STRLEN(string);
|
|
3214
|
|
3215 int type;
|
|
3216 char *seltype;
|
|
3217 ssize_t seltypelen;
|
|
3218
|
|
3219 /*
|
|
3220 * Try to get the special vim selection type first
|
|
3221 */
|
|
3222 if (m->FindData(vimselectiontype, B_MIME_TYPE,
|
|
3223 (const void **)&seltype, &seltypelen) == B_OK)
|
|
3224 {
|
|
3225 switch (*seltype)
|
|
3226 {
|
|
3227 default:
|
|
3228 case 'L': type = MLINE; break;
|
|
3229 case 'C': type = MCHAR; break;
|
|
3230 #ifdef FEAT_VISUAL
|
|
3231 case 'B': type = MBLOCK; break;
|
|
3232 #endif
|
|
3233 }
|
|
3234 }
|
|
3235 else
|
|
3236 {
|
|
3237 /* Otherwise use heuristic as documented */
|
|
3238 type = memchr(string, stringlen, '\n') ? MLINE : MCHAR;
|
|
3239 }
|
|
3240 clip_yank_selection(type, string, (long)stringlen, cbd);
|
|
3241 }
|
|
3242 be_clipboard->Unlock();
|
|
3243 }
|
|
3244 }
|
|
3245 /*
|
|
3246 * Make vim the owner of the current selection.
|
|
3247 */
|
|
3248 void
|
|
3249 clip_mch_lose_selection(VimClipboard *cbd)
|
|
3250 {
|
|
3251 /* Nothing needs to be done here */
|
|
3252 }
|
|
3253
|
|
3254 /*
|
|
3255 * Make vim the owner of the current selection. Return OK upon success.
|
|
3256 */
|
|
3257 int
|
|
3258 clip_mch_own_selection(VimClipboard *cbd)
|
|
3259 {
|
|
3260 /*
|
|
3261 * Never actually own the clipboard. If another application sets the
|
|
3262 * clipboard, we don't want to think that we still own it.
|
|
3263 */
|
|
3264 return FAIL;
|
|
3265 }
|
|
3266
|
|
3267 /*
|
|
3268 * Send the current selection to the clipboard.
|
|
3269 */
|
|
3270 void
|
|
3271 clip_mch_set_selection(VimClipboard *cbd)
|
|
3272 {
|
|
3273 if (be_clipboard->Lock())
|
|
3274 {
|
|
3275 be_clipboard->Clear();
|
|
3276 BMessage *m = be_clipboard->Data();
|
|
3277 assert(m);
|
|
3278
|
|
3279 /* If the '*' register isn't already filled in, fill it in now */
|
|
3280 cbd->owned = TRUE;
|
|
3281 clip_get_selection(cbd);
|
|
3282 cbd->owned = FALSE;
|
|
3283
|
|
3284 char_u *str = NULL;
|
|
3285 long_u count;
|
|
3286 int type;
|
|
3287
|
|
3288 type = clip_convert_selection(&str, &count, cbd);
|
|
3289
|
|
3290 if (type < 0)
|
|
3291 return;
|
|
3292
|
|
3293 m->AddData(textplain, B_MIME_TYPE, (void *)str, count);
|
|
3294
|
|
3295 /* Add type of selection */
|
|
3296 char vtype;
|
|
3297 switch (type)
|
|
3298 {
|
|
3299 default:
|
|
3300 case MLINE: vtype = 'L'; break;
|
|
3301 case MCHAR: vtype = 'C'; break;
|
|
3302 #ifdef FEAT_VISUAL
|
|
3303 case MBLOCK: vtype = 'B'; break;
|
|
3304 #endif
|
|
3305 }
|
|
3306 m->AddData(vimselectiontype, B_MIME_TYPE, (void *)&vtype, 1);
|
|
3307
|
|
3308 vim_free(str);
|
|
3309
|
|
3310 be_clipboard->Commit();
|
|
3311 be_clipboard->Unlock();
|
|
3312 }
|
|
3313 }
|
|
3314
|
|
3315 #endif /* FEAT_CLIPBOARD */
|
|
3316
|
|
3317 /*
|
|
3318 * Return the RGB value of a pixel as long.
|
|
3319 */
|
|
3320 long_u
|
|
3321 gui_mch_get_rgb(guicolor_T pixel)
|
|
3322 {
|
|
3323 rgb_color rgb = GUI_TO_RGB(pixel);
|
|
3324
|
|
3325 return ((rgb.red & 0xff) << 16) + ((rgb.green & 0xff) << 8)
|
|
3326 + (rgb.blue & 0xff);
|
|
3327 }
|
|
3328
|
|
3329 void
|
|
3330 gui_mch_setmouse(int x, int y)
|
|
3331 {
|
|
3332 TRACE();
|
|
3333 /* TODO */
|
|
3334 }
|
|
3335
|
|
3336 void
|
|
3337 gui_mch_show_popupmenu(vimmenu_T *menu)
|
|
3338 {
|
|
3339 TRACE();
|
|
3340 /* TODO */
|
|
3341 }
|
|
3342
|
|
3343 int
|
|
3344 gui_mch_get_mouse_x()
|
|
3345 {
|
|
3346 TRACE();
|
|
3347 return 0;
|
|
3348 }
|
|
3349
|
|
3350
|
|
3351 int
|
|
3352 gui_mch_get_mouse_y()
|
|
3353 {
|
|
3354 TRACE();
|
|
3355 return 0;
|
|
3356 }
|
|
3357
|
|
3358 } /* extern "C" */
|