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 * Based on "GUI support for the Buzzword Enhanced Operating System." 11 * 12 * Ported to R4 by Richard Offer <[email protected]> Jul 99 13 * 14 * Haiku support by Siarzhuk Zharski <[email protected]> Apr-Mai 2009 15 * 16 */ 17 18 /* 19 * Structure of the Haiku GUI code: 20 * 21 * There are 3 threads. 22 * 1. The initial thread. In gui_mch_prepare() this gets to run the 23 * BApplication message loop. But before it starts doing that, 24 * it creates thread 2 25 * 2. The main() thread. This thread is created in gui_mch_prepare() 26 * and its purpose in life is to call main(argc, argv) again. 27 * This thread is doing the bulk of the work. 28 * 3. Sooner or later, a window is opened by the main() thread. This 29 * causes a second message loop to be created: the window thread. 30 * 31 * == alternatively === 32 * 33 * #if RUN_BAPPLICATION_IN_NEW_THREAD... 34 * 35 * 1. The initial thread. In gui_mch_prepare() this gets to spawn 36 * thread 2. After doing that, it returns to main() to do the 37 * bulk of the work, being the main() thread. 38 * 2. Runs the BApplication. 39 * 3. The window thread, just like in the first case. 40 * 41 * This second alternative is cleaner from Vim's viewpoint. However, 42 * the BeBook seems to assume everywhere that the BApplication *must* 43 * run in the initial thread. So perhaps doing otherwise is very wrong. 44 * 45 * However, from a B_SINGLE_LAUNCH viewpoint, the first is better. 46 * If Vim is marked "Single Launch" in its application resources, 47 * and a file is dropped on the Vim icon, and another Vim is already 48 * running, the file is passed on to the earlier Vim. This happens 49 * in BApplication::Run(). So we want Vim to terminate if 50 * BApplication::Run() terminates. (See the BeBook, on BApplication. 51 * However, it seems that the second copy of Vim isn't even started 52 * in this case... which is for the better since I wouldn't know how 53 * to detect this case.) 54 * 55 * Communication between these threads occurs mostly by translating 56 * BMessages that come in and posting an appropriate translation on 57 * the VDCMP (Vim Direct Communication Message Port). Therefore the 58 * actions required for keypresses and window resizes, etc, are mostly 59 * performed in the main() thread. 60 * 61 * A notable exception to this is the Draw() event. The redrawing of 62 * the window contents is performed asynchronously from the window 63 * thread. To make this work correctly, a locking protocol is used when 64 * any thread is accessing the essential variables that are used by 65 * the window thread. 66 * 67 * This locking protocol consists of locking Vim's window. This is both 68 * convenient and necessary. 69 */ 70 71 extern "C" { 72 73 #include <assert.h> 74 #include <float.h> 75 #include <syslog.h> 76 77 #include "vim.h" 78 #include "globals.h" 79 #include "proto.h" 80 #include "version.h" 81 82 } // extern "C" 83 84 // ---------------- start of header part ---------------- 85 86 //#include <Alert.h> 87 #include <Application.h> 88 #include <Beep.h> 89 #include <Bitmap.h> 90 #include <Box.h> 91 #include <Button.h> 92 #include <Clipboard.h> 93 #include <Debug.h> 94 //#include <Directory.h> 95 //#include <Entry.h> 96 #include <File.h> 97 #include <FilePanel.h> 98 #include <FindDirectory.h> 99 //#include <Font.h> 100 #include <IconUtils.h> 101 #include <Input.h> 102 #include <ListView.h> 103 #include <MenuBar.h> 104 #include <MenuItem.h> 105 //#include <MessageQueue.h> 106 //#include <OS.h> 107 #include <Path.h> 108 #include <PictureButton.h> 109 #include <PopUpMenu.h> 110 //#include <Region.h> 111 #include <Resources.h> 112 //#include <Roster.h> 113 #include <Screen.h> 114 #include <ScrollBar.h> 115 #include <ScrollView.h> 116 #include <String.h> 117 #include <StringView.h> 118 //#include <SupportDefs.h> 119 #include <TabView.h> 120 #include <TextControl.h> 121 #include <TextView.h> 122 #include <TranslationUtils.h> 123 #include <TranslatorFormats.h> 124 #include <View.h> 125 #include <Window.h> 126 127 class VimApp; 128 class VimFormView; 129 class VimTextAreaView; 130 class VimWindow; 131 class VimToolbar; 132 class VimTabLine; 133 134 extern key_map *keyMap; 135 extern char *keyMapChars; 136 137 extern int main(int argc, char **argv); 138 139 #ifndef B_MAX_PORT_COUNT 140 #define B_MAX_PORT_COUNT 255 141 #endif 142 143 // VimApp seems comparable to the X "vimShell" 144 class VimApp: public BApplication 145 { 146 typedef BApplication Inherited; 147 public: 148 VimApp(const char *appsig); 149 ~VimApp(); 150 151 // callbacks: 152 #if 0 153 virtual void DispatchMessage(BMessage *m, BHandler *h) 154 { 155 m->PrintToStream(); 156 Inherited::DispatchMessage(m, h); 157 } 158 #endif 159 virtual void ReadyToRun(); 160 virtual void ArgvReceived(int32 argc, char **argv); 161 virtual void RefsReceived(BMessage *m); 162 virtual bool QuitRequested(); 163 virtual void MessageReceived(BMessage *m); 164 165 static void SendRefs(BMessage *m, bool changedir); 166 167 sem_id fFilePanelSem; 168 BFilePanel* fFilePanel; 169 BPath fBrowsedPath; 170 private: 171 }; 172 173 class VimWindow: public BWindow 174 { 175 typedef BWindow Inherited; 176 public: 177 VimWindow(); 178 ~VimWindow(); 179 180 // virtual void DispatchMessage(BMessage *m, BHandler *h); 181 virtual void WindowActivated(bool active); 182 virtual bool QuitRequested(); 183 184 VimFormView *formView; 185 186 private: 187 void init(); 188 189 }; 190 191 class VimFormView: public BView 192 { 193 typedef BView Inherited; 194 public: 195 VimFormView(BRect frame); 196 ~VimFormView(); 197 198 // callbacks: 199 virtual void AllAttached(); 200 virtual void FrameResized(float new_width, float new_height); 201 202 #define MENUBAR_MARGIN 1 203 float MenuHeight() const 204 { return menuBar ? menuBar->Frame().Height() + MENUBAR_MARGIN: 0; } 205 BMenuBar *MenuBar() const 206 { return menuBar; } 207 208 private: 209 void init(BRect); 210 211 BMenuBar *menuBar; 212 VimTextAreaView *textArea; 213 214 #ifdef FEAT_TOOLBAR 215 public: 216 float ToolbarHeight() const; 217 VimToolbar *ToolBar() const 218 { return toolBar; } 219 private: 220 VimToolbar *toolBar; 221 #endif 222 223 #ifdef FEAT_GUI_TABLINE 224 public: 225 VimTabLine *TabLine() const { return tabLine; } 226 bool IsShowingTabLine() const { return showingTabLine; } 227 void SetShowingTabLine(bool showing) { showingTabLine = showing; } 228 float TablineHeight() const; 229 private: 230 VimTabLine *tabLine; 231 int showingTabLine; 232 #endif 233 }; 234 235 class VimTextAreaView: public BView 236 { 237 typedef BView Inherited; 238 public: 239 VimTextAreaView(BRect frame); 240 ~VimTextAreaView(); 241 242 // callbacks: 243 virtual void Draw(BRect updateRect); 244 virtual void KeyDown(const char *bytes, int32 numBytes); 245 virtual void MouseDown(BPoint point); 246 virtual void MouseUp(BPoint point); 247 virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *message); 248 virtual void MessageReceived(BMessage *m); 249 250 // own functions: 251 int mchInitFont(char_u *name); 252 void mchDrawString(int row, int col, char_u *s, int len, int flags); 253 void mchClearBlock(int row1, int col1, int row2, int col2); 254 void mchClearAll(); 255 void mchDeleteLines(int row, int num_lines); 256 void mchInsertLines(int row, int num_lines); 257 258 static void guiSendMouseEvent(int button, int x, int y, int repeated_click, int_u modifiers); 259 static void guiMouseMoved(int x, int y); 260 static void guiBlankMouse(bool should_hide); 261 static int_u mouseModifiersToVim(int32 beModifiers); 262 263 int32 mouseDragEventCount; 264 265 #ifdef FEAT_MBYTE_IME 266 void DrawIMString(void); 267 #endif 268 269 private: 270 void init(BRect); 271 272 int_u vimMouseButton; 273 int_u vimMouseModifiers; 274 275 #ifdef FEAT_MBYTE_IME 276 struct { 277 BMessenger* messenger; 278 BMessage* message; 279 BPoint location; 280 int row; 281 int col; 282 int count; 283 } IMData; 284 #endif 285 }; 286 287 class VimScrollBar: public BScrollBar 288 { 289 typedef BScrollBar Inherited; 290 public: 291 VimScrollBar(scrollbar_T *gsb, orientation posture); 292 ~VimScrollBar(); 293 294 virtual void ValueChanged(float newValue); 295 virtual void MouseUp(BPoint where); 296 void SetValue(float newval); 297 scrollbar_T *getGsb() 298 { return gsb; } 299 300 int32 scrollEventCount; 301 302 private: 303 scrollbar_T *gsb; 304 float ignoreValue; 305 }; 306 307 308 #ifdef FEAT_TOOLBAR 309 310 class VimToolbar : public BBox 311 { 312 static BBitmap *normalButtonsBitmap; 313 static BBitmap *grayedButtonsBitmap; 314 315 BBitmap *LoadVimBitmap(const char* fileName); 316 bool GetPictureFromBitmap(BPicture *pictureTo, int32 index, BBitmap *bitmapFrom, bool pressed); 317 bool ModifyBitmapToGrayed(BBitmap *bitmap); 318 319 BList fButtonsList; 320 void InvalidateLayout(); 321 322 public: 323 VimToolbar(BRect frame, const char * name); 324 ~VimToolbar(); 325 326 bool PrepareButtonBitmaps(); 327 328 bool AddButton(int32 index, vimmenu_T *menu); 329 bool RemoveButton(vimmenu_T *menu); 330 bool GrayButton(vimmenu_T *menu, int grey); 331 332 float ToolbarHeight() const; 333 virtual void AttachedToWindow(); 334 }; 335 336 BBitmap *VimToolbar::normalButtonsBitmap = NULL; 337 BBitmap *VimToolbar::grayedButtonsBitmap = NULL; 338 339 const float ToolbarMargin = 3.; 340 const float ButtonMargin = 3.; 341 342 #endif //FEAT_TOOLBAR 343 344 #ifdef FEAT_GUI_TABLINE 345 346 class VimTabLine : public BTabView 347 { 348 public: 349 class VimTab : public BTab { 350 public: 351 VimTab() : BTab(new BView(BRect(), "-Empty-", 0, 0)) {} 352 353 virtual void Select(BView* owner); 354 }; 355 356 VimTabLine(BRect r) : BTabView(r, "vimTabLine", B_WIDTH_FROM_LABEL, 357 B_FOLLOW_LEFT | B_FOLLOW_TOP | B_FOLLOW_RIGHT, B_WILL_DRAW | B_FRAME_EVENTS) {} 358 359 float TablineHeight() const; 360 virtual void MouseDown(BPoint point); 361 }; 362 363 #endif //FEAT_GUI_TABLINE 364 365 366 // For caching the fonts that are used; 367 // Vim seems rather sloppy in this regard. 368 class VimFont: public BFont 369 { 370 typedef BFont Inherited; 371 public: 372 VimFont(); 373 VimFont(const VimFont *rhs); 374 VimFont(const BFont *rhs); 375 VimFont(const VimFont &rhs); 376 ~VimFont(); 377 378 VimFont *next; 379 int refcount; 380 char_u *name; 381 382 private: 383 void init(); 384 }; 385 386 #if defined(FEAT_GUI_DIALOG) 387 388 class VimDialog : public BWindow 389 { 390 typedef BWindow Inherited; 391 392 BButton* _CreateButton(int32 which, const char* label); 393 394 public: 395 396 class View : public BView { 397 typedef BView Inherited; 398 399 public: 400 View(BRect frame); 401 ~View(); 402 403 virtual void Draw(BRect updateRect); 404 void InitIcon(int32 type); 405 406 private: 407 BBitmap* fIconBitmap; 408 }; 409 410 VimDialog(int type, const char *title, const char *message, 411 const char *buttons, int dfltbutton, const char *textfield, 412 int ex_cmd); 413 ~VimDialog(); 414 415 int Go(); 416 417 virtual void MessageReceived(BMessage *msg); 418 419 private: 420 sem_id fDialogSem; 421 int fDialogValue; 422 BList fButtonsList; 423 BTextView* fMessageView; 424 BTextControl* fInputControl; 425 const char* fInputValue; 426 }; 427 428 class VimSelectFontDialog : public BWindow 429 { 430 typedef BWindow Inherited; 431 432 void _CleanList(BListView* list); 433 void _UpdateFontStyles(); 434 void _UpdateSizeInputPreview(); 435 void _UpdateFontPreview(); 436 bool _UpdateFromListItem(BListView* list, char* text, int textSize); 437 public: 438 439 VimSelectFontDialog(font_family* family, font_style* style, float* size); 440 ~VimSelectFontDialog(); 441 442 bool Go(); 443 444 virtual void MessageReceived(BMessage *msg); 445 446 private: 447 status_t fStatus; 448 sem_id fDialogSem; 449 bool fDialogValue; 450 font_family* fFamily; 451 font_style* fStyle; 452 float* fSize; 453 font_family fFontFamily; 454 font_style fFontStyle; 455 float fFontSize; 456 BStringView* fPreview; 457 BListView* fFamiliesList; 458 BListView* fStylesList; 459 BListView* fSizesList; 460 BTextControl* fSizesInput; 461 }; 462 463 #endif // FEAT_GUI_DIALOG 464 465 // ---------------- end of GUI classes ---------------- 466 467 struct MainArgs { 468 int argc; 469 char **argv; 470 }; 471 472 // These messages are copied through the VDCMP. 473 // Therefore they ought not to have anything fancy. 474 // They must be of POD type (Plain Old Data) 475 // as the C++ standard calls them. 476 477 #define KEY_MSG_BUFSIZ 7 478 #if KEY_MSG_BUFSIZ < MAX_KEY_CODE_LEN 479 #error Increase KEY_MSG_BUFSIZ! 480 #endif 481 482 struct VimKeyMsg { 483 char_u length; 484 char_u chars[KEY_MSG_BUFSIZ]; // contains Vim encoding 485 bool csi_escape; 486 }; 487 488 struct VimResizeMsg { 489 int width; 490 int height; 491 }; 492 493 struct VimScrollBarMsg { 494 VimScrollBar *sb; 495 long value; 496 int stillDragging; 497 }; 498 499 struct VimMenuMsg { 500 vimmenu_T *guiMenu; 501 }; 502 503 struct VimMouseMsg { 504 int button; 505 int x; 506 int y; 507 int repeated_click; 508 int_u modifiers; 509 }; 510 511 struct VimMouseMovedMsg { 512 int x; 513 int y; 514 }; 515 516 struct VimFocusMsg { 517 bool active; 518 }; 519 520 struct VimRefsMsg { 521 BMessage *message; 522 bool changedir; 523 }; 524 525 struct VimTablineMsg { 526 int index; 527 }; 528 529 struct VimTablineMenuMsg { 530 int index; 531 int event; 532 }; 533 534 struct VimMsg { 535 enum VimMsgType { 536 Key, Resize, ScrollBar, Menu, Mouse, MouseMoved, Focus, Refs, Tabline, TablineMenu 537 }; 538 539 union { 540 struct VimKeyMsg Key; 541 struct VimResizeMsg NewSize; 542 struct VimScrollBarMsg Scroll; 543 struct VimMenuMsg Menu; 544 struct VimMouseMsg Mouse; 545 struct VimMouseMovedMsg MouseMoved; 546 struct VimFocusMsg Focus; 547 struct VimRefsMsg Refs; 548 struct VimTablineMsg Tabline; 549 struct VimTablineMenuMsg TablineMenu; 550 } u; 551 }; 552 553 #define RGB(r, g, b) ((char_u)(r) << 16 | (char_u)(g) << 8 | (char_u)(b) << 0) 554 #define GUI_TO_RGB(g) { (char_u)((g) >> 16), (char_u)((g) >> 8), (char_u)((g) >> 0), 255 } 555 556 // ---------------- end of header part ---------------- 557 558 static struct specialkey 559 { 560 uint16 BeKeys; 561 #define KEY(a,b) ((a)<<8|(b)) 562 #define K(a) KEY(0,a) // for ASCII codes 563 #define F(b) KEY(1,b) // for scancodes 564 char_u vim_code0; 565 char_u vim_code1; 566 } special_keys[] = 567 { 568 {K(B_UP_ARROW), 'k', 'u'}, 569 {K(B_DOWN_ARROW), 'k', 'd'}, 570 {K(B_LEFT_ARROW), 'k', 'l'}, 571 {K(B_RIGHT_ARROW), 'k', 'r'}, 572 {K(B_BACKSPACE), 'k', 'b'}, 573 {K(B_INSERT), 'k', 'I'}, 574 {K(B_DELETE), 'k', 'D'}, 575 {K(B_HOME), 'k', 'h'}, 576 {K(B_END), '@', '7'}, 577 {K(B_PAGE_UP), 'k', 'P'}, // XK_Prior 578 {K(B_PAGE_DOWN), 'k', 'N'}, // XK_Next, 579 580 #define FIRST_FUNCTION_KEY 11 581 {F(B_F1_KEY), 'k', '1'}, 582 {F(B_F2_KEY), 'k', '2'}, 583 {F(B_F3_KEY), 'k', '3'}, 584 {F(B_F4_KEY), 'k', '4'}, 585 {F(B_F5_KEY), 'k', '5'}, 586 {F(B_F6_KEY), 'k', '6'}, 587 {F(B_F7_KEY), 'k', '7'}, 588 {F(B_F8_KEY), 'k', '8'}, 589 {F(B_F9_KEY), 'k', '9'}, 590 {F(B_F10_KEY), 'k', ';'}, 591 592 {F(B_F11_KEY), 'F', '1'}, 593 {F(B_F12_KEY), 'F', '2'}, 594 // {XK_F13, 'F', '3'}, // would be print screen 595 // sysreq 596 {F(0x0F), 'F', '4'}, // scroll lock 597 {F(0x10), 'F', '5'}, // pause/break 598 // {XK_F16, 'F', '6'}, 599 // {XK_F17, 'F', '7'}, 600 // {XK_F18, 'F', '8'}, 601 // {XK_F19, 'F', '9'}, 602 // {XK_F20, 'F', 'A'}, 603 // {XK_F21, 'F', 'B'}, 604 // {XK_F22, 'F', 'C'}, 605 // {XK_F23, 'F', 'D'}, 606 // {XK_F24, 'F', 'E'}, 607 // {XK_F25, 'F', 'F'}, 608 // {XK_F26, 'F', 'G'}, 609 // {XK_F27, 'F', 'H'}, 610 // {XK_F28, 'F', 'I'}, 611 // {XK_F29, 'F', 'J'}, 612 // {XK_F30, 'F', 'K'}, 613 // {XK_F31, 'F', 'L'}, 614 // {XK_F32, 'F', 'M'}, 615 // {XK_F33, 'F', 'N'}, 616 // {XK_F34, 'F', 'O'}, 617 // {XK_F35, 'F', 'P'}, // keysymdef.h defines up to F35 618 619 // {XK_Help, '%', '1'}, // XK_Help 620 {F(B_PRINT_KEY), '%', '9'}, 621 622 #if 0 623 // Keypad keys: 624 {F(0x48), 'k', 'l'}, // XK_KP_Left 625 {F(0x4A), 'k', 'r'}, // XK_KP_Right 626 {F(0x38), 'k', 'u'}, // XK_KP_Up 627 {F(0x59), 'k', 'd'}, // XK_KP_Down 628 {F(0x64), 'k', 'I'}, // XK_KP_Insert 629 {F(0x65), 'k', 'D'}, // XK_KP_Delete 630 {F(0x37), 'k', 'h'}, // XK_KP_Home 631 {F(0x58), '@', '7'}, // XK_KP_End 632 {F(0x39), 'k', 'P'}, // XK_KP_Prior 633 {F(0x60), 'k', 'N'}, // XK_KP_Next 634 {F(0x49), '&', '8'}, // XK_Undo, keypad 5 635 #endif 636 637 // End of list marker: 638 {0, 0, 0} 639 }; 640 641 #define NUM_SPECIAL_KEYS (sizeof(special_keys)/sizeof(special_keys[0])) 642 643 // ---------------- VimApp ---------------- 644 645 static void 646 docd(BPath &path) 647 { 648 mch_chdir((char *)path.Path()); 649 // Do this to get the side effects of a :cd command 650 do_cmdline_cmd((char_u *)"cd ."); 651 } 652 653 static void 654 drop_callback(void *cookie) 655 { 656 // TODO here we could handle going to a specific position in the dropped 657 // file (see src/gui_mac.c) 658 // Update the screen display 659 update_screen(NOT_VALID); 660 } 661 662 // Really handle dropped files and folders. 663 static void 664 RefsReceived(BMessage *m, bool changedir) 665 { 666 uint32 type; 667 int32 count; 668 669 m->PrintToStream(); 670 switch (m->what) { 671 case B_REFS_RECEIVED: 672 case B_SIMPLE_DATA: 673 m->GetInfo("refs", &type, &count); 674 if (type != B_REF_TYPE) 675 goto bad; 676 break; 677 case B_ARGV_RECEIVED: 678 m->GetInfo("argv", &type, &count); 679 if (type != B_STRING_TYPE) 680 goto bad; 681 if (changedir) { 682 char *dirname; 683 if (m->FindString("cwd", (const char **) &dirname) == B_OK) { 684 chdir(dirname); 685 do_cmdline_cmd((char_u *)"cd ."); 686 } 687 } 688 break; 689 default: 690 bad: 691 /*fprintf(stderr, "bad!\n"); */ 692 delete m; 693 return; 694 } 695 696 #ifdef FEAT_VISUAL 697 reset_VIsual(); 698 #endif 699 700 char_u **fnames; 701 fnames = (char_u **) alloc(count * sizeof(char_u *)); 702 int fname_index = 0; 703 704 switch (m->what) { 705 case B_REFS_RECEIVED: 706 case B_SIMPLE_DATA: 707 // fprintf(stderr, "case B_REFS_RECEIVED\n"); 708 for (int i = 0; i < count; ++i) 709 { 710 entry_ref ref; 711 if (m->FindRef("refs", i, &ref) == B_OK) { 712 BEntry entry(&ref, false); 713 BPath path; 714 entry.GetPath(&path); 715 716 // Change to parent directory? 717 if (changedir) { 718 BPath parentpath; 719 path.GetParent(&parentpath); 720 docd(parentpath); 721 } 722 723 // Is it a directory? If so, cd into it. 724 BDirectory bdir(&ref); 725 if (bdir.InitCheck() == B_OK) { 726 // don't cd if we already did it 727 if (!changedir) 728 docd(path); 729 } else { 730 mch_dirname(IObuff, IOSIZE); 731 char_u *fname = shorten_fname((char_u *)path.Path(), IObuff); 732 if (fname == NULL) 733 fname = (char_u *)path.Path(); 734 fnames[fname_index++] = vim_strsave(fname); 735 // fprintf(stderr, "%s\n", fname); 736 } 737 738 // Only do it for the first file/dir 739 changedir = false; 740 } 741 } 742 break; 743 case B_ARGV_RECEIVED: 744 // fprintf(stderr, "case B_ARGV_RECEIVED\n"); 745 for (int i = 1; i < count; ++i) 746 { 747 char *fname; 748 749 if (m->FindString("argv", i, (const char **) &fname) == B_OK) { 750 fnames[fname_index++] = vim_strsave((char_u *)fname); 751 } 752 } 753 break; 754 default: 755 // fprintf(stderr, "case default\n"); 756 break; 757 } 758 759 delete m; 760 761 // Handle the drop, :edit to get to the file 762 if (fname_index > 0) { 763 handle_drop(fname_index, fnames, FALSE, drop_callback, NULL); 764 765 setcursor(); 766 out_flush(); 767 } else { 768 vim_free(fnames); 769 } 770 } 771 772 VimApp::VimApp(const char *appsig): 773 BApplication(appsig), 774 fFilePanelSem(-1), 775 fFilePanel(NULL) 776 { 777 } 778 779 VimApp::~VimApp() 780 { 781 } 782 783 void 784 VimApp::ReadyToRun() 785 { 786 /* 787 * Apparently signals are inherited by the created thread - 788 * disable the most annoying ones. 789 */ 790 signal(SIGINT, SIG_IGN); 791 signal(SIGQUIT, SIG_IGN); 792 } 793 794 void 795 VimApp::ArgvReceived(int32 arg_argc, char **arg_argv) 796 { 797 if (!IsLaunching()) { 798 /* 799 * This can happen if we are set to Single or Exclusive 800 * Launch. Be nice and open the file(s). 801 */ 802 if (gui.vimWindow) 803 gui.vimWindow->Minimize(false); 804 BMessage *m = CurrentMessage(); 805 DetachCurrentMessage(); 806 SendRefs(m, true); 807 } 808 } 809 810 void 811 VimApp::RefsReceived(BMessage *m) 812 { 813 // Horrible hack!!! XXX XXX XXX 814 // The real problem is that b_start_ffc is set too late for 815 // the initial empty buffer. As a result the window will be 816 // split instead of abandoned. 817 int limit = 15; 818 while (--limit >= 0 && (curbuf == NULL || curbuf->b_start_ffc == 0)) 819 snooze(100000); // 0.1 s 820 if (gui.vimWindow) 821 gui.vimWindow->Minimize(false); 822 DetachCurrentMessage(); 823 SendRefs(m, true); 824 } 825 826 /* 827 * Pass a BMessage on to the main() thread. 828 * Caller must have detached the message. 829 */ 830 void 831 VimApp::SendRefs(BMessage *m, bool changedir) 832 { 833 VimRefsMsg rm; 834 rm.message = m; 835 rm.changedir = changedir; 836 837 write_port(gui.vdcmp, VimMsg::Refs, &rm, sizeof(rm)); 838 // calls ::RefsReceived 839 } 840 841 void 842 VimApp::MessageReceived(BMessage *m) 843 { 844 switch (m->what) { 845 case 'save': 846 { 847 entry_ref refDirectory; 848 m->FindRef("directory", &refDirectory); 849 fBrowsedPath.SetTo(&refDirectory); 850 BString strName; 851 m->FindString("name", &strName); 852 fBrowsedPath.Append(strName.String()); 853 } 854 break; 855 case 'open': 856 { 857 entry_ref ref; 858 m->FindRef("refs", &ref); 859 fBrowsedPath.SetTo(&ref); 860 } 861 break; 862 case B_CANCEL: 863 { 864 BFilePanel *panel; 865 m->FindPointer("source", (void**)&panel); 866 if (fFilePanelSem != -1 && panel == fFilePanel) 867 { 868 delete_sem(fFilePanelSem); 869 fFilePanelSem = -1; 870 } 871 872 } 873 break; 874 default: 875 Inherited::MessageReceived(m); 876 break; 877 } 878 } 879 880 bool 881 VimApp::QuitRequested() 882 { 883 (void)Inherited::QuitRequested(); 884 return false; 885 } 886 887 // ---------------- VimWindow ---------------- 888 889 VimWindow::VimWindow(): 890 BWindow(BRect(40, 40, 150, 150), 891 "Vim", 892 B_TITLED_WINDOW, 893 0, 894 B_CURRENT_WORKSPACE) 895 896 { 897 init(); 898 } 899 900 VimWindow::~VimWindow() 901 { 902 if (formView) { 903 RemoveChild(formView); 904 delete formView; 905 } 906 gui.vimWindow = NULL; 907 } 908 909 void 910 VimWindow::init() 911 { 912 // Attach the VimFormView 913 formView = new VimFormView(Bounds()); 914 if (formView != NULL) { 915 AddChild(formView); 916 } 917 } 918 919 #if 0 // disabled in zeta patch 920 void 921 VimWindow::DispatchMessage(BMessage *m, BHandler *h) 922 { 923 /* 924 * Route B_MOUSE_UP messages to MouseUp(), in 925 * a manner that should be compatible with the 926 * intended future system behaviour. 927 */ 928 switch (m->what) { 929 case B_MOUSE_UP: 930 // if (!h) h = PreferredHandler(); 931 // gcc isn't happy without this extra set of braces, complains about 932 // jump to case label crosses init of 'class BView * v' 933 // [email protected] jul 99 934 { 935 BView *v = dynamic_cast<BView *>(h); 936 if (v) { 937 // m->PrintToStream(); 938 BPoint where; 939 m->FindPoint("where", &where); 940 v->MouseUp(where); 941 } else { 942 Inherited::DispatchMessage(m, h); 943 } 944 } 945 break; 946 default: 947 Inherited::DispatchMessage(m, h); 948 } 949 } 950 #endif 951 952 void 953 VimWindow::WindowActivated(bool active) 954 { 955 Inherited::WindowActivated(active); 956 // the textArea gets the keyboard action 957 if (active && gui.vimTextArea) 958 gui.vimTextArea->MakeFocus(true); 959 960 struct VimFocusMsg fm; 961 fm.active = active; 962 963 write_port(gui.vdcmp, VimMsg::Focus, &fm, sizeof(fm)); 964 } 965 966 bool 967 VimWindow::QuitRequested() 968 { 969 struct VimKeyMsg km; 970 km.length = 5; 971 memcpy((char *)km.chars, "\033:qa\r", km.length); 972 km.csi_escape = false; 973 write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km)); 974 return false; 975 } 976 977 // ---------------- VimFormView ---------------- 978 979 VimFormView::VimFormView(BRect frame): 980 BView(frame, "VimFormView", B_FOLLOW_ALL_SIDES, 981 B_WILL_DRAW | B_FRAME_EVENTS), 982 menuBar(NULL), 983 #ifdef FEAT_TOOLBAR 984 toolBar(NULL), 985 #endif 986 #ifdef FEAT_GUI_TABLINE 987 // showingTabLine(false), 988 tabLine(NULL), 989 #endif 990 textArea(NULL) 991 { 992 init(frame); 993 } 994 995 VimFormView::~VimFormView() 996 { 997 if (menuBar) { 998 RemoveChild(menuBar); 999 #ifdef never 1000 // deleting the menuBar leads to SEGV on exit 1001 // [email protected] Jul 99 1002 delete menuBar; 1003 #endif 1004 } 1005 1006 #ifdef FEAT_TOOLBAR 1007 delete toolBar; 1008 #endif 1009 1010 #ifdef FEAT_GUI_TABLINE 1011 delete tabLine; 1012 #endif 1013 1014 if (textArea) { 1015 RemoveChild(textArea); 1016 delete textArea; 1017 } 1018 gui.vimForm = NULL; 1019 } 1020 1021 void 1022 VimFormView::init(BRect frame) 1023 { 1024 menuBar = new BMenuBar(BRect(0,0,-MENUBAR_MARGIN,-MENUBAR_MARGIN), 1025 "VimMenuBar"); 1026 1027 AddChild(menuBar); 1028 1029 #ifdef FEAT_TOOLBAR 1030 toolBar = new VimToolbar(BRect(0,0,0,0), "VimToolBar"); 1031 toolBar->PrepareButtonBitmaps(); 1032 AddChild(toolBar); 1033 #endif 1034 1035 #ifdef FEAT_GUI_TABLINE 1036 tabLine = new VimTabLine(BRect(0,0,0,0)); 1037 // tabLine->PrepareButtonBitmaps(); 1038 AddChild(tabLine); 1039 #endif 1040 1041 BRect remaining = frame; 1042 textArea = new VimTextAreaView(remaining); 1043 AddChild(textArea); 1044 // The textArea will be resized later when menus are added 1045 1046 gui.vimForm = this; 1047 } 1048 1049 #ifdef FEAT_TOOLBAR 1050 float 1051 VimFormView::ToolbarHeight() const 1052 { 1053 return toolBar ? toolBar->ToolbarHeight() : 0.; 1054 } 1055 #endif 1056 1057 #ifdef FEAT_GUI_TABLINE 1058 float 1059 VimFormView::TablineHeight() const 1060 { 1061 return (tabLine && IsShowingTabLine()) ? tabLine->TablineHeight() : 0.; 1062 } 1063 #endif 1064 1065 void 1066 VimFormView::AllAttached() 1067 { 1068 /* 1069 * Apparently signals are inherited by the created thread - 1070 * disable the most annoying ones. 1071 */ 1072 signal(SIGINT, SIG_IGN); 1073 signal(SIGQUIT, SIG_IGN); 1074 1075 if (menuBar && textArea) { 1076 /* 1077 * Resize the textArea to fill the space left over by the menu. 1078 * This is somewhat futile since it will be done again once 1079 * menus are added to the menu bar. 1080 */ 1081 BRect remaining = Bounds(); 1082 1083 #ifdef FEAT_MENU 1084 remaining.top += MenuHeight(); 1085 menuBar->ResizeTo(remaining.right, remaining.top); 1086 gui.menu_height = (int) MenuHeight(); 1087 #endif 1088 1089 #ifdef FEAT_TOOLBAR 1090 toolBar->MoveTo(remaining.left, remaining.top); 1091 toolBar->ResizeTo(remaining.right, ToolbarHeight()); 1092 remaining.top += ToolbarHeight(); 1093 gui.toolbar_height = ToolbarHeight(); 1094 #endif 1095 1096 #ifdef FEAT_GUI_TABLINE 1097 tabLine->MoveTo(remaining.left, remaining.top); 1098 tabLine->ResizeTo(remaining.right + 1, TablineHeight()); 1099 remaining.top += TablineHeight(); 1100 gui.tabline_height = TablineHeight(); 1101 #endif 1102 1103 textArea->ResizeTo(remaining.Width(), remaining.Height()); 1104 textArea->MoveTo(remaining.left, remaining.top); 1105 } 1106 1107 1108 Inherited::AllAttached(); 1109 } 1110 1111 void 1112 VimFormView::FrameResized(float new_width, float new_height) 1113 { 1114 struct VimResizeMsg sm; 1115 int adjust_h, adjust_w; 1116 1117 new_width += 1; // adjust from width to number of pixels occupied 1118 new_height += 1; 1119 1120 sm.width = (int) new_width; 1121 sm.height = (int) new_height; 1122 adjust_w = ((int)new_width - gui_get_base_width()) % gui.char_width; 1123 adjust_h = ((int)new_height - gui_get_base_height()) % gui.char_height; 1124 1125 if (adjust_w > 0 || adjust_h > 0) { 1126 sm.width -= adjust_w; 1127 sm.height -= adjust_h; 1128 } 1129 1130 write_port(gui.vdcmp, VimMsg::Resize, &sm, sizeof(sm)); 1131 // calls gui_resize_shell(new_width, new_height); 1132 1133 return; 1134 1135 /* 1136 * The area below the vertical scrollbar is erased to the colour 1137 * set with SetViewColor() automatically, because we had set 1138 * B_WILL_DRAW. Resizing the window tight around the vertical 1139 * scroll bar also helps to avoid debris. 1140 */ 1141 } 1142 1143 // ---------------- VimTextAreaView ---------------- 1144 1145 VimTextAreaView::VimTextAreaView(BRect frame): 1146 BView(frame, "VimTextAreaView", B_FOLLOW_ALL_SIDES, 1147 #ifdef FEAT_MBYTE_IME 1148 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_INPUT_METHOD_AWARE 1149 #else 1150 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE 1151 #endif 1152 ), 1153 mouseDragEventCount(0) 1154 { 1155 #ifdef FEAT_MBYTE_IME 1156 IMData.messenger = NULL; 1157 IMData.message = NULL; 1158 #endif 1159 init(frame); 1160 } 1161 1162 VimTextAreaView::~VimTextAreaView() 1163 { 1164 gui.vimTextArea = NULL; 1165 } 1166 1167 void 1168 VimTextAreaView::init(BRect frame) 1169 { 1170 // set up global var for fast access 1171 gui.vimTextArea = this; 1172 1173 /* 1174 * Tell the app server not to erase the view: we will 1175 * fill it in completely by ourselves. 1176 * (Does this really work? Even if not, it won't harm either.) 1177 */ 1178 SetViewColor(B_TRANSPARENT_32_BIT); 1179 #define PEN_WIDTH 1 1180 SetPenSize(PEN_WIDTH); 1181 #define W_WIDTH(curwin) 0 1182 } 1183 1184 void 1185 VimTextAreaView::Draw(BRect updateRect) 1186 { 1187 /* 1188 * XXX Other ports call here: 1189 * out_flush(); * make sure all output has been processed * 1190 * but we can't do that, since it involves too much information 1191 * that is owned by other threads... 1192 */ 1193 1194 /* 1195 * No need to use gui.vimWindow->Lock(): we are locked already. 1196 * However, it would not hurt. 1197 */ 1198 rgb_color rgb = GUI_TO_RGB(gui.back_pixel); 1199 SetLowColor(rgb); 1200 FillRect(updateRect, B_SOLID_LOW); 1201 gui_redraw((int) updateRect.left, (int) updateRect.top, 1202 (int) (updateRect.Width() + PEN_WIDTH), (int) (updateRect.Height() + PEN_WIDTH)); 1203 1204 // Clear the border areas if needed 1205 SetLowColor(rgb); 1206 1207 if (updateRect.left < FILL_X(0)) // left border 1208 FillRect(BRect(updateRect.left, updateRect.top, 1209 FILL_X(0)-PEN_WIDTH, updateRect.bottom), B_SOLID_LOW); 1210 if (updateRect.top < FILL_Y(0)) // top border 1211 FillRect(BRect(updateRect.left, updateRect.top, 1212 updateRect.right, FILL_Y(0)-PEN_WIDTH), B_SOLID_LOW); 1213 if (updateRect.right >= FILL_X(Columns)) // right border 1214 FillRect(BRect(FILL_X((int)Columns), updateRect.top, 1215 updateRect.right, updateRect.bottom), B_SOLID_LOW); 1216 if (updateRect.bottom >= FILL_Y(Rows)) // bottom border 1217 FillRect(BRect(updateRect.left, FILL_Y((int)Rows), 1218 updateRect.right, updateRect.bottom), B_SOLID_LOW); 1219 1220 #ifdef FEAT_MBYTE_IME 1221 DrawIMString(); 1222 #endif 1223 } 1224 1225 void 1226 VimTextAreaView::KeyDown(const char *bytes, int32 numBytes) 1227 { 1228 struct VimKeyMsg km; 1229 char_u *dest = km.chars; 1230 1231 bool canHaveVimModifiers = false; 1232 1233 BMessage *msg = Window()->CurrentMessage(); 1234 assert(msg); 1235 // msg->PrintToStream(); 1236 1237 /* 1238 * Convert special keys to Vim codes. 1239 * I think it is better to do it in the window thread 1240 * so we use at least a little bit of the potential 1241 * of our 2 CPUs. Besides, due to the fantastic mapping 1242 * of special keys to UTF-8, we have quite some work to 1243 * do... 1244 * TODO: I'm not quite happy with detection of special 1245 * keys. Perhaps I should use scan codes after all... 1246 */ 1247 if (numBytes > 1) { 1248 // This cannot be a special key 1249 if (numBytes > KEY_MSG_BUFSIZ) 1250 numBytes = KEY_MSG_BUFSIZ; // should never happen... ??? 1251 km.length = numBytes; 1252 memcpy((char *)dest, bytes, numBytes); 1253 km.csi_escape = true; 1254 } else { 1255 int32 scancode = 0; 1256 msg->FindInt32("key", &scancode); 1257 1258 int32 beModifiers = 0; 1259 msg->FindInt32("modifiers", &beModifiers); 1260 1261 char_u string[3]; 1262 int len = 0; 1263 km.length = 0; 1264 1265 /* 1266 * For normal, printable ASCII characters, don't look them up 1267 * to check if they might be a special key. They aren't. 1268 */ 1269 assert(B_BACKSPACE <= 0x20); 1270 assert(B_DELETE == 0x7F); 1271 if (((char_u)bytes[0] <= 0x20 || (char_u)bytes[0] == 0x7F) && 1272 numBytes == 1) { 1273 /* 1274 * Due to the great nature of Be's mapping of special keys, 1275 * viz. into the range of the control characters, 1276 * we can only be sure it is *really* a special key if 1277 * if it is special without using ctrl. So, only if ctrl is 1278 * used, we need to check it unmodified. 1279 */ 1280 if (beModifiers & B_CONTROL_KEY) { 1281 int index = keyMap->normal_map[scancode]; 1282 int newNumBytes = keyMapChars[index]; 1283 char_u *newBytes = (char_u *)&keyMapChars[index + 1]; 1284 1285 /* 1286 * Check if still special without the control key. 1287 * This is needed for BACKSPACE: that key does produce 1288 * different values with modifiers (DEL). 1289 * Otherwise we could simply have checked for equality. 1290 */ 1291 if (newNumBytes != 1 || (*newBytes > 0x20 && 1292 *newBytes != 0x7F )) { 1293 goto notspecial; 1294 } 1295 bytes = (char *)newBytes; 1296 } 1297 canHaveVimModifiers = true; 1298 1299 uint16 beoskey; 1300 int first, last; 1301 1302 /* 1303 * If numBytes == 0 that probably always indicates a special key. 1304 * (does not happen yet) 1305 */ 1306 if (numBytes == 0 || bytes[0] == B_FUNCTION_KEY) { 1307 beoskey = F(scancode); 1308 first = FIRST_FUNCTION_KEY; 1309 last = NUM_SPECIAL_KEYS; 1310 } else if (*bytes == '\n' && scancode == 0x47) { 1311 // remap the (non-keypad) ENTER key from \n to \r. 1312 string[0] = '\r'; 1313 len = 1; 1314 first = last = 0; 1315 } else { 1316 beoskey = K(bytes[0]); 1317 first = 0; 1318 last = FIRST_FUNCTION_KEY; 1319 } 1320 1321 for (int i = first; i < last; i++) { 1322 if (special_keys[i].BeKeys == beoskey) { 1323 string[0] = CSI; 1324 string[1] = special_keys[i].vim_code0; 1325 string[2] = special_keys[i].vim_code1; 1326 len = 3; 1327 } 1328 } 1329 } 1330 notspecial: 1331 if (len == 0) { 1332 string[0] = bytes[0]; 1333 len = 1; 1334 } 1335 1336 // Special keys (and a few others) may have modifiers 1337 #if 0 1338 if (len == 3 || 1339 bytes[0] == B_SPACE || bytes[0] == B_TAB || 1340 bytes[0] == B_RETURN || bytes[0] == '\r' || 1341 bytes[0] == B_ESCAPE) 1342 #else 1343 if (canHaveVimModifiers) 1344 #endif 1345 { 1346 int modifiers; 1347 modifiers = 0; 1348 if (beModifiers & B_SHIFT_KEY) 1349 modifiers |= MOD_MASK_SHIFT; 1350 if (beModifiers & B_CONTROL_KEY) 1351 modifiers |= MOD_MASK_CTRL; 1352 if (beModifiers & B_OPTION_KEY) 1353 modifiers |= MOD_MASK_ALT; 1354 1355 /* 1356 * For some keys a shift modifier is translated into another key 1357 * code. Do we need to handle the case where len != 1 and 1358 * string[0] != CSI? (Not for BeOS, since len == 3 implies 1359 * string[0] == CSI...) 1360 */ 1361 int key; 1362 if (string[0] == CSI && len == 3) 1363 key = TO_SPECIAL(string[1], string[2]); 1364 else 1365 key = string[0]; 1366 key = simplify_key(key, &modifiers); 1367 if (IS_SPECIAL(key)) 1368 { 1369 string[0] = CSI; 1370 string[1] = K_SECOND(key); 1371 string[2] = K_THIRD(key); 1372 len = 3; 1373 } 1374 else 1375 { 1376 string[0] = key; 1377 len = 1; 1378 } 1379 1380 if (modifiers) 1381 { 1382 *dest++ = CSI; 1383 *dest++ = KS_MODIFIER; 1384 *dest++ = modifiers; 1385 km.length = 3; 1386 } 1387 } 1388 memcpy((char *)dest, string, len); 1389 km.length += len; 1390 km.csi_escape = false; 1391 } 1392 1393 write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km)); 1394 1395 /* 1396 * blank out the pointer if necessary 1397 */ 1398 if (p_mh && !gui.pointer_hidden) 1399 { 1400 guiBlankMouse(true); 1401 gui.pointer_hidden = TRUE; 1402 } 1403 } 1404 void 1405 VimTextAreaView::guiSendMouseEvent( 1406 int button, 1407 int x, 1408 int y, 1409 int repeated_click, 1410 int_u modifiers) 1411 { 1412 VimMouseMsg mm; 1413 1414 mm.button = button; 1415 mm.x = x; 1416 mm.y = y; 1417 mm.repeated_click = repeated_click; 1418 mm.modifiers = modifiers; 1419 1420 write_port(gui.vdcmp, VimMsg::Mouse, &mm, sizeof(mm)); 1421 // calls gui_send_mouse_event() 1422 1423 /* 1424 * if our pointer is currently hidden, then we should show it. 1425 */ 1426 if (gui.pointer_hidden) 1427 { 1428 guiBlankMouse(false); 1429 gui.pointer_hidden = FALSE; 1430 } 1431 } 1432 1433 void 1434 VimTextAreaView::guiMouseMoved( 1435 int x, 1436 int y) 1437 { 1438 VimMouseMovedMsg mm; 1439 1440 mm.x = x; 1441 mm.y = y; 1442 1443 write_port(gui.vdcmp, VimMsg::MouseMoved, &mm, sizeof(mm)); 1444 1445 if (gui.pointer_hidden) 1446 { 1447 guiBlankMouse(false); 1448 gui.pointer_hidden = FALSE; 1449 } 1450 } 1451 1452 void 1453 VimTextAreaView::guiBlankMouse(bool should_hide) 1454 { 1455 if (should_hide) { 1456 // gui.vimApp->HideCursor(); 1457 gui.vimApp->ObscureCursor(); 1458 /* 1459 * ObscureCursor() would even be easier, but then 1460 * Vim's idea of mouse visibility does not necessarily 1461 * correspond to reality. 1462 */ 1463 } else { 1464 // gui.vimApp->ShowCursor(); 1465 } 1466 } 1467 1468 int_u 1469 VimTextAreaView::mouseModifiersToVim(int32 beModifiers) 1470 { 1471 int_u vim_modifiers = 0x0; 1472 1473 if (beModifiers & B_SHIFT_KEY) 1474 vim_modifiers |= MOUSE_SHIFT; 1475 if (beModifiers & B_CONTROL_KEY) 1476 vim_modifiers |= MOUSE_CTRL; 1477 if (beModifiers & B_OPTION_KEY) // Alt or Meta key 1478 vim_modifiers |= MOUSE_ALT; 1479 1480 return vim_modifiers; 1481 } 1482 1483 void 1484 VimTextAreaView::MouseDown(BPoint point) 1485 { 1486 BMessage *m = Window()->CurrentMessage(); 1487 assert(m); 1488 1489 int32 buttons = 0; 1490 m->FindInt32("buttons", &buttons); 1491 1492 int vimButton; 1493 1494 if (buttons & B_PRIMARY_MOUSE_BUTTON) 1495 vimButton = MOUSE_LEFT; 1496 else if (buttons & B_SECONDARY_MOUSE_BUTTON) 1497 vimButton = MOUSE_RIGHT; 1498 else if (buttons & B_TERTIARY_MOUSE_BUTTON) 1499 vimButton = MOUSE_MIDDLE; 1500 else 1501 return; // Unknown button 1502 1503 vimMouseButton = 1; // don't care which one 1504 1505 // Handle multiple clicks 1506 int32 clicks = 0; 1507 m->FindInt32("clicks", &clicks); 1508 1509 int32 modifiers = 0; 1510 m->FindInt32("modifiers", &modifiers); 1511 1512 vimMouseModifiers = mouseModifiersToVim(modifiers); 1513 1514 guiSendMouseEvent(vimButton, point.x, point.y, 1515 clicks > 1 /* = repeated_click*/, vimMouseModifiers); 1516 } 1517 1518 void 1519 VimTextAreaView::MouseUp(BPoint point) 1520 { 1521 vimMouseButton = 0; 1522 1523 BMessage *m = Window()->CurrentMessage(); 1524 assert(m); 1525 // m->PrintToStream(); 1526 1527 int32 modifiers = 0; 1528 m->FindInt32("modifiers", &modifiers); 1529 1530 vimMouseModifiers = mouseModifiersToVim(modifiers); 1531 1532 guiSendMouseEvent(MOUSE_RELEASE, point.x, point.y, 1533 0 /* = repeated_click*/, vimMouseModifiers); 1534 1535 Inherited::MouseUp(point); 1536 } 1537 1538 void 1539 VimTextAreaView::MouseMoved(BPoint point, uint32 transit, const BMessage *message) 1540 { 1541 /* 1542 * if our pointer is currently hidden, then we should show it. 1543 */ 1544 if (gui.pointer_hidden) 1545 { 1546 guiBlankMouse(false); 1547 gui.pointer_hidden = FALSE; 1548 } 1549 1550 if (!vimMouseButton) { // could also check m->"buttons" 1551 guiMouseMoved(point.x, point.y); 1552 return; 1553 } 1554 1555 atomic_add(&mouseDragEventCount, 1); 1556 1557 // Don't care much about "transit" 1558 guiSendMouseEvent(MOUSE_DRAG, point.x, point.y, 0, vimMouseModifiers); 1559 } 1560 1561 void 1562 VimTextAreaView::MessageReceived(BMessage *m) 1563 { 1564 switch (m->what) { 1565 case 'menu': 1566 { 1567 VimMenuMsg mm; 1568 mm.guiMenu = NULL; // in case no pointer in msg 1569 m->FindPointer("VimMenu", (void **)&mm.guiMenu); 1570 write_port(gui.vdcmp, VimMsg::Menu, &mm, sizeof(mm)); 1571 } 1572 break; 1573 case B_MOUSE_WHEEL_CHANGED: 1574 { 1575 VimScrollBar* scb = curwin->w_scrollbars[1].id; 1576 float small=0, big=0, dy=0; 1577 m->FindFloat("be:wheel_delta_y", &dy); 1578 scb->GetSteps(&small, &big); 1579 scb->SetValue(scb->Value()+small*dy*3); 1580 scb->ValueChanged(scb->Value()); 1581 #if 0 1582 scb = curwin->w_scrollbars[0].id; 1583 scb->GetSteps(&small, &big); 1584 scb->SetValue(scb->Value()+small*dy); 1585 scb->ValueChanged(scb->Value()); 1586 #endif 1587 } 1588 break; 1589 #ifdef FEAT_MBYTE_IME 1590 case B_INPUT_METHOD_EVENT: 1591 { 1592 int32 opcode; 1593 m->FindInt32("be:opcode", &opcode); 1594 switch(opcode) 1595 { 1596 case B_INPUT_METHOD_STARTED: 1597 if (!IMData.messenger) delete IMData.messenger; 1598 IMData.messenger = new BMessenger(); 1599 m->FindMessenger("be:reply_to", IMData.messenger); 1600 break; 1601 case B_INPUT_METHOD_CHANGED: 1602 { 1603 BString str; 1604 bool confirmed; 1605 if (IMData.message) *(IMData.message) = *m; 1606 else IMData.message = new BMessage(*m); 1607 DrawIMString(); 1608 m->FindBool("be:confirmed", &confirmed); 1609 if (confirmed) 1610 { 1611 m->FindString("be:string", &str); 1612 char_u *chars = (char_u*)str.String(); 1613 struct VimKeyMsg km; 1614 km.csi_escape = true; 1615 int clen; 1616 int i = 0; 1617 while (i < str.Length()) 1618 { 1619 clen = utf_ptr2len(chars+i); 1620 memcpy(km.chars, chars+i, clen); 1621 km.length = clen; 1622 write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km)); 1623 i += clen; 1624 } 1625 } 1626 } 1627 break; 1628 case B_INPUT_METHOD_LOCATION_REQUEST: 1629 { 1630 BMessage msg(B_INPUT_METHOD_EVENT); 1631 msg.AddInt32("be:opcode", B_INPUT_METHOD_LOCATION_REQUEST); 1632 msg.AddPoint("be:location_reply", IMData.location); 1633 msg.AddFloat("be:height_reply", FILL_Y(1)); 1634 IMData.messenger->SendMessage(&msg); 1635 } 1636 break; 1637 case B_INPUT_METHOD_STOPPED: 1638 delete IMData.messenger; 1639 delete IMData.message; 1640 IMData.messenger = NULL; 1641 IMData.message = NULL; 1642 break; 1643 } 1644 } 1645 // TODO: sz: break here??? 1646 #endif 1647 default: 1648 if (m->WasDropped()) { 1649 BWindow *w = Window(); 1650 w->DetachCurrentMessage(); 1651 w->Minimize(false); 1652 VimApp::SendRefs(m, (modifiers() & B_SHIFT_KEY) != 0); 1653 } else { 1654 Inherited::MessageReceived(m); 1655 } 1656 break; 1657 } 1658 } 1659 1660 int 1661 VimTextAreaView::mchInitFont(char_u *name) 1662 { 1663 VimFont *newFont = (VimFont *)gui_mch_get_font(name, 1); 1664 if (newFont != NOFONT) { 1665 gui.norm_font = (GuiFont)newFont; 1666 gui_mch_set_font((GuiFont)newFont); 1667 if (name && STRCMP(name, "*") != 0) 1668 hl_set_font_name(name); 1669 1670 SetDrawingMode(B_OP_COPY); 1671 1672 /* 1673 * Try to load other fonts for bold, italic, and bold-italic. 1674 * We should also try to work out what font to use for these when they are 1675 * not specified by X resources, but we don't yet. 1676 */ 1677 return OK; 1678 } 1679 return FAIL; 1680 } 1681 1682 void 1683 VimTextAreaView::mchDrawString(int row, int col, char_u *s, int len, int flags) 1684 { 1685 /* 1686 * First we must erase the area, because DrawString won't do 1687 * that for us. XXX Most of the time this is a waste of effort 1688 * since the bachground has been erased already... DRAW_TRANSP 1689 * should be set when appropriate!!! 1690 * (Rectangles include the bottom and right edge) 1691 */ 1692 if (!(flags & DRAW_TRANSP)) { 1693 int cells; 1694 cells = 0; 1695 for (int i=0; i<len; i++) { 1696 int cn = utf_ptr2cells((char_u *)(s+i)); 1697 if (cn<4) cells += cn; 1698 } 1699 1700 BRect r(FILL_X(col), FILL_Y(row), 1701 FILL_X(col + cells) - PEN_WIDTH, FILL_Y(row + 1) - PEN_WIDTH); 1702 FillRect(r, B_SOLID_LOW); 1703 } 1704 1705 BFont font; 1706 this->GetFont(&font); 1707 if (!font.IsFixed()) 1708 { 1709 char* p = (char*)s; 1710 int32 clen, lastpos = 0; 1711 BPoint where; 1712 int cells; 1713 while ((p - (char*)s) < len) { 1714 clen = utf_ptr2len((u_char*)p); 1715 where.Set(TEXT_X(col+lastpos), TEXT_Y(row)); 1716 DrawString(p, clen, where); 1717 if (flags & DRAW_BOLD) { 1718 where.x += 1.0; 1719 SetDrawingMode(B_OP_BLEND); 1720 DrawString(p, clen, where); 1721 SetDrawingMode(B_OP_COPY); 1722 } 1723 cells = utf_ptr2cells((char_u *)p); 1724 if (cells<4) lastpos += cells; 1725 else lastpos++; 1726 p += clen; 1727 } 1728 } 1729 else 1730 { 1731 BPoint where(TEXT_X(col), TEXT_Y(row)); 1732 DrawString((char*)s, len, where); 1733 if (flags & DRAW_BOLD) { 1734 where.x += 1.0; 1735 SetDrawingMode(B_OP_BLEND); 1736 DrawString((char*)s, len, where); 1737 SetDrawingMode(B_OP_COPY); 1738 } 1739 } 1740 1741 if (flags & DRAW_UNDERL) { 1742 int cells; 1743 cells = 0; 1744 for (int i=0; i<len; i++) { 1745 int cn = utf_ptr2cells((char_u *)(s+i)); 1746 if (cn<4) cells += cn; 1747 } 1748 1749 BPoint start(FILL_X(col), FILL_Y(row + 1) - PEN_WIDTH); 1750 BPoint end(FILL_X(col + cells) - PEN_WIDTH, start.y); 1751 1752 StrokeLine(start, end); 1753 } 1754 } 1755 1756 void 1757 VimTextAreaView::mchClearBlock( 1758 int row1, 1759 int col1, 1760 int row2, 1761 int col2) 1762 { 1763 BRect r(FILL_X(col1), FILL_Y(row1), 1764 FILL_X(col2 + 1) - PEN_WIDTH, FILL_Y(row2 + 1) - PEN_WIDTH); 1765 gui_mch_set_bg_color(gui.back_pixel); 1766 FillRect(r, B_SOLID_LOW); 1767 } 1768 1769 void 1770 VimTextAreaView::mchClearAll() 1771 { 1772 gui_mch_set_bg_color(gui.back_pixel); 1773 FillRect(Bounds(), B_SOLID_LOW); 1774 } 1775 1776 /* 1777 * mchDeleteLines() Lock()s the window by itself. 1778 */ 1779 void 1780 VimTextAreaView::mchDeleteLines(int row, int num_lines) 1781 { 1782 BRect source, dest; 1783 source.left = FILL_X(gui.scroll_region_left); 1784 source.top = FILL_Y(row + num_lines); 1785 source.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH; 1786 source.bottom = FILL_Y(gui.scroll_region_bot + 1) - PEN_WIDTH; 1787 1788 dest.left = FILL_X(gui.scroll_region_left); 1789 dest.top = FILL_Y(row); 1790 dest.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH; 1791 dest.bottom = FILL_Y(gui.scroll_region_bot - num_lines + 1) - PEN_WIDTH; 1792 1793 if (gui.vimWindow->Lock()) { 1794 // Clear one column more for when bold has spilled over 1795 CopyBits(source, dest); 1796 gui_clear_block(gui.scroll_region_bot - num_lines + 1, 1797 gui.scroll_region_left, 1798 gui.scroll_region_bot, gui.scroll_region_right); 1799 1800 1801 gui.vimWindow->Unlock(); 1802 /* 1803 * The Draw() callback will be called now if some of the source 1804 * bits were not in the visible region. 1805 */ 1806 } 1807 // gui_x11_check_copy_area(); 1808 // } 1809 } 1810 1811 /* 1812 * mchInsertLines() Lock()s the window by itself. 1813 */ 1814 void 1815 VimTextAreaView::mchInsertLines(int row, int num_lines) 1816 { 1817 BRect source, dest; 1818 1819 // XXX Attempt at a hack: 1820 gui.vimWindow->UpdateIfNeeded(); 1821 source.left = FILL_X(gui.scroll_region_left); 1822 source.top = FILL_Y(row); 1823 source.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH; 1824 source.bottom = FILL_Y(gui.scroll_region_bot - num_lines + 1) - PEN_WIDTH; 1825 1826 dest.left = FILL_X(gui.scroll_region_left); 1827 dest.top = FILL_Y(row + num_lines); 1828 dest.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH; 1829 dest.bottom = FILL_Y(gui.scroll_region_bot + 1) - PEN_WIDTH; 1830 1831 if (gui.vimWindow->Lock()) { 1832 // Clear one column more for when bold has spilled over 1833 CopyBits(source, dest); 1834 gui_clear_block(row, gui.scroll_region_left, 1835 row + num_lines - 1, gui.scroll_region_right); 1836 1837 gui.vimWindow->Unlock(); 1838 /* 1839 * The Draw() callback will be called now if some of the source 1840 * bits were not in the visible region. 1841 * However, if we scroll too fast it can't keep up and the 1842 * update region gets messed up. This seems to be because copying 1843 * un-Draw()n bits does not generate Draw() calls for the copy... 1844 * I moved the hack to before the CopyBits() to reduce the 1845 * amount of additional waiting needed. 1846 */ 1847 1848 // gui_x11_check_copy_area(); 1849 1850 } 1851 } 1852 1853 #ifdef FEAT_MBYTE_IME 1854 /* 1855 * DrawIMString draws string with IMData.message. 1856 */ 1857 void VimTextAreaView::DrawIMString(void) 1858 { 1859 static const rgb_color r_highlight = {255, 152, 152, 255}, 1860 b_highlight = {152, 203, 255, 255}; 1861 BString str; 1862 const char* s; 1863 int len; 1864 BMessage* msg = IMData.message; 1865 if (!msg) 1866 return; 1867 gui_redraw_block(IMData.row, 0, 1868 IMData.row + IMData.count, W_WIDTH(curwin), GUI_MON_NOCLEAR); 1869 bool confirmed = false; 1870 msg->FindBool("be:confirmed", &confirmed); 1871 if (confirmed) 1872 return; 1873 rgb_color hcolor = HighColor(), lcolor = LowColor(); 1874 msg->FindString("be:string", &str); 1875 s = str.String(); 1876 len = str.Length(); 1877 SetHighColor(0, 0, 0); 1878 IMData.row = gui.row; 1879 IMData.col = gui.col; 1880 int32 sel_start = 0, sel_end = 0; 1881 msg->FindInt32("be:selection", 0, &sel_start); 1882 msg->FindInt32("be:selection", 1, &sel_end); 1883 int clen, cn; 1884 BPoint pos(IMData.col, 0); 1885 BRect r; 1886 BPoint where; 1887 IMData.location = ConvertToScreen( 1888 BPoint(FILL_X(pos.x), FILL_Y(IMData.row + pos.y))); 1889 for (int i=0; i<len; i+=clen) 1890 { 1891 cn = utf_ptr2cells((char_u *)(s+i)); 1892 clen = utf_ptr2len((char_u *)(s+i)); 1893 if (pos.x + cn > W_WIDTH(curwin)) 1894 { 1895 pos.y++; 1896 pos.x = 0; 1897 } 1898 if (sel_start<=i && i<sel_end) 1899 { 1900 SetLowColor(r_highlight); 1901 IMData.location = ConvertToScreen( 1902 BPoint(FILL_X(pos.x), FILL_Y(IMData.row + pos.y))); 1903 } 1904 else 1905 { 1906 SetLowColor(b_highlight); 1907 } 1908 r.Set(FILL_X(pos.x), FILL_Y(IMData.row + pos.y), 1909 FILL_X(pos.x + cn) - PEN_WIDTH, 1910 FILL_Y(IMData.row + pos.y + 1) - PEN_WIDTH); 1911 FillRect(r, B_SOLID_LOW); 1912 where.Set(TEXT_X(pos.x), TEXT_Y(IMData.row + pos.y)); 1913 DrawString((s+i), clen, where); 1914 pos.x += cn; 1915 } 1916 IMData.count = (int)pos.y; 1917 1918 SetHighColor(hcolor); 1919 SetLowColor(lcolor); 1920 } 1921 #endif 1922 // ---------------- VimScrollBar ---------------- 1923 1924 /* 1925 * BUG: XXX 1926 * It seems that BScrollBar determine their direction not from 1927 * "posture" but from if they are "tall" or "wide" in shape... 1928 * 1929 * Also, place them out of sight, because Vim enables them before 1930 * they are positioned. 1931 */ 1932 VimScrollBar::VimScrollBar(scrollbar_T *g, orientation posture): 1933 BScrollBar(posture == B_HORIZONTAL ? BRect(-100,-100,-10,-90) : 1934 BRect(-100,-100,-90,-10), 1935 "vim scrollbar", (BView *)NULL, 1936 0.0, 10.0, posture), 1937 ignoreValue(-1), 1938 scrollEventCount(0) 1939 { 1940 gsb = g; 1941 SetResizingMode(B_FOLLOW_NONE); 1942 } 1943 1944 VimScrollBar::~VimScrollBar() 1945 { 1946 } 1947 1948 void 1949 VimScrollBar::ValueChanged(float newValue) 1950 { 1951 if (ignoreValue >= 0.0 && newValue == ignoreValue) { 1952 ignoreValue = -1; 1953 return; 1954 } 1955 ignoreValue = -1; 1956 /* 1957 * We want to throttle the amount of scroll messages generated. 1958 * Normally I presume you won't get a new message before we've 1959 * handled the previous one, but because we're passing them on this 1960 * happens very quickly. So instead we keep a counter of how many 1961 * scroll events there are (or will be) in the VDCMP, and the 1962 * throttling happens at the receiving end. 1963 */ 1964 atomic_add(&scrollEventCount, 1); 1965 1966 struct VimScrollBarMsg sm; 1967 1968 sm.sb = this; 1969 sm.value = (long) newValue; 1970 sm.stillDragging = TRUE; 1971 1972 write_port(gui.vdcmp, VimMsg::ScrollBar, &sm, sizeof(sm)); 1973 1974 // calls gui_drag_scrollbar(sb, newValue, TRUE); 1975 } 1976 1977 /* 1978 * When the mouse goes up, report that scrolling has stopped. 1979 * MouseUp() is NOT called when the mouse-up occurs outside 1980 * the window, even though the thumb does move while the mouse 1981 * is outside... This has some funny effects... XXX 1982 * So we do special processing when the window de/activates. 1983 */ 1984 void 1985 VimScrollBar::MouseUp(BPoint where) 1986 { 1987 // BMessage *m = Window()->CurrentMessage(); 1988 // m->PrintToStream(); 1989 1990 atomic_add(&scrollEventCount, 1); 1991 1992 struct VimScrollBarMsg sm; 1993 1994 sm.sb = this; 1995 sm.value = (long) Value(); 1996 sm.stillDragging = FALSE; 1997 1998 write_port(gui.vdcmp, VimMsg::ScrollBar, &sm, sizeof(sm)); 1999 2000 // calls gui_drag_scrollbar(sb, newValue, FALSE); 2001 2002 Inherited::MouseUp(where); 2003 } 2004 2005 void 2006 VimScrollBar::SetValue(float newValue) 2007 { 2008 if (newValue == Value()) 2009 return; 2010 2011 ignoreValue = newValue; 2012 Inherited::SetValue(newValue); 2013 } 2014 2015 // ---------------- VimFont ---------------- 2016 2017 VimFont::VimFont(): BFont() 2018 { 2019 init(); 2020 } 2021 2022 VimFont::VimFont(const VimFont *rhs): BFont(rhs) 2023 { 2024 init(); 2025 } 2026 2027 VimFont::VimFont(const BFont *rhs): BFont(rhs) 2028 { 2029 init(); 2030 } 2031 2032 VimFont::VimFont(const VimFont &rhs): BFont(rhs) 2033 { 2034 init(); 2035 } 2036 2037 VimFont::~VimFont() 2038 { 2039 } 2040 2041 void 2042 VimFont::init() 2043 { 2044 next = NULL; 2045 refcount = 1; 2046 name = NULL; 2047 } 2048 2049 // ---------------- VimDialog ---------------- 2050 2051 #if defined(FEAT_GUI_DIALOG) 2052 2053 const unsigned int kVimDialogButtonMsg = 'VMDB'; 2054 const unsigned int kVimDialogIconStripeWidth = 30; 2055 const unsigned int kVimDialogButtonsSpacingX = 9; 2056 const unsigned int kVimDialogButtonsSpacingY = 4; 2057 const unsigned int kVimDialogSpacingX = 6; 2058 const unsigned int kVimDialogSpacingY = 10; 2059 const unsigned int kVimDialogMinimalWidth = 310; 2060 const unsigned int kVimDialogMinimalHeight = 75; 2061 const BRect kDefaultRect = 2062 BRect(0, 0, kVimDialogMinimalWidth, kVimDialogMinimalHeight); 2063 2064 VimDialog::VimDialog(int type, const char *title, const char *message, 2065 const char *buttons, int dfltbutton, const char *textfield, int ex_cmd) 2066 : BWindow(kDefaultRect, title, B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL, 2067 B_NOT_CLOSABLE | B_NOT_RESIZABLE | 2068 B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_ASYNCHRONOUS_CONTROLS) 2069 , fDialogSem(-1) 2070 , fDialogValue(dfltbutton) 2071 , fMessageView(NULL) 2072 , fInputControl(NULL) 2073 , fInputValue(textfield) 2074 { 2075 // master view 2076 VimDialog::View* view = new VimDialog::View(Bounds()); 2077 if (view == NULL) 2078 return; 2079 2080 if (title == NULL) 2081 SetTitle("Vim " VIM_VERSION_MEDIUM); 2082 2083 AddChild(view); 2084 2085 // icon 2086 view->InitIcon(type); 2087 2088 // buttons 2089 int32 which = 1; 2090 float maxButtonWidth = 0; 2091 float maxButtonHeight = 0; 2092 float buttonsWidth = 0; 2093 float buttonsHeight = 0; 2094 BString strButtons(buttons); 2095 strButtons.RemoveAll("&"); 2096 do { 2097 int32 end = strButtons.FindFirst('\n'); 2098 if (end != B_ERROR) 2099 strButtons.SetByteAt(end, '\0'); 2100 2101 BButton *button = _CreateButton(which++, strButtons.String()); 2102 view->AddChild(button); 2103 fButtonsList.AddItem(button); 2104 2105 maxButtonWidth = max_c(maxButtonWidth, button->Bounds().Width()); 2106 maxButtonHeight = max_c(maxButtonHeight, button->Bounds().Height()); 2107 buttonsWidth += button->Bounds().Width(); 2108 buttonsHeight += button->Bounds().Height(); 2109 2110 if (end == B_ERROR) 2111 break; 2112 2113 strButtons.Remove(0, end + 1); 2114 } while (true); 2115 2116 int32 buttonsCount = fButtonsList.CountItems(); 2117 buttonsWidth += kVimDialogButtonsSpacingX * (buttonsCount - 1); 2118 buttonsHeight += kVimDialogButtonsSpacingY * (buttonsCount - 1); 2119 float dialogWidth = buttonsWidth + kVimDialogIconStripeWidth + 2120 kVimDialogSpacingX * 2; 2121 float dialogHeight = maxButtonHeight + kVimDialogSpacingY * 3; 2122 2123 // Check 'v' flag in 'guioptions': vertical button placement. 2124 bool vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL) || 2125 dialogWidth >= gui.vimWindow->Bounds().Width(); 2126 if (vertical) { 2127 dialogWidth -= buttonsWidth; 2128 dialogWidth += maxButtonWidth; 2129 dialogHeight -= maxButtonHeight; 2130 dialogHeight += buttonsHeight; 2131 } 2132 2133 dialogWidth = max_c(dialogWidth, kVimDialogMinimalWidth); 2134 2135 // message view 2136 BRect rect(0, 0, dialogWidth, 0); 2137 rect.left += kVimDialogIconStripeWidth + 16 + kVimDialogSpacingX; 2138 rect.top += kVimDialogSpacingY; 2139 rect.right -= kVimDialogSpacingX; 2140 rect.bottom = rect.top; 2141 fMessageView = new BTextView(rect, "_tv_", rect.OffsetByCopy(B_ORIGIN), 2142 B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW); 2143 2144 fMessageView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 2145 rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR); 2146 fMessageView->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor); 2147 fMessageView->SetText(message); 2148 fMessageView->MakeEditable(false); 2149 fMessageView->MakeSelectable(false); 2150 fMessageView->SetWordWrap(true); 2151 AddChild(fMessageView); 2152 2153 float messageHeight = fMessageView->TextHeight(0, fMessageView->CountLines()); 2154 fMessageView->ResizeBy(0, messageHeight); 2155 fMessageView->SetTextRect(BRect(0, 0, rect.Width(), messageHeight)); 2156 2157 dialogHeight += messageHeight; 2158 2159 // input view 2160 if (fInputValue != NULL) { 2161 rect.top = 2162 rect.bottom += messageHeight + kVimDialogSpacingY; 2163 fInputControl = new BTextControl(rect, "_iv_", NULL, fInputValue, NULL, 2164 B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE | B_PULSE_NEEDED); 2165 fInputControl->TextView()->SetText(fInputValue); 2166 fInputControl->TextView()->SetWordWrap(false); 2167 AddChild(fInputControl); 2168 2169 float width = 0.f, height = 0.f; 2170 fInputControl->GetPreferredSize(&width, &height); 2171 fInputControl->MakeFocus(true); 2172 2173 dialogHeight += height + kVimDialogSpacingY * 1.5; 2174 } 2175 2176 dialogHeight = max_c(dialogHeight, kVimDialogMinimalHeight); 2177 2178 ResizeTo(dialogWidth, dialogHeight); 2179 MoveTo((gui.vimWindow->Bounds().Width() - dialogWidth) / 2, 2180 (gui.vimWindow->Bounds().Height() - dialogHeight) / 2); 2181 2182 // adjust layout of buttons 2183 float buttonWidth = max_c(maxButtonWidth, rect.Width() * 0.66); 2184 BPoint origin(dialogWidth, dialogHeight); 2185 origin.x -= kVimDialogSpacingX + (vertical ? buttonWidth : buttonsWidth); 2186 origin.y -= kVimDialogSpacingY + (vertical ? buttonsHeight : maxButtonHeight); 2187 2188 for (int32 i = 0 ; i < buttonsCount; i++) { 2189 BButton *button = (BButton*)fButtonsList.ItemAt(i); 2190 button->MoveTo(origin); 2191 if (vertical) { 2192 origin.y += button->Frame().Height() + kVimDialogButtonsSpacingY; 2193 button->ResizeTo(buttonWidth, button->Frame().Height()); 2194 } else 2195 origin.x += button->Frame().Width() + kVimDialogButtonsSpacingX; 2196 2197 if (dfltbutton == i + 1) { 2198 button->MakeDefault(true); 2199 button->MakeFocus(fInputControl == NULL); 2200 } 2201 } 2202 } 2203 2204 VimDialog::~VimDialog() 2205 { 2206 if (fDialogSem > B_OK) 2207 delete_sem(fDialogSem); 2208 } 2209 2210 int 2211 VimDialog::Go() 2212 { 2213 fDialogSem = create_sem(0, "VimDialogSem"); 2214 if (fDialogSem < B_OK) { 2215 Quit(); 2216 return fDialogValue; 2217 } 2218 2219 Show(); 2220 2221 while (acquire_sem(fDialogSem) == B_INTERRUPTED); 2222 2223 int retValue = fDialogValue; 2224 if (fInputValue != NULL) 2225 vim_strncpy((char_u*)fInputValue, (char_u*)fInputControl->Text(), IOSIZE - 1); 2226 2227 if (Lock()) 2228 Quit(); 2229 2230 return retValue; 2231 } 2232 2233 void VimDialog::MessageReceived(BMessage *msg) 2234 { 2235 int32 which = 0; 2236 if (msg->what != kVimDialogButtonMsg || 2237 msg->FindInt32("which", &which) != B_OK) 2238 return BWindow::MessageReceived(msg); 2239 2240 fDialogValue = which; 2241 delete_sem(fDialogSem); 2242 fDialogSem = -1; 2243 } 2244 2245 BButton* VimDialog::_CreateButton(int32 which, const char* label) 2246 { 2247 BMessage *message = new BMessage(kVimDialogButtonMsg); 2248 message->AddInt32("which", which); 2249 2250 BRect rect(0, 0, 0, 0); 2251 BString name; 2252 name << "_b" << which << "_"; 2253 2254 BButton* button = new BButton(rect, name.String(), label, message, 2255 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); 2256 2257 float width = 0.f, height = 0.f; 2258 button->GetPreferredSize(&width, &height); 2259 button->ResizeTo(width, height); 2260 2261 return button; 2262 } 2263 2264 VimDialog::View::View(BRect frame) 2265 : BView(frame, "VimDialogView", B_FOLLOW_ALL_SIDES, B_WILL_DRAW), 2266 fIconBitmap(NULL) 2267 { 2268 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 2269 } 2270 2271 VimDialog::View::~View() 2272 { 2273 delete fIconBitmap; 2274 } 2275 2276 void VimDialog::View::Draw(BRect updateRect) 2277 { 2278 BRect stripeRect = Bounds(); 2279 stripeRect.right = kVimDialogIconStripeWidth; 2280 SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT)); 2281 FillRect(stripeRect); 2282 2283 if (fIconBitmap == NULL) 2284 return; 2285 2286 SetDrawingMode(B_OP_ALPHA); 2287 SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 2288 DrawBitmapAsync(fIconBitmap, BPoint(18, 6)); 2289 } 2290 2291 void VimDialog::View::InitIcon(int32 type) 2292 { 2293 if (type == VIM_GENERIC) 2294 return; 2295 2296 BPath path; 2297 status_t status = find_directory(B_BEOS_SERVERS_DIRECTORY, &path); 2298 if (status != B_OK) { 2299 fprintf(stderr, "Cannot retrieve app info:%s\n", strerror(status)); 2300 return; 2301 } 2302 2303 path.Append("app_server"); 2304 2305 BFile file(path.Path(), O_RDONLY); 2306 if (file.InitCheck() != B_OK) { 2307 fprintf(stderr, "App file assignment failed:%s\n", 2308 strerror(file.InitCheck())); 2309 return; 2310 } 2311 2312 BResources resources(&file); 2313 if (resources.InitCheck() != B_OK) { 2314 fprintf(stderr, "App server resources assignment failed:%s\n", 2315 strerror(resources.InitCheck())); 2316 return; 2317 } 2318 2319 const char *name = ""; 2320 switch(type) { 2321 case VIM_ERROR: name = "stop"; break; 2322 case VIM_WARNING: name = "warn"; break; 2323 case VIM_INFO: name = "info"; break; 2324 case VIM_QUESTION: name = "idea"; break; 2325 default: return; 2326 } 2327 2328 int32 iconSize = 32; 2329 fIconBitmap = new BBitmap(BRect(0, 0, iconSize - 1, iconSize - 1), 0, B_RGBA32); 2330 if (fIconBitmap == NULL || fIconBitmap->InitCheck() != B_OK) { 2331 fprintf(stderr, "Icon bitmap allocation failed:%s\n", 2332 (fIconBitmap == NULL) ? "null" : strerror(fIconBitmap->InitCheck())); 2333 return; 2334 } 2335 2336 size_t size = 0; 2337 const uint8* iconData = NULL; 2338 // try vector icon first? 2339 iconData = (const uint8*)resources.LoadResource(B_VECTOR_ICON_TYPE, name, &size); 2340 if (iconData != NULL && BIconUtils::GetVectorIcon(iconData, size, fIconBitmap) == B_OK) 2341 return; 2342 2343 // try bitmap icon now 2344 iconData = (const uint8*)resources.LoadResource(B_LARGE_ICON_TYPE, name, &size); 2345 if (iconData == NULL) { 2346 fprintf(stderr, "Bitmap icon resource not found\n"); 2347 delete fIconBitmap; 2348 fIconBitmap = NULL; 2349 return; 2350 } 2351 2352 if (fIconBitmap->ColorSpace() != B_CMAP8) 2353 BIconUtils::ConvertFromCMAP8(iconData, iconSize, iconSize, iconSize, fIconBitmap); 2354 } 2355 2356 const unsigned int kVimDialogOKButtonMsg = 'FDOK'; 2357 const unsigned int kVimDialogCancelButtonMsg = 'FDCN'; 2358 const unsigned int kVimDialogSizeInputMsg = 'SICH'; 2359 const unsigned int kVimDialogFamilySelectMsg = 'MSFM'; 2360 const unsigned int kVimDialogStyleSelectMsg = 'MSST'; 2361 const unsigned int kVimDialogSizeSelectMsg = 'MSSZ'; 2362 2363 VimSelectFontDialog::VimSelectFontDialog(font_family* family, font_style* style, float* size) 2364 : BWindow(kDefaultRect, "Font Selection", B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL, 2365 B_NOT_CLOSABLE | B_NOT_RESIZABLE | 2366 B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_ASYNCHRONOUS_CONTROLS) 2367 , fStatus(B_NO_INIT) 2368 , fDialogSem(-1) 2369 , fDialogValue(false) 2370 , fFamily(family) 2371 , fStyle(style) 2372 , fSize(size) 2373 , fFontSize(*size) 2374 , fPreview(0) 2375 , fFamiliesList(0) 2376 , fStylesList(0) 2377 , fSizesList(0) 2378 , fSizesInput(0) 2379 { 2380 strncpy(fFontFamily, *family, B_FONT_FAMILY_LENGTH); 2381 strncpy(fFontStyle, *style, B_FONT_STYLE_LENGTH); 2382 2383 // "client" area view 2384 BBox *clientBox = new BBox(Bounds(), B_EMPTY_STRING, B_FOLLOW_ALL_SIDES, 2385 B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP | B_PULSE_NEEDED, 2386 B_PLAIN_BORDER); 2387 AddChild(clientBox); 2388 2389 // client view 2390 BRect RC = clientBox->Bounds(); 2391 RC.InsetBy(kVimDialogSpacingX, kVimDialogSpacingY); 2392 BRect rc(RC.LeftTop(), RC.LeftTop()); 2393 2394 // at first create all controls 2395 fPreview = new BStringView(rc, "preview", "DejaVu Sans Mono"); 2396 clientBox->AddChild(fPreview); 2397 2398 BBox* boxDivider = new BBox(rc, B_EMPTY_STRING, 2399 B_FOLLOW_NONE, B_WILL_DRAW, B_FANCY_BORDER); 2400 clientBox->AddChild(boxDivider); 2401 2402 BStringView *labelFamily = new BStringView(rc, "labelFamily", "Family:"); 2403 clientBox->AddChild(labelFamily); 2404 labelFamily->ResizeToPreferred(); 2405 2406 BStringView *labelStyle = new BStringView(rc, "labelStyle", "Style:"); 2407 clientBox->AddChild(labelStyle); 2408 labelStyle->ResizeToPreferred(); 2409 2410 BStringView *labelSize = new BStringView(rc, "labelSize", "Size:"); 2411 clientBox->AddChild(labelSize); 2412 labelSize->ResizeToPreferred(); 2413 2414 fFamiliesList = new BListView(rc, "listFamily", 2415 B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES); 2416 BScrollView *scrollFamilies = new BScrollView("scrollFamily", 2417 fFamiliesList, B_FOLLOW_LEFT_RIGHT, 0, false, true); 2418 clientBox->AddChild(scrollFamilies); 2419 2420 fStylesList= new BListView(rc, "listStyles", 2421 B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES); 2422 BScrollView *scrollStyles = new BScrollView("scrollStyle", 2423 fStylesList, B_FOLLOW_LEFT_RIGHT, 0, false, true); 2424 clientBox->AddChild(scrollStyles); 2425 2426 fSizesInput = new BTextControl(rc, "inputSize", NULL, "???", 2427 new BMessage(kVimDialogSizeInputMsg)); 2428 clientBox->AddChild(fSizesInput); 2429 fSizesInput->ResizeToPreferred(); 2430 2431 fSizesList = new BListView(rc, "listSizes", 2432 B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES); 2433 BScrollView *scrollSizes = new BScrollView("scrollSize", 2434 fSizesList, B_FOLLOW_LEFT_RIGHT, 0, false, true); 2435 clientBox->AddChild(scrollSizes); 2436 2437 BButton *buttonOK = new BButton(rc, "buttonOK", "OK", 2438 new BMessage(kVimDialogOKButtonMsg)); 2439 clientBox->AddChild(buttonOK); 2440 buttonOK->ResizeToPreferred(); 2441 2442 BButton *buttonCancel = new BButton(rc, "buttonCancel", "Cancel", 2443 new BMessage(kVimDialogCancelButtonMsg)); 2444 clientBox->AddChild(buttonCancel); 2445 buttonCancel->ResizeToPreferred(); 2446 2447 // layout controls 2448 float lineHeight = labelFamily->Bounds().Height(); 2449 float previewHeight = lineHeight * 3; 2450 float offsetYLabels = previewHeight + kVimDialogSpacingY; 2451 float offsetYLists = offsetYLabels + lineHeight + kVimDialogSpacingY / 2; 2452 float offsetYSizes = offsetYLists + fSizesInput->Bounds().Height() + kVimDialogSpacingY / 2; 2453 float listsHeight = lineHeight * 9; 2454 float offsetYButtons = offsetYLists + listsHeight + kVimDialogSpacingY; 2455 float maxControlsHeight = offsetYButtons + buttonOK->Bounds().Height(); 2456 float familiesWidth = labelFamily->Bounds().Width() * 5; 2457 float offsetXStyles = familiesWidth + kVimDialogSpacingX; 2458 float stylesWidth = labelStyle->Bounds().Width() * 4; 2459 float offsetXSizes = offsetXStyles + stylesWidth + kVimDialogSpacingX; 2460 float sizesWidth = labelSize->Bounds().Width() * 2; 2461 float maxControlsWidth = offsetXSizes + sizesWidth; 2462 2463 ResizeTo(maxControlsWidth + kVimDialogSpacingX * 2, 2464 maxControlsHeight + kVimDialogSpacingY * 2); 2465 2466 BRect rcVim = gui.vimWindow->Frame(); 2467 MoveTo(rcVim.left + (rcVim.Width() - Frame().Width()) / 2, 2468 rcVim.top + (rcVim.Height() - Frame().Height()) / 2); 2469 2470 fPreview->ResizeTo(maxControlsWidth, previewHeight); 2471 fPreview->SetAlignment(B_ALIGN_CENTER); 2472 2473 boxDivider->MoveBy(0.f, previewHeight + kVimDialogSpacingY / 2); 2474 boxDivider->ResizeTo(maxControlsWidth, 1.f); 2475 2476 labelFamily->MoveBy(0.f, offsetYLabels); 2477 labelStyle->MoveBy(offsetXStyles, offsetYLabels); 2478 labelSize->MoveBy(offsetXSizes, offsetYLabels); 2479 2480 // text control alignment issues 2481 float insetX = fSizesInput->TextView()->Bounds().Width() - fSizesInput->Bounds().Width(); 2482 float insetY = fSizesInput->TextView()->Bounds().Width() - fSizesInput->Bounds().Width(); 2483 2484 scrollFamilies->MoveBy(0.f, offsetYLists); 2485 scrollStyles->MoveBy(offsetXStyles, offsetYLists); 2486 fSizesInput->MoveBy(offsetXSizes + insetX / 2, offsetYLists + insetY / 2); 2487 scrollSizes->MoveBy(offsetXSizes, offsetYSizes); 2488 2489 fSizesInput->SetAlignment(B_ALIGN_CENTER, B_ALIGN_CENTER); 2490 2491 scrollFamilies->ResizeTo(familiesWidth, listsHeight); 2492 scrollStyles->ResizeTo(stylesWidth, listsHeight); 2493 fSizesInput->ResizeTo(sizesWidth, fSizesInput->Bounds().Height()); 2494 scrollSizes->ResizeTo(sizesWidth, 2495 listsHeight - (offsetYSizes - offsetYLists)); 2496 2497 buttonOK->MoveBy(maxControlsWidth - buttonOK->Bounds().Width(), offsetYButtons); 2498 buttonCancel->MoveBy(maxControlsWidth - buttonOK->Bounds().Width() 2499 - buttonCancel->Bounds().Width() - kVimDialogSpacingX, offsetYButtons); 2500 2501 // fill lists 2502 int selIndex = -1; 2503 int count = count_font_families(); 2504 for (int i = 0; i < count; i++) { 2505 font_family family; 2506 if (get_font_family(i, &family ) == B_OK) { 2507 fFamiliesList->AddItem(new BStringItem((const char*)family)); 2508 if (strncmp(family, fFontFamily, B_FONT_FAMILY_LENGTH) == 0) 2509 selIndex = i; 2510 } 2511 } 2512 2513 if (selIndex >= 0) { 2514 fFamiliesList->Select(selIndex); 2515 fFamiliesList->ScrollToSelection(); 2516 } 2517 2518 _UpdateFontStyles(); 2519 2520 selIndex = -1; 2521 for (int size = 8, index = 0; size <= 18; size++, index++) { 2522 BString str; 2523 str << size; 2524 fSizesList->AddItem(new BStringItem(str)); 2525 if (size == fFontSize) 2526 selIndex = index; 2527 2528 } 2529 2530 if (selIndex >= 0) { 2531 fSizesList->Select(selIndex); 2532 fSizesList->ScrollToSelection(); 2533 } 2534 2535 fFamiliesList->SetSelectionMessage(new BMessage(kVimDialogFamilySelectMsg)); 2536 fStylesList->SetSelectionMessage(new BMessage(kVimDialogStyleSelectMsg)); 2537 fSizesList->SetSelectionMessage(new BMessage(kVimDialogSizeSelectMsg)); 2538 fSizesInput->SetModificationMessage(new BMessage(kVimDialogSizeInputMsg)); 2539 2540 _UpdateSizeInputPreview(); 2541 _UpdateFontPreview(); 2542 2543 fStatus = B_OK; 2544 } 2545 2546 VimSelectFontDialog::~VimSelectFontDialog() 2547 { 2548 _CleanList(fFamiliesList); 2549 _CleanList(fStylesList); 2550 _CleanList(fSizesList); 2551 2552 if (fDialogSem > B_OK) 2553 delete_sem(fDialogSem); 2554 } 2555 2556 void 2557 VimSelectFontDialog::_CleanList(BListView* list) 2558 { 2559 while (0 < list->CountItems()) 2560 delete (dynamic_cast<BStringItem*>(list->RemoveItem((int32)0))); 2561 } 2562 2563 bool 2564 VimSelectFontDialog::Go() 2565 { 2566 if (fStatus != B_OK) { 2567 Quit(); 2568 return NOFONT; 2569 } 2570 2571 fDialogSem = create_sem(0, "VimFontSelectDialogSem"); 2572 if (fDialogSem < B_OK) { 2573 Quit(); 2574 return fDialogValue; 2575 } 2576 2577 Show(); 2578 2579 while (acquire_sem(fDialogSem) == B_INTERRUPTED); 2580 2581 bool retValue = fDialogValue; 2582 2583 if (Lock()) 2584 Quit(); 2585 2586 return retValue; 2587 } 2588 2589 2590 void VimSelectFontDialog::_UpdateFontStyles() 2591 { 2592 _CleanList(fStylesList); 2593 2594 int32 selIndex = -1; 2595 int32 count = count_font_styles(fFontFamily); 2596 for (int32 i = 0; i < count; i++) { 2597 font_style style; 2598 uint32 flags = 0; 2599 if (get_font_style(fFontFamily, i, &style, &flags) == B_OK) { 2600 fStylesList->AddItem(new BStringItem((const char*)style)); 2601 if (strncmp(style, fFontStyle, B_FONT_STYLE_LENGTH) == 0) 2602 selIndex = i; 2603 } 2604 } 2605 2606 if (selIndex >= 0) { 2607 fStylesList->Select(selIndex); 2608 fStylesList->ScrollToSelection(); 2609 } else 2610 fStylesList->Select(0); 2611 } 2612 2613 2614 void VimSelectFontDialog::_UpdateSizeInputPreview() 2615 { 2616 char buf[10] = {0}; 2617 vim_snprintf(buf, sizeof(buf), (char*)"%.0f", fFontSize); 2618 fSizesInput->SetText(buf); 2619 } 2620 2621 2622 void VimSelectFontDialog::_UpdateFontPreview() 2623 { 2624 BFont font; 2625 fPreview->GetFont(&font); 2626 font.SetSize(fFontSize); 2627 font.SetFamilyAndStyle(fFontFamily, fFontStyle); 2628 fPreview->SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE); 2629 2630 BString str; 2631 str << fFontFamily << " " << fFontStyle << ", " << (int)fFontSize << " pt."; 2632 fPreview->SetText(str); 2633 } 2634 2635 2636 bool 2637 VimSelectFontDialog::_UpdateFromListItem(BListView* list, char* text, int textSize) 2638 { 2639 int32 index = list->CurrentSelection(); 2640 if (index < 0) 2641 return false; 2642 BStringItem* item = (BStringItem*)list->ItemAt(index); 2643 if (item == NULL) 2644 return false; 2645 strncpy(text, item->Text(), textSize); 2646 return true; 2647 } 2648 2649 2650 void VimSelectFontDialog::MessageReceived(BMessage *msg) 2651 { 2652 switch (msg->what) { 2653 case kVimDialogOKButtonMsg: 2654 strncpy(*fFamily, fFontFamily, B_FONT_FAMILY_LENGTH); 2655 strncpy(*fStyle, fFontStyle, B_FONT_STYLE_LENGTH); 2656 *fSize = fFontSize; 2657 fDialogValue = true; 2658 case kVimDialogCancelButtonMsg: 2659 delete_sem(fDialogSem); 2660 fDialogSem = -1; 2661 return; 2662 case B_KEY_UP: 2663 { 2664 int32 key = 0; 2665 if (msg->FindInt32("raw_char", &key) == B_OK 2666 && key == B_ESCAPE) { 2667 delete_sem(fDialogSem); 2668 fDialogSem = -1; 2669 } 2670 } 2671 break; 2672 2673 case kVimDialogFamilySelectMsg: 2674 if (_UpdateFromListItem(fFamiliesList, 2675 fFontFamily, B_FONT_FAMILY_LENGTH)) { 2676 _UpdateFontStyles(); 2677 _UpdateFontPreview(); 2678 } 2679 break; 2680 case kVimDialogStyleSelectMsg: 2681 if (_UpdateFromListItem(fStylesList, 2682 fFontStyle, B_FONT_STYLE_LENGTH)) 2683 _UpdateFontPreview(); 2684 break; 2685 case kVimDialogSizeSelectMsg: 2686 { 2687 char buf[10] = {0}; 2688 if (_UpdateFromListItem(fSizesList, buf, sizeof(buf))) { 2689 float size = atof(buf); 2690 if (size > 0.f) { 2691 fFontSize = size; 2692 _UpdateSizeInputPreview(); 2693 _UpdateFontPreview(); 2694 } 2695 } 2696 } 2697 break; 2698 case kVimDialogSizeInputMsg: 2699 { 2700 float size = atof(fSizesInput->Text()); 2701 if (size > 0.f) { 2702 fFontSize = size; 2703 _UpdateFontPreview(); 2704 } 2705 } 2706 break; 2707 default: 2708 break; 2709 } 2710 return BWindow::MessageReceived(msg); 2711 } 2712 2713 #endif // FEAT_GUI_DIALOG 2714 2715 #ifdef FEAT_TOOLBAR 2716 2717 // some forward declaration required by toolbar functions... 2718 static BMessage * MenuMessage(vimmenu_T *menu); 2719 2720 VimToolbar::VimToolbar(BRect frame, const char *name) : 2721 BBox(frame, name, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_FRAME_EVENTS, B_PLAIN_BORDER) 2722 { 2723 } 2724 2725 VimToolbar::~VimToolbar() 2726 { 2727 int32 count = fButtonsList.CountItems(); 2728 for (int32 i = 0; i < count; i++) 2729 delete (BPictureButton*)fButtonsList.ItemAt(i); 2730 fButtonsList.MakeEmpty(); 2731 2732 delete normalButtonsBitmap; 2733 delete grayedButtonsBitmap; 2734 normalButtonsBitmap = NULL; 2735 grayedButtonsBitmap = NULL; 2736 } 2737 2738 void 2739 VimToolbar::AttachedToWindow() 2740 { 2741 BBox::AttachedToWindow(); 2742 2743 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 2744 } 2745 2746 float 2747 VimToolbar::ToolbarHeight() const 2748 { 2749 float size = NULL == normalButtonsBitmap ? 18. : normalButtonsBitmap->Bounds().Height(); 2750 return size + ToolbarMargin * 2 + ButtonMargin * 2 + 1; 2751 } 2752 2753 bool 2754 VimToolbar::ModifyBitmapToGrayed(BBitmap *bitmap) 2755 { 2756 float height = bitmap->Bounds().Height(); 2757 float width = bitmap->Bounds().Width(); 2758 2759 rgb_color *bits = (rgb_color*)bitmap->Bits(); 2760 int32 pixels = bitmap->BitsLength() / 4; 2761 for (int32 i = 0; i < pixels; i++) { 2762 bits[i].red = bits[i].green = 2763 bits[i].blue = ((uint32)bits[i].red + bits[i].green + bits[i].blue) / 3; 2764 bits[i].alpha /= 4; 2765 } 2766 2767 return true; 2768 } 2769 2770 bool 2771 VimToolbar::PrepareButtonBitmaps() 2772 { 2773 // first try to load potentially customized $VIRUNTIME/bitmaps/builtin-tools.png 2774 normalButtonsBitmap = LoadVimBitmap("builtin-tools.png"); 2775 if (normalButtonsBitmap == NULL) 2776 // customized not found? dig application resources for "builtin-tools" one 2777 normalButtonsBitmap = BTranslationUtils::GetBitmap(B_PNG_FORMAT, "builtin-tools"); 2778 2779 if (normalButtonsBitmap == NULL) 2780 return false; 2781 2782 BMessage archive; 2783 normalButtonsBitmap->Archive(&archive); 2784 2785 grayedButtonsBitmap = new BBitmap(&archive); 2786 if (grayedButtonsBitmap == NULL) 2787 return false; 2788 2789 // modify grayed bitmap 2790 ModifyBitmapToGrayed(grayedButtonsBitmap); 2791 2792 return true; 2793 } 2794 2795 BBitmap *VimToolbar::LoadVimBitmap(const char* fileName) 2796 { 2797 BBitmap *bitmap = NULL; 2798 2799 int mustfree = 0; 2800 char_u* runtimePath = vim_getenv((char_u*)"VIMRUNTIME", &mustfree); 2801 if (runtimePath != NULL && fileName != NULL) { 2802 BString strPath((char*)runtimePath); 2803 strPath << "/bitmaps/" << fileName; 2804 bitmap = BTranslationUtils::GetBitmap(strPath.String()); 2805 } 2806 2807 if (mustfree) 2808 vim_free(runtimePath); 2809 2810 return bitmap; 2811 } 2812 2813 bool 2814 VimToolbar::GetPictureFromBitmap(BPicture *pictureTo, int32 index, BBitmap *bitmapFrom, bool pressed) 2815 { 2816 float size = bitmapFrom->Bounds().Height() + 1.; 2817 2818 BView view(BRect(0, 0, size, size), "", 0, 0); 2819 2820 AddChild(&view); 2821 view.BeginPicture(pictureTo); 2822 2823 view.SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 2824 view.FillRect(view.Bounds()); 2825 view.SetDrawingMode(B_OP_OVER); 2826 2827 BRect source(0, 0, size - 1, size - 1); 2828 BRect destination(source); 2829 2830 source.OffsetBy(size * index, 0); 2831 destination.OffsetBy(ButtonMargin, ButtonMargin); 2832 2833 view.DrawBitmap(bitmapFrom, source, destination); 2834 2835 if (pressed) { 2836 rgb_color shineColor = ui_color(B_SHINE_COLOR); 2837 rgb_color shadowColor = ui_color(B_SHADOW_COLOR); 2838 size += ButtonMargin * 2 - 1; 2839 view.BeginLineArray(4); 2840 view.AddLine(BPoint(0, 0), BPoint(size, 0), shadowColor); 2841 view.AddLine(BPoint(size, 0), BPoint(size, size), shineColor); 2842 view.AddLine(BPoint(size, size), BPoint(0, size), shineColor); 2843 view.AddLine(BPoint(0, size), BPoint(0, 0), shadowColor); 2844 view.EndLineArray(); 2845 } 2846 2847 view.EndPicture(); 2848 RemoveChild(&view); 2849 2850 return true; 2851 } 2852 2853 bool 2854 VimToolbar::AddButton(int32 index, vimmenu_T *menu) 2855 { 2856 BPictureButton *button = NULL; 2857 if (!menu_is_separator(menu->name)) { 2858 float size = normalButtonsBitmap ? 2859 normalButtonsBitmap->Bounds().Height() + 1. + ButtonMargin * 2 : 18.; 2860 BRect frame(0, 0, size, size); 2861 BPicture pictureOn; 2862 BPicture pictureOff; 2863 BPicture pictureGray; 2864 2865 if (menu->iconfile == NULL && menu->iconidx >= 0 && normalButtonsBitmap) { 2866 GetPictureFromBitmap(&pictureOn, menu->iconidx, normalButtonsBitmap, true); 2867 GetPictureFromBitmap(&pictureOff, menu->iconidx, normalButtonsBitmap, false); 2868 GetPictureFromBitmap(&pictureGray, menu->iconidx, grayedButtonsBitmap, false); 2869 } else { 2870 2871 char_u buffer[MAXPATHL] = {0}; 2872 BBitmap *bitmap = NULL; 2873 2874 if (menu->iconfile) { 2875 gui_find_iconfile(menu->iconfile, buffer, (char*)"png"); 2876 bitmap = BTranslationUtils::GetBitmap((char*)buffer); 2877 } 2878 2879 if (bitmap == NULL && gui_find_bitmap(menu->name, buffer, (char*)"png") == OK) 2880 bitmap = BTranslationUtils::GetBitmap((char*)buffer); 2881 2882 if (bitmap == NULL) 2883 bitmap = new BBitmap(BRect(0, 0, size, size), B_RGB32); 2884 2885 GetPictureFromBitmap(&pictureOn, 0, bitmap, true); 2886 GetPictureFromBitmap(&pictureOff, 0, bitmap, false); 2887 ModifyBitmapToGrayed(bitmap); 2888 GetPictureFromBitmap(&pictureGray, 0, bitmap, false); 2889 2890 delete bitmap; 2891 } 2892 2893 button = new BPictureButton(frame, (char*)menu->name, 2894 &pictureOff, &pictureOn, MenuMessage(menu)); 2895 2896 button->SetDisabledOn(&pictureGray); 2897 button->SetDisabledOff(&pictureGray); 2898 2899 button->SetTarget(gui.vimTextArea); 2900 2901 AddChild(button); 2902 2903 menu->button = button; 2904 } 2905 2906 bool result = fButtonsList.AddItem(button, index); 2907 InvalidateLayout(); 2908 return result; 2909 } 2910 2911 bool 2912 VimToolbar::RemoveButton(vimmenu_T *menu) 2913 { 2914 if (menu->button) { 2915 if (fButtonsList.RemoveItem(menu->button)) { 2916 delete menu->button; 2917 menu->button = NULL; 2918 } 2919 } 2920 return true; 2921 } 2922 2923 bool 2924 VimToolbar::GrayButton(vimmenu_T *menu, int grey) 2925 { 2926 if (menu->button) { 2927 int32 index = fButtonsList.IndexOf(menu->button); 2928 if (index >= 0) 2929 menu->button->SetEnabled(grey ? false : true); 2930 } 2931 return true; 2932 } 2933 2934 void 2935 VimToolbar::InvalidateLayout() 2936 { 2937 int32 offset = ToolbarMargin; 2938 int32 count = fButtonsList.CountItems(); 2939 for (int32 i = 0; i < count; i++) { 2940 BPictureButton *button = (BPictureButton *)fButtonsList.ItemAt(i); 2941 if (button) { 2942 button->MoveTo(offset, ToolbarMargin); 2943 offset += button->Bounds().Width() + ToolbarMargin; 2944 } else 2945 offset += ToolbarMargin * 3; 2946 } 2947 } 2948 2949 #endif /*FEAT_TOOLBAR*/ 2950 2951 #if defined(FEAT_GUI_TABLINE) 2952 2953 float 2954 VimTabLine::TablineHeight() const 2955 { 2956 // float size = NULL == normalButtonsBitmap ? 18. : normalButtonsBitmap->Bounds().Height(); 2957 // return size + ToolbarMargin * 2 + ButtonMargin * 2 + 1; 2958 return TabHeight(); // + ToolbarMargin; 2959 } 2960 2961 void 2962 VimTabLine::MouseDown(BPoint point) 2963 { 2964 if (!gui_mch_showing_tabline()) 2965 return; 2966 2967 BMessage *m = Window()->CurrentMessage(); 2968 assert(m); 2969 2970 int32 buttons = 0; 2971 m->FindInt32("buttons", &buttons); 2972 2973 int32 clicks = 0; 2974 m->FindInt32("clicks", &clicks); 2975 2976 int index = 0; // 0 means here - no tab found 2977 for (int i = 0; i < CountTabs(); i++) { 2978 if (TabFrame(i).Contains(point)) { 2979 index = i + 1; // indexes are 1-based 2980 break; 2981 } 2982 } 2983 2984 int event = -1; 2985 2986 if ((buttons & B_PRIMARY_MOUSE_BUTTON) && clicks > 1) 2987 // left button double click on - create new tab 2988 event = TABLINE_MENU_NEW; 2989 2990 else if (buttons & B_TERTIARY_MOUSE_BUTTON) 2991 // middle button click - close the pointed tab 2992 // or create new one in case empty space 2993 event = index > 0 ? TABLINE_MENU_CLOSE : TABLINE_MENU_NEW; 2994 2995 else if (buttons & B_SECONDARY_MOUSE_BUTTON) { 2996 // right button click - show context menu 2997 BPopUpMenu* popUpMenu = new BPopUpMenu("tabLineContextMenu", false, false); 2998 popUpMenu->AddItem(new BMenuItem(_("Close tabi R"), new BMessage(TABLINE_MENU_CLOSE))); 2999 popUpMenu->AddItem(new BMenuItem(_("New tab T"), new BMessage(TABLINE_MENU_NEW))); 3000 popUpMenu->AddItem(new BMenuItem(_("Open tab..."), new BMessage(TABLINE_MENU_OPEN))); 3001 3002 ConvertToScreen(&point); 3003 BMenuItem* item = popUpMenu->Go(point); 3004 if (item != NULL) { 3005 event = item->Command(); 3006 } 3007 3008 delete popUpMenu; 3009 3010 } else { 3011 // default processing 3012 BTabView::MouseDown(point); 3013 return; 3014 } 3015 3016 if (event < 0) 3017 return; 3018 3019 VimTablineMenuMsg tmm; 3020 tmm.index = index; 3021 tmm.event = event; 3022 write_port(gui.vdcmp, VimMsg::TablineMenu, &tmm, sizeof(tmm)); 3023 } 3024 3025 void 3026 VimTabLine::VimTab::Select(BView* owner) 3027 { 3028 BTab::Select(owner); 3029 3030 VimTabLine *tabLine = gui.vimForm->TabLine(); 3031 if (tabLine != NULL) { 3032 3033 int32 i = 0; 3034 for (; i < tabLine->CountTabs(); i++) 3035 if (this == tabLine->TabAt(i)) 3036 break; 3037 3038 // printf("%d:%d:%s\n", i, tabLine->CountTabs(), tabLine->TabAt(i)->Label()); 3039 if (i < tabLine->CountTabs()) { 3040 VimTablineMsg tm; 3041 tm.index = i + 1; 3042 write_port(gui.vdcmp, VimMsg::Tabline, &tm, sizeof(tm)); 3043 } 3044 } 3045 } 3046 3047 #endif // defined(FEAT_GUI_TABLINE) 3048 3049 // ---------------- ---------------- 3050 3051 // some global variables 3052 static char appsig[] = "application/x-vnd.Haiku-Vim-8"; 3053 key_map *keyMap; 3054 char *keyMapChars; 3055 int main_exitcode = 127; 3056 3057 status_t 3058 gui_haiku_process_event(bigtime_t timeout) 3059 { 3060 struct VimMsg vm; 3061 int32 what; 3062 ssize_t size; 3063 3064 size = read_port_etc(gui.vdcmp, &what, &vm, sizeof(vm), 3065 B_TIMEOUT, timeout); 3066 3067 if (size >= 0) { 3068 switch (what) { 3069 case VimMsg::Key: 3070 { 3071 char_u *string = vm.u.Key.chars; 3072 int len = vm.u.Key.length; 3073 if (len == 1 && string[0] == Ctrl_chr('C')) { 3074 trash_input_buf(); 3075 got_int = TRUE; 3076 } 3077 3078 if (vm.u.Key.csi_escape) 3079 #ifndef FEAT_MBYTE_IME 3080 { 3081 int i; 3082 char_u buf[2]; 3083 3084 for (i = 0; i < len; ++i) 3085 { 3086 add_to_input_buf(string + i, 1); 3087 if (string[i] == CSI) 3088 { 3089 // Turn CSI into K_CSI. 3090 buf[0] = KS_EXTRA; 3091 buf[1] = (int)KE_CSI; 3092 add_to_input_buf(buf, 2); 3093 } 3094 } 3095 } 3096 #else 3097 add_to_input_buf_csi(string, len); 3098 #endif 3099 else 3100 add_to_input_buf(string, len); 3101 } 3102 break; 3103 case VimMsg::Resize: 3104 gui_resize_shell(vm.u.NewSize.width, vm.u.NewSize.height); 3105 break; 3106 case VimMsg::ScrollBar: 3107 { 3108 /* 3109 * If loads of scroll messages queue up, use only the last 3110 * one. Always report when the scrollbar stops dragging. 3111 * This is not perfect yet anyway: these events are queued 3112 * yet again, this time in the keyboard input buffer. 3113 */ 3114 int32 oldCount = 3115 atomic_add(&vm.u.Scroll.sb->scrollEventCount, -1); 3116 if (oldCount <= 1 || !vm.u.Scroll.stillDragging) 3117 gui_drag_scrollbar(vm.u.Scroll.sb->getGsb(), 3118 vm.u.Scroll.value, vm.u.Scroll.stillDragging); 3119 } 3120 break; 3121 #if defined(FEAT_MENU) 3122 case VimMsg::Menu: 3123 gui_menu_cb(vm.u.Menu.guiMenu); 3124 break; 3125 #endif 3126 case VimMsg::Mouse: 3127 { 3128 int32 oldCount; 3129 if (vm.u.Mouse.button == MOUSE_DRAG) 3130 oldCount = 3131 atomic_add(&gui.vimTextArea->mouseDragEventCount, -1); 3132 else 3133 oldCount = 0; 3134 if (oldCount <= 1) 3135 gui_send_mouse_event(vm.u.Mouse.button, vm.u.Mouse.x, 3136 vm.u.Mouse.y, vm.u.Mouse.repeated_click, 3137 vm.u.Mouse.modifiers); 3138 } 3139 break; 3140 case VimMsg::MouseMoved: 3141 { 3142 gui_mouse_moved(vm.u.MouseMoved.x, vm.u.MouseMoved.y); 3143 } 3144 break; 3145 case VimMsg::Focus: 3146 gui.in_focus = vm.u.Focus.active; 3147 // XXX Signal that scrollbar dragging has stopped? 3148 // This is needed because we don't get a MouseUp if 3149 // that happens while outside the window... :-( 3150 if (gui.dragged_sb) { 3151 gui.dragged_sb = SBAR_NONE; 3152 } 3153 // gui_update_cursor(TRUE, FALSE); 3154 break; 3155 case VimMsg::Refs: 3156 ::RefsReceived(vm.u.Refs.message, vm.u.Refs.changedir); 3157 break; 3158 case VimMsg::Tabline: 3159 send_tabline_event(vm.u.Tabline.index); 3160 break; 3161 case VimMsg::TablineMenu: 3162 send_tabline_menu_event(vm.u.TablineMenu.index, vm.u.TablineMenu.event); 3163 break; 3164 default: 3165 // unrecognised message, ignore it 3166 break; 3167 } 3168 } 3169 3170 /* 3171 * If size < B_OK, it is an error code. 3172 */ 3173 return size; 3174 } 3175 3176 /* 3177 * Here are some functions to protect access to ScreenLines[] and 3178 * LineOffset[]. These are used from the window thread to respond 3179 * to a Draw() callback. When that occurs, the window is already 3180 * locked by the system. 3181 * 3182 * Other code that needs to lock is any code that changes these 3183 * variables. Other read-only access, or access merely to the 3184 * contents of the screen buffer, need not be locked. 3185 * 3186 * If there is no window, don't call Lock() but do succeed. 3187 */ 3188 3189 int 3190 vim_lock_screen() 3191 { 3192 return !gui.vimWindow || gui.vimWindow->Lock(); 3193 } 3194 3195 void 3196 vim_unlock_screen() 3197 { 3198 if (gui.vimWindow) 3199 gui.vimWindow->Unlock(); 3200 } 3201 3202 #define RUN_BAPPLICATION_IN_NEW_THREAD 0 3203 3204 #if RUN_BAPPLICATION_IN_NEW_THREAD 3205 3206 int32 3207 run_vimapp(void *args) 3208 { 3209 VimApp app(appsig); 3210 3211 gui.vimApp = &app; 3212 app.Run(); // Run until Quit() called 3213 3214 return 0; 3215 } 3216 3217 #else 3218 3219 int32 3220 call_main(void *args) 3221 { 3222 struct MainArgs *ma = (MainArgs *)args; 3223 3224 return main(ma->argc, ma->argv); 3225 } 3226 #endif 3227 3228 /* 3229 * Parse the GUI related command-line arguments. Any arguments used are 3230 * deleted from argv, and *argc is decremented accordingly. This is called 3231 * when vim is started, whether or not the GUI has been started. 3232 */ 3233 void 3234 gui_mch_prepare( 3235 int *argc, 3236 char **argv) 3237 { 3238 /* 3239 * We don't have any command line arguments for the BeOS GUI yet, 3240 * but this is an excellent place to create our Application object. 3241 */ 3242 if (!gui.vimApp) { 3243 thread_info tinfo; 3244 get_thread_info(find_thread(NULL), &tinfo); 3245 3246 // May need the port very early on to process RefsReceived() 3247 gui.vdcmp = create_port(B_MAX_PORT_COUNT, "vim VDCMP"); 3248 3249 #if RUN_BAPPLICATION_IN_NEW_THREAD 3250 thread_id tid = spawn_thread(run_vimapp, "vim VimApp", 3251 tinfo.priority, NULL); 3252 if (tid >= B_OK) { 3253 resume_thread(tid); 3254 } else { 3255 getout(1); 3256 } 3257 #else 3258 MainArgs ma = { *argc, argv }; 3259 thread_id tid = spawn_thread(call_main, "vim main()", 3260 tinfo.priority, &ma); 3261 if (tid >= B_OK) { 3262 VimApp app(appsig); 3263 3264 gui.vimApp = &app; 3265 resume_thread(tid); 3266 /* 3267 * This is rather horrible. 3268 * call_main will call main() again... 3269 * There will be no infinite recursion since 3270 * gui.vimApp is set now. 3271 */ 3272 app.Run(); // Run until Quit() called 3273 // fprintf(stderr, "app.Run() returned...\n"); 3274 status_t dummy_exitcode; 3275 (void)wait_for_thread(tid, &dummy_exitcode); 3276 3277 /* 3278 * This path should be the normal one taken to exit Vim. 3279 * The main() thread calls mch_exit() which calls 3280 * gui_mch_exit() which terminates its thread. 3281 */ 3282 exit(main_exitcode); 3283 } 3284 #endif 3285 } 3286 // Don't fork() when starting the GUI. Spawned threads are not 3287 // duplicated with a fork(). The result is a mess. 3288 gui.dofork = FALSE; 3289 /* 3290 * XXX Try to determine whether we were started from 3291 * the Tracker or the terminal. 3292 * It would be nice to have this work, because the Tracker 3293 * follows symlinks, so even if you double-click on gvim, 3294 * when it is a link to vim it will still pass a command name 3295 * of vim... 3296 * We try here to see if stdin comes from /dev/null. If so, 3297 * (or if there is an error, which should never happen) start the GUI. 3298 * This does the wrong thing for vim - </dev/null, and we're 3299 * too early to see the command line parsing. Tough. 3300 * On the other hand, it starts the gui for vim file & which is nice. 3301 */ 3302 if (!isatty(0)) { 3303 struct stat stat_stdin, stat_dev_null; 3304 3305 if (fstat(0, &stat_stdin) == -1 || 3306 stat("/dev/null", &stat_dev_null) == -1 || 3307 (stat_stdin.st_dev == stat_dev_null.st_dev && 3308 stat_stdin.st_ino == stat_dev_null.st_ino)) 3309 gui.starting = TRUE; 3310 } 3311 } 3312 3313 /* 3314 * Check if the GUI can be started. Called before gvimrc is sourced. 3315 * Return OK or FAIL. 3316 */ 3317 int 3318 gui_mch_init_check(void) 3319 { 3320 return OK; // TODO: GUI can always be started? 3321 } 3322 3323 /* 3324 * Initialise the GUI. Create all the windows, set up all the call-backs 3325 * etc. 3326 */ 3327 int 3328 gui_mch_init() 3329 { 3330 display_errors(); 3331 gui.def_norm_pixel = RGB(0x00, 0x00, 0x00); // black 3332 gui.def_back_pixel = RGB(0xFF, 0xFF, 0xFF); // white 3333 gui.norm_pixel = gui.def_norm_pixel; 3334 gui.back_pixel = gui.def_back_pixel; 3335 3336 gui.scrollbar_width = (int) B_V_SCROLL_BAR_WIDTH; 3337 gui.scrollbar_height = (int) B_H_SCROLL_BAR_HEIGHT; 3338 #ifdef FEAT_MENU 3339 gui.menu_height = 19; // initial guess - 3340 // correct for my default settings 3341 #endif 3342 gui.border_offset = 3; // coordinates are inside window borders 3343 3344 if (gui.vdcmp < B_OK) 3345 return FAIL; 3346 get_key_map(&keyMap, &keyMapChars); 3347 3348 gui.vimWindow = new VimWindow(); // hidden and locked 3349 if (!gui.vimWindow) 3350 return FAIL; 3351 3352 gui.vimWindow->Run(); // Run() unlocks but does not show 3353 3354 // Get the colors from the "Normal" group (set in syntax.c or in a vimrc 3355 // file) 3356 set_normal_colors(); 3357 3358 /* 3359 * Check that none of the colors are the same as the background color 3360 */ 3361 gui_check_colors(); 3362 3363 // Get the colors for the highlight groups (gui_check_colors() might have 3364 // changed them) 3365 highlight_gui_started(); // re-init colors and fonts 3366 3367 gui_mch_new_colors(); // window must exist for this 3368 3369 return OK; 3370 } 3371 3372 /* 3373 * Called when the foreground or background color has been changed. 3374 */ 3375 void 3376 gui_mch_new_colors() 3377 { 3378 rgb_color rgb = GUI_TO_RGB(gui.back_pixel); 3379 3380 if (gui.vimWindow->Lock()) { 3381 gui.vimForm->SetViewColor(rgb); 3382 // Does this not have too much effect for those small rectangles? 3383 gui.vimForm->Invalidate(); 3384 gui.vimWindow->Unlock(); 3385 } 3386 } 3387 3388 /* 3389 * Open the GUI window which was created by a call to gui_mch_init(). 3390 */ 3391 int 3392 gui_mch_open() 3393 { 3394 if (gui_win_x != -1 && gui_win_y != -1) 3395 gui_mch_set_winpos(gui_win_x, gui_win_y); 3396 3397 // Actually open the window 3398 if (gui.vimWindow->Lock()) { 3399 gui.vimWindow->Show(); 3400 gui.vimWindow->Unlock(); 3401 return OK; 3402 } 3403 3404 return FAIL; 3405 } 3406 3407 void 3408 gui_mch_exit(int vim_exitcode) 3409 { 3410 if (gui.vimWindow) { 3411 thread_id tid = gui.vimWindow->Thread(); 3412 gui.vimWindow->Lock(); 3413 gui.vimWindow->Quit(); 3414 // Wait until it is truely gone 3415 int32 exitcode; 3416 wait_for_thread(tid, &exitcode); 3417 } 3418 delete_port(gui.vdcmp); 3419 #if !RUN_BAPPLICATION_IN_NEW_THREAD 3420 /* 3421 * We are in the main() thread - quit the App thread and 3422 * quit ourselves (passing on the exitcode). Use a global since the 3423 * value from exit_thread() is only used if wait_for_thread() is 3424 * called in time (race condition). 3425 */ 3426 #endif 3427 if (gui.vimApp) { 3428 VimTextAreaView::guiBlankMouse(false); 3429 3430 main_exitcode = vim_exitcode; 3431 #if RUN_BAPPLICATION_IN_NEW_THREAD 3432 thread_id tid = gui.vimApp->Thread(); 3433 int32 exitcode; 3434 gui.vimApp->Lock(); 3435 gui.vimApp->Quit(); 3436 gui.vimApp->Unlock(); 3437 wait_for_thread(tid, &exitcode); 3438 #else 3439 gui.vimApp->Lock(); 3440 gui.vimApp->Quit(); 3441 gui.vimApp->Unlock(); 3442 // suicide 3443 exit_thread(vim_exitcode); 3444 #endif 3445 } 3446 // If we are somehow still here, let mch_exit() handle things. 3447 } 3448 3449 /* 3450 * Get the position of the top left corner of the window. 3451 */ 3452 int 3453 gui_mch_get_winpos(int *x, int *y) 3454 { 3455 if (gui.vimWindow->Lock()) { 3456 BRect r; 3457 r = gui.vimWindow->Frame(); 3458 gui.vimWindow->Unlock(); 3459 *x = (int)r.left; 3460 *y = (int)r.top; 3461 return OK; 3462 } 3463 else 3464 return FAIL; 3465 } 3466 3467 /* 3468 * Set the position of the top left corner of the window to the given 3469 * coordinates. 3470 */ 3471 void 3472 gui_mch_set_winpos(int x, int y) 3473 { 3474 if (gui.vimWindow->Lock()) { 3475 gui.vimWindow->MoveTo(x, y); 3476 gui.vimWindow->Unlock(); 3477 } 3478 } 3479 3480 /* 3481 * Set the size of the window to the given width and height in pixels. 3482 */ 3483 void 3484 gui_mch_set_shellsize( 3485 int width, 3486 int height, 3487 int min_width, 3488 int min_height, 3489 int base_width, 3490 int base_height, 3491 int direction) // TODO: utilize? 3492 { 3493 /* 3494 * We are basically given the size of the VimForm, if I understand 3495 * correctly. Since it fills the window completely, this will also 3496 * be the size of the window. 3497 */ 3498 if (gui.vimWindow->Lock()) { 3499 gui.vimWindow->ResizeTo(width - PEN_WIDTH, height - PEN_WIDTH); 3500 3501 // set size limits 3502 float minWidth, maxWidth, minHeight, maxHeight; 3503 3504 gui.vimWindow->GetSizeLimits(&minWidth, &maxWidth, 3505 &minHeight, &maxHeight); 3506 gui.vimWindow->SetSizeLimits(min_width, maxWidth, 3507 min_height, maxHeight); 3508 3509 /* 3510 * Set the resizing alignment depending on font size. 3511 */ 3512 gui.vimWindow->SetWindowAlignment( 3513 B_PIXEL_ALIGNMENT, // window_alignment mode, 3514 1, // int32 h, 3515 0, // int32 hOffset = 0, 3516 gui.char_width, // int32 width = 0, 3517 base_width, // int32 widthOffset = 0, 3518 1, // int32 v = 0, 3519 0, // int32 vOffset = 0, 3520 gui.char_height, // int32 height = 0, 3521 base_height // int32 heightOffset = 0 3522 ); 3523 3524 gui.vimWindow->Unlock(); 3525 } 3526 } 3527 3528 void 3529 gui_mch_get_screen_dimensions( 3530 int *screen_w, 3531 int *screen_h) 3532 { 3533 BRect frame; 3534 3535 { 3536 BScreen screen(gui.vimWindow); 3537 3538 if (screen.IsValid()) { 3539 frame = screen.Frame(); 3540 } else { 3541 frame.right = 640; 3542 frame.bottom = 480; 3543 } 3544 } 3545 3546 // XXX approximations... 3547 *screen_w = (int) frame.right - 2 * gui.scrollbar_width - 20; 3548 *screen_h = (int) frame.bottom - gui.scrollbar_height 3549 #ifdef FEAT_MENU 3550 - gui.menu_height 3551 #endif 3552 - 30; 3553 } 3554 3555 void 3556 gui_mch_set_text_area_pos( 3557 int x, 3558 int y, 3559 int w, 3560 int h) 3561 { 3562 if (!gui.vimTextArea) 3563 return; 3564 3565 if (gui.vimWindow->Lock()) { 3566 gui.vimTextArea->MoveTo(x, y); 3567 gui.vimTextArea->ResizeTo(w - PEN_WIDTH, h - PEN_WIDTH); 3568 3569 #ifdef FEAT_GUI_TABLINE 3570 if (gui.vimForm->TabLine() != NULL) { 3571 gui.vimForm->TabLine()->ResizeTo(w, gui.vimForm->TablineHeight()); 3572 } 3573 #endif // FEAT_GUI_TABLINE 3574 3575 gui.vimWindow->Unlock(); 3576 } 3577 } 3578 3579 3580 /* 3581 * Scrollbar stuff: 3582 */ 3583 3584 void 3585 gui_mch_enable_scrollbar( 3586 scrollbar_T *sb, 3587 int flag) 3588 { 3589 VimScrollBar *vsb = sb->id; 3590 if (gui.vimWindow->Lock()) { 3591 /* 3592 * This function is supposed to be idempotent, but Show()/Hide() 3593 * is not. Therefore we test if they are needed. 3594 */ 3595 if (flag) { 3596 if (vsb->IsHidden()) { 3597 vsb->Show(); 3598 } 3599 } else { 3600 if (!vsb->IsHidden()) { 3601 vsb->Hide(); 3602 } 3603 } 3604 gui.vimWindow->Unlock(); 3605 } 3606 } 3607 3608 void 3609 gui_mch_set_scrollbar_thumb( 3610 scrollbar_T *sb, 3611 int val, 3612 int size, 3613 int max) 3614 { 3615 if (gui.vimWindow->Lock()) { 3616 VimScrollBar *s = sb->id; 3617 if (max == 0) { 3618 s->SetValue(0); 3619 s->SetRange(0.0, 0.0); 3620 } else { 3621 s->SetProportion((float)size / (max + 1.0)); 3622 s->SetSteps(1.0, size > 5 ? size - 2 : size); 3623 #ifndef SCROLL_PAST_END // really only defined in gui.c... 3624 max = max + 1 - size; 3625 #endif 3626 if (max < s->Value()) { 3627 /* 3628 * If the new maximum is lower than the current value, 3629 * setting it would cause the value to be clipped and 3630 * therefore a ValueChanged() call. 3631 * We avoid this by setting the value first, because 3632 * it presumably is <= max. 3633 */ 3634 s->SetValue(val); 3635 s->SetRange(0.0, max); 3636 } else { 3637 /* 3638 * In the other case, set the range first, since the 3639 * new value might be higher than the current max. 3640 */ 3641 s->SetRange(0.0, max); 3642 s->SetValue(val); 3643 } 3644 } 3645 gui.vimWindow->Unlock(); 3646 } 3647 } 3648 3649 void 3650 gui_mch_set_scrollbar_pos( 3651 scrollbar_T *sb, 3652 int x, 3653 int y, 3654 int w, 3655 int h) 3656 { 3657 if (gui.vimWindow->Lock()) { 3658 BRect winb = gui.vimWindow->Bounds(); 3659 float vsbx = x, vsby = y; 3660 VimScrollBar *vsb = sb->id; 3661 vsb->ResizeTo(w - PEN_WIDTH, h - PEN_WIDTH); 3662 if (winb.right-(x+w)<w) vsbx = winb.right - (w - PEN_WIDTH); 3663 vsb->MoveTo(vsbx, vsby); 3664 gui.vimWindow->Unlock(); 3665 } 3666 } 3667 3668 void 3669 gui_mch_create_scrollbar( 3670 scrollbar_T *sb, 3671 int orient) // SBAR_VERT or SBAR_HORIZ 3672 { 3673 orientation posture = 3674 (orient == SBAR_HORIZ) ? B_HORIZONTAL : B_VERTICAL; 3675 3676 VimScrollBar *vsb = sb->id = new VimScrollBar(sb, posture); 3677 if (gui.vimWindow->Lock()) { 3678 vsb->SetTarget(gui.vimTextArea); 3679 vsb->Hide(); 3680 gui.vimForm->AddChild(vsb); 3681 gui.vimWindow->Unlock(); 3682 } 3683 } 3684 3685 #if defined(FEAT_WINDOWS) || defined(FEAT_GUI_HAIKU) || defined(PROTO) 3686 void 3687 gui_mch_destroy_scrollbar( 3688 scrollbar_T *sb) 3689 { 3690 if (gui.vimWindow->Lock()) { 3691 sb->id->RemoveSelf(); 3692 delete sb->id; 3693 gui.vimWindow->Unlock(); 3694 } 3695 } 3696 #endif 3697 3698 /* 3699 * Cursor does not flash 3700 */ 3701 int 3702 gui_mch_is_blink_off(void) 3703 { 3704 return FALSE; 3705 } 3706 3707 /* 3708 * Cursor blink functions. 3709 * 3710 * This is a simple state machine: 3711 * BLINK_NONE not blinking at all 3712 * BLINK_OFF blinking, cursor is not shown 3713 * BLINK_ON blinking, cursor is shown 3714 */ 3715 3716 #define BLINK_NONE 0 3717 #define BLINK_OFF 1 3718 #define BLINK_ON 2 3719 3720 static int blink_state = BLINK_NONE; 3721 static long_u blink_waittime = 700; 3722 static long_u blink_ontime = 400; 3723 static long_u blink_offtime = 250; 3724 static int blink_timer = 0; 3725 3726 void 3727 gui_mch_set_blinking( 3728 long waittime, 3729 long on, 3730 long off) 3731 { 3732 // TODO 3733 blink_waittime = waittime; 3734 blink_ontime = on; 3735 blink_offtime = off; 3736 } 3737 3738 /* 3739 * Stop the cursor blinking. Show the cursor if it wasn't shown. 3740 */ 3741 void 3742 gui_mch_stop_blink(int may_call_gui_update_cursor) 3743 { 3744 // TODO 3745 if (blink_timer != 0) 3746 { 3747 // XtRemoveTimeOut(blink_timer); 3748 blink_timer = 0; 3749 } 3750 if (blink_state == BLINK_OFF) 3751 gui_update_cursor(TRUE, FALSE); 3752 blink_state = BLINK_NONE; 3753 } 3754 3755 /* 3756 * Start the cursor blinking. If it was already blinking, this restarts the 3757 * waiting time and shows the cursor. 3758 */ 3759 void 3760 gui_mch_start_blink() 3761 { 3762 // TODO 3763 if (blink_timer != 0) 3764 ;// XtRemoveTimeOut(blink_timer); 3765 // Only switch blinking on if none of the times is zero 3766 if (blink_waittime && blink_ontime && blink_offtime && gui.in_focus) 3767 { 3768 blink_timer = 1; // XtAppAddTimeOut(app_context, blink_waittime, 3769 blink_state = BLINK_ON; 3770 gui_update_cursor(TRUE, FALSE); 3771 } 3772 } 3773 3774 /* 3775 * Initialise vim to use the font with the given name. Return FAIL if the font 3776 * could not be loaded, OK otherwise. 3777 */ 3778 int 3779 gui_mch_init_font( 3780 char_u *font_name, 3781 int fontset) 3782 { 3783 if (gui.vimWindow->Lock()) 3784 { 3785 int rc = gui.vimTextArea->mchInitFont(font_name); 3786 gui.vimWindow->Unlock(); 3787 3788 return rc; 3789 } 3790 3791 return FAIL; 3792 } 3793 3794 3795 int 3796 gui_mch_adjust_charsize() 3797 { 3798 return FAIL; 3799 } 3800 3801 3802 int 3803 gui_mch_font_dialog(font_family* family, font_style* style, float* size) 3804 { 3805 #if defined(FEAT_GUI_DIALOG) 3806 // gui.vimWindow->Unlock(); 3807 VimSelectFontDialog *dialog = new VimSelectFontDialog(family, style, size); 3808 return dialog->Go(); 3809 #else 3810 return NOFONT; 3811 #endif // FEAT_GUI_DIALOG 3812 } 3813 3814 3815 GuiFont 3816 gui_mch_get_font( 3817 char_u *name, 3818 int giveErrorIfMissing) 3819 { 3820 static VimFont *fontList = NULL; 3821 3822 if (!gui.in_use) // can't do this when GUI not running 3823 return NOFONT; 3824 3825 // storage for locally modified name; 3826 const int buff_size = B_FONT_FAMILY_LENGTH + B_FONT_STYLE_LENGTH + 20; 3827 static char font_name[buff_size] = {0}; 3828 font_family family = {0}; 3829 font_style style = {0}; 3830 float size = 0.f; 3831 3832 if (name == 0 && be_fixed_font == 0) { 3833 if (giveErrorIfMissing) 3834 semsg(_(e_font), name); 3835 return NOFONT; 3836 } 3837 3838 bool useSelectGUI = false; 3839 if (name != NULL) 3840 if (STRCMP(name, "*") == 0) { 3841 useSelectGUI = true; 3842 STRNCPY(font_name, hl_get_font_name(), buff_size); 3843 } else 3844 STRNCPY(font_name, name, buff_size); 3845 3846 if (font_name[0] == 0) { 3847 be_fixed_font->GetFamilyAndStyle(&family, &style); 3848 size = be_fixed_font->Size(); 3849 vim_snprintf(font_name, buff_size, 3850 (char*)"%s/%s/%.0f", family, style, size); 3851 } 3852 3853 // replace underscores with spaces 3854 char* end = 0; 3855 while (end = strchr((char *)font_name, '_')) 3856 *end = ' '; 3857 3858 // store the name before strtok corrupt the buffer ;-) 3859 static char buff[buff_size] = {0}; 3860 STRNCPY(buff, font_name, buff_size); 3861 STRNCPY(family, strtok(buff, "/\0"), B_FONT_FAMILY_LENGTH); 3862 char* style_s = strtok(0, "/\0"); 3863 if (style_s != 0) 3864 STRNCPY(style, style_s, B_FONT_STYLE_LENGTH); 3865 size = atof((style_s != 0) ? strtok(0, "/\0") : "0"); 3866 3867 if (useSelectGUI) { 3868 if (gui_mch_font_dialog(&family, &style, &size) == NOFONT) 3869 return FAIL; 3870 // compose for further processing 3871 vim_snprintf(font_name, buff_size, 3872 (char*)"%s/%s/%.0f", family, style, size); 3873 hl_set_font_name((char_u*)font_name); 3874 3875 // Set guifont to the name of the selected font. 3876 char_u* new_p_guifont = (char_u*)alloc(STRLEN(font_name) + 1); 3877 if (new_p_guifont != NULL) { 3878 STRCPY(new_p_guifont, font_name); 3879 vim_free(p_guifont); 3880 p_guifont = new_p_guifont; 3881 // Replace spaces in the font name with underscores. 3882 for ( ; *new_p_guifont; ++new_p_guifont) 3883 if (*new_p_guifont == ' ') 3884 *new_p_guifont = '_'; 3885 } 3886 } 3887 3888 VimFont *flp; 3889 for (flp = fontList; flp; flp = flp->next) { 3890 if (STRCMP(font_name, flp->name) == 0) { 3891 flp->refcount++; 3892 return (GuiFont)flp; 3893 } 3894 } 3895 3896 VimFont *font = new VimFont(); 3897 font->name = vim_strsave((char_u*)font_name); 3898 3899 if (count_font_styles(family) <= 0) { 3900 if (giveErrorIfMissing) 3901 semsg(_(e_font), font->name); 3902 delete font; 3903 return NOFONT; 3904 } 3905 3906 // Remember font in the static list for later use 3907 font->next = fontList; 3908 fontList = font; 3909 3910 font->SetFamilyAndStyle(family, style); 3911 if (size > 0.f) 3912 font->SetSize(size); 3913 3914 font->SetSpacing(B_FIXED_SPACING); 3915 font->SetEncoding(B_UNICODE_UTF8); 3916 3917 return (GuiFont)font; 3918 } 3919 3920 /* 3921 * Set the current text font. 3922 */ 3923 void 3924 gui_mch_set_font( 3925 GuiFont font) 3926 { 3927 if (gui.vimWindow->Lock()) { 3928 VimFont *vf = (VimFont *)font; 3929 3930 gui.vimTextArea->SetFont(vf); 3931 3932 gui.char_width = (int) vf->StringWidth("n"); 3933 font_height fh; 3934 vf->GetHeight(&fh); 3935 gui.char_height = (int)(fh.ascent + 0.9999) 3936 + (int)(fh.descent + 0.9999) + (int)(fh.leading + 0.9999); 3937 gui.char_ascent = (int)(fh.ascent + 0.9999); 3938 3939 gui.vimWindow->Unlock(); 3940 } 3941 } 3942 3943 // XXX TODO This is apparently never called... 3944 void 3945 gui_mch_free_font( 3946 GuiFont font) 3947 { 3948 if (font == NOFONT) 3949 return; 3950 VimFont *f = (VimFont *)font; 3951 if (--f->refcount <= 0) { 3952 if (f->refcount < 0) 3953 fprintf(stderr, "VimFont: refcount < 0\n"); 3954 delete f; 3955 } 3956 } 3957 3958 char_u * 3959 gui_mch_get_fontname(GuiFont font, char_u *name) 3960 { 3961 if (name == NULL) 3962 return NULL; 3963 return vim_strsave(name); 3964 } 3965 3966 /* 3967 * Adjust gui.char_height (after 'linespace' was changed). 3968 */ 3969 int 3970 gui_mch_adjust_charheight() 3971 { 3972 3973 // TODO: linespace support? 3974 3975 // #ifdef FEAT_XFONTSET 3976 // if (gui.fontset != NOFONTSET) 3977 // { 3978 // gui.char_height = fontset_height((XFontSet)gui.fontset) + p_linespace; 3979 // gui.char_ascent = fontset_ascent((XFontSet)gui.fontset) 3980 // + p_linespace / 2; 3981 // } 3982 // else 3983 // #endif 3984 { 3985 VimFont *font = (VimFont *)gui.norm_font; 3986 font_height fh = {0}; 3987 font->GetHeight(&fh); 3988 gui.char_height = (int)(fh.ascent + fh.descent + 0.5) + p_linespace; 3989 gui.char_ascent = (int)(fh.ascent + 0.5) + p_linespace / 2; 3990 } 3991 return OK; 3992 } 3993 3994 void 3995 gui_mch_getmouse(int *x, int *y) 3996 { 3997 fprintf(stderr, "gui_mch_getmouse"); 3998 3999 /*int rootx, rooty, winx, winy; 4000 Window root, child; 4001 unsigned int mask; 4002 4003 if (gui.wid && XQueryPointer(gui.dpy, gui.wid, &root, &child, 4004 &rootx, &rooty, &winx, &winy, &mask)) { 4005 *x = winx; 4006 *y = winy; 4007 } else*/ { 4008 *x = -1; 4009 *y = -1; 4010 } 4011 } 4012 4013 void 4014 gui_mch_mousehide(int hide) 4015 { 4016 fprintf(stderr, "gui_mch_getmouse"); 4017 // TODO 4018 } 4019 4020 static int 4021 hex_digit(int c) 4022 { 4023 if (isdigit(c)) 4024 return c - '0'; 4025 c = TOLOWER_ASC(c); 4026 if (c >= 'a' && c <= 'f') 4027 return c - 'a' + 10; 4028 return -1000; 4029 } 4030 4031 /* 4032 * This function has been lifted from gui_w32.c and extended a bit. 4033 * 4034 * Return the Pixel value (color) for the given color name. 4035 * Return INVALCOLOR for error. 4036 */ 4037 guicolor_T 4038 gui_mch_get_color( 4039 char_u *name) 4040 { 4041 typedef struct GuiColourTable 4042 { 4043 const char *name; 4044 guicolor_T colour; 4045 } GuiColourTable; 4046 4047 #define NSTATIC_COLOURS 50 // 32 4048 #define NDYNAMIC_COLOURS 33 4049 #define NCOLOURS (NSTATIC_COLOURS + NDYNAMIC_COLOURS) 4050 4051 static GuiColourTable table[NCOLOURS] = 4052 { 4053 {"Black", RGB(0x00, 0x00, 0x00)}, 4054 {"DarkGray", RGB(0x80, 0x80, 0x80)}, 4055 {"DarkGrey", RGB(0x80, 0x80, 0x80)}, 4056 {"Gray", RGB(0xC0, 0xC0, 0xC0)}, 4057 {"Grey", RGB(0xC0, 0xC0, 0xC0)}, 4058 {"LightGray", RGB(0xD3, 0xD3, 0xD3)}, 4059 {"LightGrey", RGB(0xD3, 0xD3, 0xD3)}, 4060 {"Gray10", RGB(0x1A, 0x1A, 0x1A)}, 4061 {"Grey10", RGB(0x1A, 0x1A, 0x1A)}, 4062 {"Gray20", RGB(0x33, 0x33, 0x33)}, 4063 {"Grey20", RGB(0x33, 0x33, 0x33)}, 4064 {"Gray30", RGB(0x4D, 0x4D, 0x4D)}, 4065 {"Grey30", RGB(0x4D, 0x4D, 0x4D)}, 4066 {"Gray40", RGB(0x66, 0x66, 0x66)}, 4067 {"Grey40", RGB(0x66, 0x66, 0x66)}, 4068 {"Gray50", RGB(0x7F, 0x7F, 0x7F)}, 4069 {"Grey50", RGB(0x7F, 0x7F, 0x7F)}, 4070 {"Gray60", RGB(0x99, 0x99, 0x99)}, 4071 {"Grey60", RGB(0x99, 0x99, 0x99)}, 4072 {"Gray70", RGB(0xB3, 0xB3, 0xB3)}, 4073 {"Grey70", RGB(0xB3, 0xB3, 0xB3)}, 4074 {"Gray80", RGB(0xCC, 0xCC, 0xCC)}, 4075 {"Grey80", RGB(0xCC, 0xCC, 0xCC)}, 4076 {"Gray90", RGB(0xE5, 0xE5, 0xE5)}, 4077 {"Grey90", RGB(0xE5, 0xE5, 0xE5)}, 4078 {"White", RGB(0xFF, 0xFF, 0xFF)}, 4079 {"DarkRed", RGB(0x80, 0x00, 0x00)}, 4080 {"Red", RGB(0xFF, 0x00, 0x00)}, 4081 {"LightRed", RGB(0xFF, 0xA0, 0xA0)}, 4082 {"DarkBlue", RGB(0x00, 0x00, 0x80)}, 4083 {"Blue", RGB(0x00, 0x00, 0xFF)}, 4084 {"LightBlue", RGB(0xA0, 0xA0, 0xFF)}, 4085 {"DarkGreen", RGB(0x00, 0x80, 0x00)}, 4086 {"Green", RGB(0x00, 0xFF, 0x00)}, 4087 {"LightGreen", RGB(0xA0, 0xFF, 0xA0)}, 4088 {"DarkCyan", RGB(0x00, 0x80, 0x80)}, 4089 {"Cyan", RGB(0x00, 0xFF, 0xFF)}, 4090 {"LightCyan", RGB(0xA0, 0xFF, 0xFF)}, 4091 {"DarkMagenta", RGB(0x80, 0x00, 0x80)}, 4092 {"Magenta", RGB(0xFF, 0x00, 0xFF)}, 4093 {"LightMagenta", RGB(0xFF, 0xA0, 0xFF)}, 4094 {"Brown", RGB(0x80, 0x40, 0x40)}, 4095 {"Yellow", RGB(0xFF, 0xFF, 0x00)}, 4096 {"LightYellow", RGB(0xFF, 0xFF, 0xA0)}, 4097 {"DarkYellow", RGB(0xBB, 0xBB, 0x00)}, 4098 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, 4099 {"Orange", RGB(0xFF, 0xA5, 0x00)}, 4100 {"Purple", RGB(0xA0, 0x20, 0xF0)}, 4101 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, 4102 {"Violet", RGB(0xEE, 0x82, 0xEE)}, 4103 // NOTE: some entries are zero-allocated for NDDYNAMIC_COLORS 4104 // in this table! 4105 }; 4106 4107 static int endColour = NSTATIC_COLOURS; 4108 static int newColour = NSTATIC_COLOURS; 4109 4110 int r, g, b; 4111 int i; 4112 4113 if (name[0] == '#' && STRLEN(name) == 7) 4114 { 4115 // Name is in "#rrggbb" format 4116 r = hex_digit(name[1]) * 16 + hex_digit(name[2]); 4117 g = hex_digit(name[3]) * 16 + hex_digit(name[4]); 4118 b = hex_digit(name[5]) * 16 + hex_digit(name[6]); 4119 if (r < 0 || g < 0 || b < 0) 4120 return INVALCOLOR; 4121 return RGB(r, g, b); 4122 } 4123 else 4124 { 4125 // Check if the name is one of the colours we know 4126 for (i = 0; i < endColour; i++) 4127 if (STRICMP(name, table[i].name) == 0) 4128 return table[i].colour; 4129 } 4130 4131 /* 4132 * Last attempt. Look in the file "$VIMRUNTIME/rgb.txt". 4133 */ 4134 { 4135 #define LINE_LEN 100 4136 FILE *fd; 4137 char line[LINE_LEN]; 4138 char_u *fname; 4139 4140 fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt"); 4141 if (fname == NULL) 4142 return INVALCOLOR; 4143 4144 fd = fopen((char *)fname, "rt"); 4145 vim_free(fname); 4146 if (fd == NULL) 4147 return INVALCOLOR; 4148 4149 while (!feof(fd)) 4150 { 4151 int len; 4152 int pos; 4153 char *colour; 4154 4155 fgets(line, LINE_LEN, fd); 4156 len = strlen(line); 4157 4158 if (len <= 1 || line[len-1] != '\n') 4159 continue; 4160 4161 line[len-1] = '\0'; 4162 4163 i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos); 4164 if (i != 3) 4165 continue; 4166 4167 colour = line + pos; 4168 4169 if (STRICMP(colour, name) == 0) 4170 { 4171 fclose(fd); 4172 /* 4173 * Now remember this colour in the table. 4174 * A LRU scheme might be better but this is simpler. 4175 * Or could use a growing array. 4176 */ 4177 guicolor_T gcolour = RGB(r,g,b); 4178 4179 // NOTE: see note above in table allocation! We are working here with 4180 // dynamically allocated names, not constant ones! 4181 vim_free((char*)table[newColour].name); 4182 table[newColour].name = (char *)vim_strsave((char_u *)colour); 4183 table[newColour].colour = gcolour; 4184 4185 newColour++; 4186 if (newColour >= NCOLOURS) 4187 newColour = NSTATIC_COLOURS; 4188 if (endColour < NCOLOURS) 4189 endColour = newColour; 4190 4191 return gcolour; 4192 } 4193 } 4194 4195 fclose(fd); 4196 } 4197 4198 return INVALCOLOR; 4199 } 4200 4201 /* 4202 * Set the current text foreground color. 4203 */ 4204 void 4205 gui_mch_set_fg_color( 4206 guicolor_T color) 4207 { 4208 rgb_color rgb = GUI_TO_RGB(color); 4209 if (gui.vimWindow->Lock()) { 4210 gui.vimTextArea->SetHighColor(rgb); 4211 gui.vimWindow->Unlock(); 4212 } 4213 } 4214 4215 /* 4216 * Set the current text background color. 4217 */ 4218 void 4219 gui_mch_set_bg_color( 4220 guicolor_T color) 4221 { 4222 rgb_color rgb = GUI_TO_RGB(color); 4223 if (gui.vimWindow->Lock()) { 4224 gui.vimTextArea->SetLowColor(rgb); 4225 gui.vimWindow->Unlock(); 4226 } 4227 } 4228 4229 /* 4230 * Set the current text special color. 4231 */ 4232 void 4233 gui_mch_set_sp_color(guicolor_T color) 4234 { 4235 // prev_sp_color = color; 4236 } 4237 4238 void 4239 gui_mch_draw_string( 4240 int row, 4241 int col, 4242 char_u *s, 4243 int len, 4244 int flags) 4245 { 4246 if (gui.vimWindow->Lock()) { 4247 gui.vimTextArea->mchDrawString(row, col, s, len, flags); 4248 gui.vimWindow->Unlock(); 4249 } 4250 } 4251 4252 guicolor_T 4253 gui_mch_get_rgb_color(int r, int g, int b) 4254 { 4255 return gui_get_rgb_color_cmn(r, g, b); 4256 } 4257 4258 4259 // Return OK if the key with the termcap name "name" is supported. 4260 int 4261 gui_mch_haskey( 4262 char_u *name) 4263 { 4264 int i; 4265 4266 for (i = 0; special_keys[i].BeKeys != 0; i++) 4267 if (name[0] == special_keys[i].vim_code0 && 4268 name[1] == special_keys[i].vim_code1) 4269 return OK; 4270 return FAIL; 4271 } 4272 4273 void 4274 gui_mch_beep() 4275 { 4276 ::beep(); 4277 } 4278 4279 void 4280 gui_mch_flash(int msec) 4281 { 4282 // Do a visual beep by reversing the foreground and background colors 4283 4284 if (gui.vimWindow->Lock()) { 4285 BRect rect = gui.vimTextArea->Bounds(); 4286 4287 gui.vimTextArea->SetDrawingMode(B_OP_INVERT); 4288 gui.vimTextArea->FillRect(rect); 4289 gui.vimTextArea->Sync(); 4290 snooze(msec * 1000); // wait for a few msec 4291 gui.vimTextArea->FillRect(rect); 4292 gui.vimTextArea->SetDrawingMode(B_OP_COPY); 4293 gui.vimTextArea->Flush(); 4294 gui.vimWindow->Unlock(); 4295 } 4296 } 4297 4298 /* 4299 * Invert a rectangle from row r, column c, for nr rows and nc columns. 4300 */ 4301 void 4302 gui_mch_invert_rectangle( 4303 int r, 4304 int c, 4305 int nr, 4306 int nc) 4307 { 4308 BRect rect; 4309 rect.left = FILL_X(c); 4310 rect.top = FILL_Y(r); 4311 rect.right = rect.left + nc * gui.char_width - PEN_WIDTH; 4312 rect.bottom = rect.top + nr * gui.char_height - PEN_WIDTH; 4313 4314 if (gui.vimWindow->Lock()) { 4315 gui.vimTextArea->SetDrawingMode(B_OP_INVERT); 4316 gui.vimTextArea->FillRect(rect); 4317 gui.vimTextArea->SetDrawingMode(B_OP_COPY); 4318 gui.vimWindow->Unlock(); 4319 } 4320 } 4321 4322 /* 4323 * Iconify the GUI window. 4324 */ 4325 void 4326 gui_mch_iconify() 4327 { 4328 if (gui.vimWindow->Lock()) { 4329 gui.vimWindow->Minimize(true); 4330 gui.vimWindow->Unlock(); 4331 } 4332 } 4333 4334 #if defined(FEAT_EVAL) || defined(PROTO) 4335 /* 4336 * Bring the Vim window to the foreground. 4337 */ 4338 void 4339 gui_mch_set_foreground(void) 4340 { 4341 // TODO 4342 } 4343 #endif 4344 4345 /* 4346 * Set the window title 4347 */ 4348 void 4349 gui_mch_settitle( 4350 char_u *title, 4351 char_u *icon) 4352 { 4353 if (gui.vimWindow->Lock()) { 4354 gui.vimWindow->SetTitle((char *)title); 4355 gui.vimWindow->Unlock(); 4356 } 4357 } 4358 4359 /* 4360 * Draw a cursor without focus. 4361 */ 4362 void 4363 gui_mch_draw_hollow_cursor(guicolor_T color) 4364 { 4365 gui_mch_set_fg_color(color); 4366 4367 BRect r; 4368 r.left = FILL_X(gui.col); 4369 r.top = FILL_Y(gui.row); 4370 int cells = utf_off2cells(LineOffset[gui.row] + gui.col, 100); // TODO-TODO 4371 if (cells>=4) cells = 1; 4372 r.right = r.left + cells*gui.char_width - PEN_WIDTH; 4373 r.bottom = r.top + gui.char_height - PEN_WIDTH; 4374 4375 if (gui.vimWindow->Lock()) { 4376 gui.vimTextArea->StrokeRect(r); 4377 gui.vimWindow->Unlock(); 4378 // gui_mch_flush(); 4379 } 4380 } 4381 4382 /* 4383 * Draw part of a cursor, only w pixels wide, and h pixels high. 4384 */ 4385 void 4386 gui_mch_draw_part_cursor( 4387 int w, 4388 int h, 4389 guicolor_T color) 4390 { 4391 gui_mch_set_fg_color(color); 4392 4393 BRect r; 4394 r.left = 4395 #ifdef FEAT_RIGHTLEFT 4396 // vertical line should be on the right of current point 4397 CURSOR_BAR_RIGHT ? FILL_X(gui.col + 1) - w : 4398 #endif 4399 FILL_X(gui.col); 4400 r.right = r.left + w - PEN_WIDTH; 4401 r.bottom = FILL_Y(gui.row + 1) - PEN_WIDTH; 4402 r.top = r.bottom - h + PEN_WIDTH; 4403 4404 if (gui.vimWindow->Lock()) { 4405 gui.vimTextArea->FillRect(r); 4406 gui.vimWindow->Unlock(); 4407 // gui_mch_flush(); 4408 } 4409 } 4410 4411 /* 4412 * Catch up with any queued events. This may put keyboard input into the 4413 * input buffer, call resize call-backs, trigger timers etc. If there is 4414 * nothing in the event queue (& no timers pending), then we return 4415 * immediately. 4416 */ 4417 void 4418 gui_mch_update() 4419 { 4420 gui_mch_flush(); 4421 while (port_count(gui.vdcmp) > 0 && 4422 !vim_is_input_buf_full() && 4423 gui_haiku_process_event(0) >= B_OK) 4424 /* nothing */ ; 4425 } 4426 4427 /* 4428 * GUI input routine called by gui_wait_for_chars(). Waits for a character 4429 * from the keyboard. 4430 * wtime == -1 Wait forever. 4431 * wtime == 0 This should never happen. 4432 * wtime > 0 Wait wtime milliseconds for a character. 4433 * Returns OK if a character was found to be available within the given time, 4434 * or FAIL otherwise. 4435 */ 4436 int 4437 gui_mch_wait_for_chars( 4438 int wtime) 4439 { 4440 int focus; 4441 bigtime_t until, timeout; 4442 status_t st; 4443 4444 if (wtime >= 0) 4445 { 4446 timeout = wtime * 1000; 4447 until = system_time() + timeout; 4448 } 4449 else 4450 timeout = B_INFINITE_TIMEOUT; 4451 4452 focus = gui.in_focus; 4453 for (;;) 4454 { 4455 // Stop or start blinking when focus changes 4456 if (gui.in_focus != focus) 4457 { 4458 if (gui.in_focus) 4459 gui_mch_start_blink(); 4460 else 4461 gui_mch_stop_blink(TRUE); 4462 focus = gui.in_focus; 4463 } 4464 4465 gui_mch_flush(); 4466 4467 #ifdef MESSAGE_QUEUE 4468 # ifdef FEAT_TIMERS 4469 did_add_timer = FALSE; 4470 # endif 4471 parse_queued_messages(); 4472 # ifdef FEAT_TIMERS 4473 if (did_add_timer) 4474 // Need to recompute the waiting time. 4475 break; 4476 # endif 4477 # ifdef FEAT_JOB_CHANNEL 4478 if (has_any_channel()) 4479 { 4480 if (wtime < 0 || timeout > 20000) 4481 timeout = 20000; 4482 } 4483 else if (wtime < 0) 4484 timeout = B_INFINITE_TIMEOUT; 4485 # endif 4486 #endif 4487 4488 /* 4489 * Don't use gui_mch_update() because then we will spin-lock until a 4490 * char arrives, instead we use gui_haiku_process_event() to hang until 4491 * an event arrives. No need to check for input_buf_full because we 4492 * are returning as soon as it contains a single char. 4493 */ 4494 st = gui_haiku_process_event(timeout); 4495 4496 if (input_available()) 4497 return OK; 4498 if (st < B_OK) // includes B_TIMED_OUT 4499 return FAIL; 4500 4501 /* 4502 * Calculate how much longer we're willing to wait for the 4503 * next event. 4504 */ 4505 if (wtime >= 0) 4506 { 4507 timeout = until - system_time(); 4508 if (timeout < 0) 4509 break; 4510 } 4511 } 4512 return FAIL; 4513 4514 } 4515 4516 /* 4517 * Output routines. 4518 */ 4519 4520 /* 4521 * Flush any output to the screen. This is typically called before 4522 * the app goes to sleep. 4523 */ 4524 void 4525 gui_mch_flush() 4526 { 4527 // does this need to lock the window? Apparently not but be safe. 4528 if (gui.vimWindow->Lock()) { 4529 gui.vimWindow->Flush(); 4530 gui.vimWindow->Unlock(); 4531 } 4532 return; 4533 } 4534 4535 /* 4536 * Clear a rectangular region of the screen from text pos (row1, col1) to 4537 * (row2, col2) inclusive. 4538 */ 4539 void 4540 gui_mch_clear_block( 4541 int row1, 4542 int col1, 4543 int row2, 4544 int col2) 4545 { 4546 if (gui.vimWindow->Lock()) { 4547 gui.vimTextArea->mchClearBlock(row1, col1, row2, col2); 4548 gui.vimWindow->Unlock(); 4549 } 4550 } 4551 4552 void 4553 gui_mch_clear_all() 4554 { 4555 if (gui.vimWindow->Lock()) { 4556 gui.vimTextArea->mchClearAll(); 4557 gui.vimWindow->Unlock(); 4558 } 4559 } 4560 4561 /* 4562 * Delete the given number of lines from the given row, scrolling up any 4563 * text further down within the scroll region. 4564 */ 4565 void 4566 gui_mch_delete_lines( 4567 int row, 4568 int num_lines) 4569 { 4570 gui.vimTextArea->mchDeleteLines(row, num_lines); 4571 } 4572 4573 /* 4574 * Insert the given number of lines before the given row, scrolling down any 4575 * following text within the scroll region. 4576 */ 4577 void 4578 gui_mch_insert_lines( 4579 int row, 4580 int num_lines) 4581 { 4582 gui.vimTextArea->mchInsertLines(row, num_lines); 4583 } 4584 4585 #if defined(FEAT_MENU) || defined(PROTO) 4586 /* 4587 * Menu stuff. 4588 */ 4589 4590 void 4591 gui_mch_enable_menu( 4592 int flag) 4593 { 4594 if (gui.vimWindow->Lock()) 4595 { 4596 BMenuBar *menubar = gui.vimForm->MenuBar(); 4597 menubar->SetEnabled(flag); 4598 gui.vimWindow->Unlock(); 4599 } 4600 } 4601 4602 void 4603 gui_mch_set_menu_pos( 4604 int x, 4605 int y, 4606 int w, 4607 int h) 4608 { 4609 // It will be in the right place anyway 4610 } 4611 4612 /* 4613 * Add a sub menu to the menu bar. 4614 */ 4615 void 4616 gui_mch_add_menu( 4617 vimmenu_T *menu, 4618 int idx) 4619 { 4620 vimmenu_T *parent = menu->parent; 4621 4622 // popup menu - just create it unattached 4623 if (menu_is_popup(menu->name) && parent == NULL) { 4624 BPopUpMenu* popUpMenu = new BPopUpMenu((const char*)menu->name, false, false); 4625 menu->submenu_id = popUpMenu; 4626 menu->id = NULL; 4627 return; 4628 } 4629 4630 if (!menu_is_menubar(menu->name) 4631 || (parent != NULL && parent->submenu_id == NULL)) 4632 return; 4633 4634 if (gui.vimWindow->Lock()) 4635 { 4636 // Major re-write of the menu code, it was failing with memory corruption when 4637 // we started loading multiple files (the Buffer menu) 4638 // 4639 // Note we don't use the preference values yet, all are inserted into the 4640 // menubar on a first come-first served basis... 4641 // 4642 // [email protected] jul 99 4643 4644 BMenu *tmp; 4645 4646 if ( parent ) 4647 tmp = parent->submenu_id; 4648 else 4649 tmp = gui.vimForm->MenuBar(); 4650 // make sure we don't try and add the same menu twice. The Buffers menu tries to 4651 // do this and Be starts to crash... 4652 4653 if ( ! tmp->FindItem((const char *) menu->dname)) { 4654 4655 BMenu *bmenu = new BMenu((char *)menu->dname); 4656 4657 menu->submenu_id = bmenu; 4658 4659 // when we add a BMenu to another Menu, it creates the interconnecting BMenuItem 4660 tmp->AddItem(bmenu); 4661 4662 // Now its safe to query the menu for the associated MenuItem.... 4663 menu->id = tmp->FindItem((const char *) menu->dname); 4664 4665 } 4666 gui.vimWindow->Unlock(); 4667 } 4668 } 4669 4670 void 4671 gui_mch_toggle_tearoffs(int enable) 4672 { 4673 // no tearoff menus 4674 } 4675 4676 static BMessage * 4677 MenuMessage(vimmenu_T *menu) 4678 { 4679 BMessage *m = new BMessage('menu'); 4680 m->AddPointer("VimMenu", (void *)menu); 4681 4682 return m; 4683 } 4684 4685 /* 4686 * Add a menu item to a menu 4687 */ 4688 void 4689 gui_mch_add_menu_item( 4690 vimmenu_T *menu, 4691 int idx) 4692 { 4693 int mnemonic = 0; 4694 vimmenu_T *parent = menu->parent; 4695 4696 // TODO: use menu->actext 4697 // This is difficult, since on Be, an accelerator must be a single char 4698 // and a lot of Vim ones are the standard VI commands. 4699 // 4700 // Punt for Now... 4701 // [email protected] jul 99 4702 if (gui.vimWindow->Lock()) 4703 { 4704 #ifdef FEAT_TOOLBAR 4705 if (menu_is_toolbar(parent->name)) { 4706 VimToolbar *toolbar = gui.vimForm->ToolBar(); 4707 if (toolbar != NULL) { 4708 toolbar->AddButton(idx, menu); 4709 } 4710 } else 4711 #endif 4712 4713 if (parent->submenu_id != NULL || menu_is_popup(parent->name)) { 4714 if (menu_is_separator(menu->name)) { 4715 BSeparatorItem *item = new BSeparatorItem(); 4716 parent->submenu_id->AddItem(item); 4717 menu->id = item; 4718 menu->submenu_id = NULL; 4719 } 4720 else { 4721 BMenuItem *item = new BMenuItem((char *)menu->dname, 4722 MenuMessage(menu)); 4723 item->SetTarget(gui.vimTextArea); 4724 item->SetTrigger((char) menu->mnemonic); 4725 parent->submenu_id->AddItem(item); 4726 menu->id = item; 4727 menu->submenu_id = NULL; 4728 } 4729 } 4730 gui.vimWindow->Unlock(); 4731 } 4732 } 4733 4734 /* 4735 * Destroy the machine specific menu widget. 4736 */ 4737 void 4738 gui_mch_destroy_menu( 4739 vimmenu_T *menu) 4740 { 4741 if (gui.vimWindow->Lock()) 4742 { 4743 #ifdef FEAT_TOOLBAR 4744 if (menu->parent && menu_is_toolbar(menu->parent->name)) { 4745 VimToolbar *toolbar = gui.vimForm->ToolBar(); 4746 if (toolbar != NULL) { 4747 toolbar->RemoveButton(menu); 4748 } 4749 } else 4750 #endif 4751 { 4752 assert(menu->submenu_id == NULL || menu->submenu_id->CountItems() == 0); 4753 /* 4754 * Detach this menu from its parent, so that it is not deleted 4755 * twice once we get to delete that parent. 4756 * Deleting a BMenuItem also deletes the associated BMenu, if any 4757 * (which does not have any items anymore since they were 4758 * removed and deleted before). 4759 */ 4760 BMenu *bmenu = menu->id->Menu(); 4761 if (bmenu) 4762 { 4763 bmenu->RemoveItem(menu->id); 4764 /* 4765 * If we removed the last item from the menu bar, 4766 * resize it out of sight. 4767 */ 4768 if (bmenu == gui.vimForm->MenuBar() && bmenu->CountItems() == 0) 4769 { 4770 bmenu->ResizeTo(-MENUBAR_MARGIN, -MENUBAR_MARGIN); 4771 } 4772 } 4773 delete menu->id; 4774 menu->id = NULL; 4775 menu->submenu_id = NULL; 4776 4777 gui.menu_height = (int) gui.vimForm->MenuHeight(); 4778 } 4779 gui.vimWindow->Unlock(); 4780 } 4781 } 4782 4783 /* 4784 * Make a menu either grey or not grey. 4785 */ 4786 void 4787 gui_mch_menu_grey( 4788 vimmenu_T *menu, 4789 int grey) 4790 { 4791 #ifdef FEAT_TOOLBAR 4792 if (menu->parent && menu_is_toolbar(menu->parent->name)) { 4793 if (gui.vimWindow->Lock()) { 4794 VimToolbar *toolbar = gui.vimForm->ToolBar(); 4795 if (toolbar != NULL) { 4796 toolbar->GrayButton(menu, grey); 4797 } 4798 gui.vimWindow->Unlock(); 4799 } 4800 } else 4801 #endif 4802 if (menu->id != NULL) 4803 menu->id->SetEnabled(!grey); 4804 } 4805 4806 /* 4807 * Make menu item hidden or not hidden 4808 */ 4809 void 4810 gui_mch_menu_hidden( 4811 vimmenu_T *menu, 4812 int hidden) 4813 { 4814 if (menu->id != NULL) 4815 menu->id->SetEnabled(!hidden); 4816 } 4817 4818 /* 4819 * This is called after setting all the menus to grey/hidden or not. 4820 */ 4821 void 4822 gui_mch_draw_menubar() 4823 { 4824 // Nothing to do in BeOS 4825 } 4826 4827 void 4828 gui_mch_show_popupmenu(vimmenu_T *menu) 4829 { 4830 if (!menu_is_popup(menu->name) || menu->submenu_id == NULL) 4831 return; 4832 4833 BPopUpMenu* popupMenu = dynamic_cast<BPopUpMenu*>(menu->submenu_id); 4834 if (popupMenu == NULL) 4835 return; 4836 4837 BPoint point; 4838 if (gui.vimWindow->Lock()) { 4839 uint32 buttons = 0; 4840 gui.vimTextArea->GetMouse(&point, &buttons); 4841 gui.vimTextArea->ConvertToScreen(&point); 4842 gui.vimWindow->Unlock(); 4843 } 4844 popupMenu->Go(point, true); 4845 } 4846 4847 #endif // FEAT_MENU 4848 4849 // Mouse stuff 4850 4851 #ifdef FEAT_CLIPBOARD 4852 /* 4853 * Clipboard stuff, for cutting and pasting text to other windows. 4854 */ 4855 char textplain[] = "text/plain"; 4856 char vimselectiontype[] = "application/x-vnd.Rhialto-Vim-selectiontype"; 4857 4858 /* 4859 * Get the current selection and put it in the clipboard register. 4860 */ 4861 void 4862 clip_mch_request_selection(Clipboard_T *cbd) 4863 { 4864 if (be_clipboard->Lock()) 4865 { 4866 BMessage *m = be_clipboard->Data(); 4867 // m->PrintToStream(); 4868 4869 char_u *string = NULL; 4870 ssize_t stringlen = -1; 4871 4872 if (m->FindData(textplain, B_MIME_TYPE, 4873 (const void **)&string, &stringlen) == B_OK 4874 || m->FindString("text", (const char **)&string) == B_OK) 4875 { 4876 if (stringlen == -1) 4877 stringlen = STRLEN(string); 4878 4879 int type; 4880 char *seltype; 4881 ssize_t seltypelen; 4882 4883 /* 4884 * Try to get the special vim selection type first 4885 */ 4886 if (m->FindData(vimselectiontype, B_MIME_TYPE, 4887 (const void **)&seltype, &seltypelen) == B_OK) 4888 { 4889 switch (*seltype) 4890 { 4891 default: 4892 case 'L': type = MLINE; break; 4893 case 'C': type = MCHAR; break; 4894 #ifdef FEAT_VISUAL 4895 case 'B': type = MBLOCK; break; 4896 #endif 4897 } 4898 } 4899 else 4900 { 4901 // Otherwise use heuristic as documented 4902 type = memchr(string, stringlen, '\n') ? MLINE : MCHAR; 4903 } 4904 clip_yank_selection(type, string, (long)stringlen, cbd); 4905 } 4906 be_clipboard->Unlock(); 4907 } 4908 } 4909 /* 4910 * Make vim the owner of the current selection. 4911 */ 4912 void 4913 clip_mch_lose_selection(Clipboard_T *cbd) 4914 { 4915 // Nothing needs to be done here 4916 } 4917 4918 /* 4919 * Make vim the owner of the current selection. Return OK upon success. 4920 */ 4921 int 4922 clip_mch_own_selection(Clipboard_T *cbd) 4923 { 4924 /* 4925 * Never actually own the clipboard. If another application sets the 4926 * clipboard, we don't want to think that we still own it. 4927 */ 4928 return FAIL; 4929 } 4930 4931 /* 4932 * Send the current selection to the clipboard. 4933 */ 4934 void 4935 clip_mch_set_selection(Clipboard_T *cbd) 4936 { 4937 if (be_clipboard->Lock()) 4938 { 4939 be_clipboard->Clear(); 4940 BMessage *m = be_clipboard->Data(); 4941 assert(m); 4942 4943 // If the '*' register isn't already filled in, fill it in now 4944 cbd->owned = TRUE; 4945 clip_get_selection(cbd); 4946 cbd->owned = FALSE; 4947 4948 char_u *str = NULL; 4949 long_u count; 4950 int type; 4951 4952 type = clip_convert_selection(&str, &count, cbd); 4953 4954 if (type < 0) 4955 return; 4956 4957 m->AddData(textplain, B_MIME_TYPE, (void *)str, count); 4958 4959 // Add type of selection 4960 char vtype; 4961 switch (type) 4962 { 4963 default: 4964 case MLINE: vtype = 'L'; break; 4965 case MCHAR: vtype = 'C'; break; 4966 #ifdef FEAT_VISUAL 4967 case MBLOCK: vtype = 'B'; break; 4968 #endif 4969 } 4970 m->AddData(vimselectiontype, B_MIME_TYPE, (void *)&vtype, 1); 4971 4972 vim_free(str); 4973 4974 be_clipboard->Commit(); 4975 be_clipboard->Unlock(); 4976 } 4977 } 4978 4979 #endif // FEAT_CLIPBOARD 4980 4981 #ifdef FEAT_BROWSE 4982 /* 4983 * Pop open a file browser and return the file selected, in allocated memory, 4984 * or NULL if Cancel is hit. 4985 * saving - TRUE if the file will be saved to, FALSE if it will be opened. 4986 * title - Title message for the file browser dialog. 4987 * dflt - Default name of file. 4988 * ext - Default extension to be added to files without extensions. 4989 * initdir - directory in which to open the browser (NULL = current dir) 4990 * filter - Filter for matched files to choose from. 4991 * Has a format like this: 4992 * "C Files (*.c)\0*.c\0" 4993 * "All Files\0*.*\0\0" 4994 * If these two strings were concatenated, then a choice of two file 4995 * filters will be selectable to the user. Then only matching files will 4996 * be shown in the browser. If NULL, the default allows all files. 4997 * 4998 * *NOTE* - the filter string must be terminated with TWO nulls. 4999 */ 5000 char_u * 5001 gui_mch_browse( 5002 int saving, 5003 char_u *title, 5004 char_u *dflt, 5005 char_u *ext, 5006 char_u *initdir, 5007 char_u *filter) 5008 { 5009 gui.vimApp->fFilePanel = new BFilePanel((saving == TRUE) ? B_SAVE_PANEL : B_OPEN_PANEL, 5010 NULL, NULL, 0, false, 5011 new BMessage((saving == TRUE) ? 'save' : 'open'), NULL, true); 5012 5013 gui.vimApp->fBrowsedPath.Unset(); 5014 5015 gui.vimApp->fFilePanel->Window()->SetTitle((char*)title); 5016 gui.vimApp->fFilePanel->SetPanelDirectory((const char*)initdir); 5017 5018 gui.vimApp->fFilePanel->Show(); 5019 5020 gui.vimApp->fFilePanelSem = create_sem(0, "FilePanelSem"); 5021 5022 while (acquire_sem(gui.vimApp->fFilePanelSem) == B_INTERRUPTED); 5023 5024 char_u *fileName = NULL; 5025 status_t result = gui.vimApp->fBrowsedPath.InitCheck(); 5026 if (result == B_OK) { 5027 fileName = vim_strsave((char_u*)gui.vimApp->fBrowsedPath.Path()); 5028 } else 5029 if (result != B_NO_INIT) { 5030 fprintf(stderr, "gui_mch_browse: BPath error: %#08x (%s)\n", 5031 result, strerror(result)); 5032 } 5033 5034 delete gui.vimApp->fFilePanel; 5035 gui.vimApp->fFilePanel = NULL; 5036 5037 return fileName; 5038 } 5039 #endif // FEAT_BROWSE 5040 5041 5042 #if defined(FEAT_GUI_DIALOG) 5043 5044 /* 5045 * Create a dialog dynamically from the parameter strings. 5046 * type = type of dialog (question, alert, etc.) 5047 * title = dialog title. may be NULL for default title. 5048 * message = text to display. Dialog sizes to accommodate it. 5049 * buttons = '\n' separated list of button captions, default first. 5050 * dfltbutton = number of default button. 5051 * 5052 * This routine returns 1 if the first button is pressed, 5053 * 2 for the second, etc. 5054 * 5055 * 0 indicates Esc was pressed. 5056 * -1 for unexpected error 5057 * 5058 * If stubbing out this fn, return 1. 5059 */ 5060 5061 int 5062 gui_mch_dialog( 5063 int type, 5064 char_u *title, 5065 char_u *message, 5066 char_u *buttons, 5067 int dfltbutton, 5068 char_u *textfield, 5069 int ex_cmd) 5070 { 5071 VimDialog *dialog = new VimDialog(type, (char*)title, (char*)message, 5072 (char*)buttons, dfltbutton, (char*)textfield, ex_cmd); 5073 return dialog->Go(); 5074 } 5075 5076 #endif // FEAT_GUI_DIALOG 5077 5078 5079 /* 5080 * Return the RGB value of a pixel as long. 5081 */ 5082 guicolor_T 5083 gui_mch_get_rgb(guicolor_T pixel) 5084 { 5085 rgb_color rgb = GUI_TO_RGB(pixel); 5086 5087 return ((rgb.red & 0xff) << 16) + ((rgb.green & 0xff) << 8) 5088 + (rgb.blue & 0xff); 5089 } 5090 5091 void 5092 gui_mch_setmouse(int x, int y) 5093 { 5094 TRACE(); 5095 // TODO 5096 } 5097 5098 #ifdef FEAT_MBYTE_IME 5099 void 5100 im_set_position(int row, int col) 5101 { 5102 if (gui.vimWindow->Lock()) 5103 { 5104 gui.vimTextArea->DrawIMString(); 5105 gui.vimWindow->Unlock(); 5106 } 5107 return; 5108 } 5109 #endif 5110 5111 void 5112 gui_mch_show_toolbar(int showit) 5113 { 5114 VimToolbar *toolbar = gui.vimForm->ToolBar(); 5115 gui.toolbar_height = (toolbar && showit) ? toolbar->ToolbarHeight() : 0.; 5116 } 5117 5118 void 5119 gui_mch_set_toolbar_pos(int x, int y, int w, int h) 5120 { 5121 VimToolbar *toolbar = gui.vimForm->ToolBar(); 5122 if (toolbar != NULL) { 5123 if (gui.vimWindow->Lock()) { 5124 toolbar->MoveTo(x, y); 5125 toolbar->ResizeTo(w - 1, h - 1); 5126 gui.vimWindow->Unlock(); 5127 } 5128 } 5129 } 5130 5131 #if defined(FEAT_GUI_TABLINE) || defined(PROTO) 5132 5133 /* 5134 * Show or hide the tabline. 5135 */ 5136 void 5137 gui_mch_show_tabline(int showit) 5138 { 5139 VimTabLine *tabLine = gui.vimForm->TabLine(); 5140 5141 if (tabLine == NULL) 5142 return; 5143 5144 if (!showit != !gui.vimForm->IsShowingTabLine()) { 5145 gui.vimForm->SetShowingTabLine(showit != 0); 5146 gui.tabline_height = gui.vimForm->TablineHeight(); 5147 } 5148 } 5149 5150 void 5151 gui_mch_set_tabline_pos(int x, int y, int w, int h) 5152 { 5153 VimTabLine *tabLine = gui.vimForm->TabLine(); 5154 if (tabLine != NULL) { 5155 if (gui.vimWindow->Lock()) { 5156 tabLine->MoveTo(x, y); 5157 tabLine->ResizeTo(w - 1, h - 1); 5158 gui.vimWindow->Unlock(); 5159 } 5160 } 5161 } 5162 5163 /* 5164 * Return TRUE when tabline is displayed. 5165 */ 5166 int 5167 gui_mch_showing_tabline() 5168 { 5169 VimTabLine *tabLine = gui.vimForm->TabLine(); 5170 return tabLine != NULL && gui.vimForm->IsShowingTabLine(); 5171 } 5172 5173 /* 5174 * Update the labels of the tabline. 5175 */ 5176 void 5177 gui_mch_update_tabline() 5178 { 5179 tabpage_T *tp; 5180 int nr = 0; 5181 int curtabidx = 0; 5182 5183 VimTabLine *tabLine = gui.vimForm->TabLine(); 5184 5185 if (tabLine == NULL) 5186 return; 5187 5188 gui.vimWindow->Lock(); 5189 5190 // Add a label for each tab page. They all contain the same text area. 5191 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr) { 5192 if (tp == curtab) 5193 curtabidx = nr; 5194 5195 BTab* tab = tabLine->TabAt(nr); 5196 5197 if (tab == NULL) { 5198 tab = new VimTabLine::VimTab(); 5199 tabLine->AddTab(NULL, tab); 5200 } 5201 5202 get_tabline_label(tp, FALSE); 5203 tab->SetLabel((const char*)NameBuff); 5204 tabLine->Invalidate(); 5205 } 5206 5207 // Remove any old labels. 5208 while (nr < tabLine->CountTabs()) 5209 tabLine->RemoveTab(nr); 5210 5211 if (tabLine->Selection() != curtabidx) 5212 tabLine->Select(curtabidx); 5213 5214 gui.vimWindow->Unlock(); 5215 } 5216 5217 /* 5218 * Set the current tab to "nr". First tab is 1. 5219 */ 5220 void 5221 gui_mch_set_curtab(int nr) 5222 { 5223 VimTabLine *tabLine = gui.vimForm->TabLine(); 5224 if (tabLine == NULL) 5225 return; 5226 5227 gui.vimWindow->Lock(); 5228 5229 if (tabLine->Selection() != nr -1) 5230 tabLine->Select(nr -1); 5231 5232 gui.vimWindow->Unlock(); 5233 } 5234 5235 #endif // FEAT_GUI_TABLINE 5236