1 /* vi:set ts=8 sw=4 sts=4: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * Photon GUI support by Julian Kinraid 5 * 6 * Do ":help uganda" in Vim to read copying and usage conditions. 7 * Do ":help credits" in Vim to see a list of people who contributed. 8 * 9 * 10 * Clipboard support is in os_qnx.c 11 * PhAttach() is called in os_qnx.c:qnx_init() 12 */ 13 14 #include "vim.h" 15 16 /* cproto fails on missing include files */ 17 #ifndef PROTO 18 # ifdef FEAT_TOOLBAR 19 # include <photon/PxImage.h> 20 # endif 21 #endif 22 23 #if !defined(__QNX__) 24 /* Used when generating prototypes. */ 25 # define PgColor_t int 26 # define PhEvent_t int 27 # define PhPoint_t int 28 # define PtWidget_t int 29 # define Pg_BLACK 0 30 # define PtCallbackF_t int 31 # define PtCallbackInfo_t int 32 # define PhTile_t int 33 # define PtWidget_t int 34 # define PhImage_t int 35 #endif 36 37 #define ARRAY_LENGTH(a) (sizeof(a) / sizeof(a[0])) 38 #define RGB(r, g, b) PgRGB(r, g, b) 39 40 #define EVENT_BUFFER_SIZE sizeof(PhEvent_t) + 1000 41 42 /* Some defines for gui_mch_mousehide() */ 43 #define MOUSE_HIDE TRUE 44 #define MOUSE_SHOW FALSE 45 46 /* Optional support for using a PtPanelGroup widget, needs work */ 47 #undef USE_PANEL_GROUP 48 49 #ifdef USE_PANEL_GROUP 50 static char *empty_title = " "; 51 static char **panel_titles = NULL; 52 static ushort_t num_panels = 0; 53 static short pg_margin_left, pg_margin_right, pg_margin_top, pg_margin_bottom; 54 #endif 55 56 #define GUI_PH_MARGIN 4 /* Size of the bevel */ 57 58 #define GUI_PH_MOUSE_TYPE Ph_CURSOR_INSERT 59 static PgColor_t gui_ph_mouse_color = Pg_BLACK; 60 61 static PhPoint_t gui_ph_raw_offset; 62 static PtWidget_t *gui_ph_timer_cursor; /* handle cursor blinking */ 63 static PtWidget_t *gui_ph_timer_timeout; /* used in gui_mch_wait_for_chars */ 64 static short is_timeout; /* Has the timeout occurred? */ 65 66 /* 67 * This is set inside the mouse callback for a right mouse 68 * button click, and used for the popup menus 69 */ 70 static PhPoint_t abs_mouse; 71 72 /* Try and avoid redraws while a resize is in progress */ 73 static int is_ignore_draw = FALSE; 74 75 /* Used for converting to/from utf-8 and other charsets */ 76 static struct PxTransCtrl *charset_translate; 77 78 /* 79 * Cursor blink functions. 80 * 81 * This is a simple state machine: 82 * BLINK_NONE not blinking at all 83 * BLINK_OFF blinking, cursor is not shown 84 * BLINK_ON blinking, cursor is shown 85 */ 86 static enum { 87 BLINK_NONE, 88 BLINK_OFF, 89 BLINK_ON 90 } blink_state = BLINK_NONE; 91 92 static long_u blink_waittime = 700; 93 static long_u blink_ontime = 400; 94 static long_u blink_offtime = 250; 95 96 static struct 97 { 98 int key_sym; 99 char_u vim_code0; 100 char_u vim_code1; 101 } special_keys[] = 102 { 103 {Pk_Up, 'k', 'u'}, 104 {Pk_Down, 'k', 'd'}, 105 {Pk_Left, 'k', 'l'}, 106 {Pk_Right, 'k', 'r'}, 107 108 {Pk_F1, 'k', '1'}, 109 {Pk_F2, 'k', '2'}, 110 {Pk_F3, 'k', '3'}, 111 {Pk_F4, 'k', '4'}, 112 {Pk_F5, 'k', '5'}, 113 {Pk_F6, 'k', '6'}, 114 {Pk_F7, 'k', '7'}, 115 {Pk_F8, 'k', '8'}, 116 {Pk_F9, 'k', '9'}, 117 {Pk_F10, 'k', ';'}, 118 119 {Pk_F11, 'F', '1'}, 120 {Pk_F12, 'F', '2'}, 121 {Pk_F13, 'F', '3'}, 122 {Pk_F14, 'F', '4'}, 123 {Pk_F15, 'F', '5'}, 124 {Pk_F16, 'F', '6'}, 125 {Pk_F17, 'F', '7'}, 126 {Pk_F18, 'F', '8'}, 127 {Pk_F19, 'F', '9'}, 128 {Pk_F20, 'F', 'A'}, 129 130 {Pk_F21, 'F', 'B'}, 131 {Pk_F22, 'F', 'C'}, 132 {Pk_F23, 'F', 'D'}, 133 {Pk_F24, 'F', 'E'}, 134 {Pk_F25, 'F', 'F'}, 135 {Pk_F26, 'F', 'G'}, 136 {Pk_F27, 'F', 'H'}, 137 {Pk_F28, 'F', 'I'}, 138 {Pk_F29, 'F', 'J'}, 139 140 {Pk_F30, 'F', 'K'}, 141 {Pk_F31, 'F', 'L'}, 142 {Pk_F32, 'F', 'M'}, 143 {Pk_F33, 'F', 'N'}, 144 {Pk_F34, 'F', 'O'}, 145 {Pk_F35, 'F', 'P'}, 146 147 {Pk_Help, '%', '1'}, 148 {Pk_BackSpace, 'k', 'b'}, 149 {Pk_Insert, 'k', 'I'}, 150 {Pk_Delete, 'k', 'D'}, 151 {Pk_Home, 'k', 'h'}, 152 {Pk_End, '@', '7'}, 153 {Pk_Prior, 'k', 'P'}, 154 {Pk_Next, 'k', 'N'}, 155 {Pk_Print, '%', '9'}, 156 157 {Pk_KP_Add, 'K', '6'}, 158 {Pk_KP_Subtract,'K', '7'}, 159 {Pk_KP_Divide, 'K', '8'}, 160 {Pk_KP_Multiply,'K', '9'}, 161 {Pk_KP_Enter, 'K', 'A'}, 162 163 {Pk_KP_0, KS_EXTRA, KE_KINS}, /* Insert */ 164 {Pk_KP_Decimal, KS_EXTRA, KE_KDEL}, /* Delete */ 165 166 {Pk_KP_4, 'k', 'l'}, /* Left */ 167 {Pk_KP_6, 'k', 'r'}, /* Right */ 168 {Pk_KP_8, 'k', 'u'}, /* Up */ 169 {Pk_KP_2, 'k', 'd'}, /* Down */ 170 171 {Pk_KP_7, 'K', '1'}, /* Home */ 172 {Pk_KP_1, 'K', '4'}, /* End */ 173 174 {Pk_KP_9, 'K', '3'}, /* Page Up */ 175 {Pk_KP_3, 'K', '5'}, /* Page Down */ 176 177 {Pk_KP_5, '&', '8'}, /* Undo */ 178 179 /* Keys that we want to be able to use any modifier with: */ 180 {Pk_Return, CAR, NUL}, 181 {Pk_space, ' ', NUL}, 182 {Pk_Tab, TAB, NUL}, 183 {Pk_Escape, ESC, NUL}, 184 {NL, NL, NUL}, 185 {CAR, CAR, NUL}, 186 187 /* End of list marker: */ 188 {0, 0, 0} 189 }; 190 191 192 /****************************************************************************/ 193 194 static PtCallbackF_t gui_ph_handle_timer_cursor; 195 static PtCallbackF_t gui_ph_handle_timer_timeout; 196 197 static PtCallbackF_t gui_ph_handle_window_cb; 198 199 static PtCallbackF_t gui_ph_handle_scrollbar; 200 static PtCallbackF_t gui_ph_handle_keyboard; 201 static PtCallbackF_t gui_ph_handle_mouse; 202 static PtCallbackF_t gui_ph_handle_pulldown_menu; 203 static PtCallbackF_t gui_ph_handle_menu; 204 static PtCallbackF_t gui_ph_handle_focus; /* focus change of text area */ 205 206 static PtCallbackF_t gui_ph_handle_menu_resize; 207 208 /* When a menu is unrealized, give focus back to vimTextArea */ 209 static PtCallbackF_t gui_ph_handle_menu_unrealized; 210 211 #ifdef USE_PANEL_GROUP 212 static void gui_ph_get_panelgroup_margins(short*, short*, short*, short*); 213 #endif 214 215 #ifdef FEAT_TOOLBAR 216 static PhImage_t *gui_ph_toolbar_find_icon(vimmenu_T *menu); 217 #endif 218 219 static void gui_ph_draw_start(void); 220 static void gui_ph_draw_end(void); 221 222 /* Set the text for the balloon */ 223 static PtWidget_t * gui_ph_show_tooltip(PtWidget_t *window, 224 PtWidget_t *widget, 225 int position, 226 char *text, 227 char *font, 228 PgColor_t fill_color, 229 PgColor_t text_color); 230 231 /****************************************************************************/ 232 233 static PtWidget_t * gui_ph_show_tooltip(PtWidget_t *window, 234 PtWidget_t *widget, 235 int position, 236 char *text, 237 char *font, 238 PgColor_t fill_color, 239 PgColor_t text_color) 240 { 241 PtArg_t arg; 242 vimmenu_T *menu; 243 char_u *tooltip; 244 245 PtSetArg(&arg, Pt_ARG_POINTER, &menu, 0); 246 PtGetResources(widget, 1, &arg); 247 248 /* Override the text and position */ 249 250 tooltip = text; 251 if (menu != NULL) 252 { 253 int index = MENU_INDEX_TIP; 254 if (menu->strings[ index ] != NULL) 255 tooltip = menu->strings[ index ]; 256 } 257 258 return PtInflateBalloon( 259 window, 260 widget, 261 /* Don't put the balloon at the bottom, 262 * it gets drawn over by gfx done in the PtRaw */ 263 Pt_BALLOON_TOP, 264 tooltip, 265 font, 266 fill_color, 267 text_color); 268 } 269 270 static void 271 gui_ph_resize_container(void) 272 { 273 PhArea_t area; 274 275 PtWidgetArea(gui.vimWindow, &area); 276 PtWidgetPos (gui.vimContainer, &area.pos); 277 278 PtSetResource(gui.vimContainer, Pt_ARG_AREA, &area, 0); 279 } 280 281 static int 282 gui_ph_handle_menu_resize( 283 PtWidget_t *widget, 284 void *other, 285 PtCallbackInfo_t *info) 286 { 287 PtContainerCallback_t *sizes = info->cbdata; 288 PtWidget_t *container; 289 PhPoint_t below_menu; 290 int_u height; 291 292 height = sizes->new_dim.h; 293 294 /* Because vim treats the toolbar and menubar separately, 295 * and here they're lumped together into a PtToolbarGroup, 296 * we only need either menu_height or toolbar_height set at once */ 297 if (gui.menu_is_active) 298 { 299 gui.menu_height = height; 300 gui.toolbar_height = 0; 301 } 302 #ifdef FEAT_TOOLBAR 303 else 304 gui.toolbar_height = height; 305 #endif 306 307 below_menu.x = 0; 308 below_menu.y = height; 309 310 #ifdef USE_PANEL_GROUP 311 container = gui.vimPanelGroup; 312 #else 313 container = gui.vimContainer; 314 #endif 315 316 PtSetResource(container, Pt_ARG_POS, &below_menu, 0); 317 318 gui_ph_resize_container(); 319 320 #ifdef USE_PANEL_GROUP 321 gui_ph_get_panelgroup_margins( 322 &pg_margin_top, &pg_margin_bottom, 323 &pg_margin_left, &pg_margin_right); 324 #endif 325 return Pt_CONTINUE; 326 } 327 328 /* 329 * Pt_ARG_TIMER_REPEAT isn't used because the on & off times 330 * are different 331 */ 332 static int 333 gui_ph_handle_timer_cursor( 334 PtWidget_t *widget, 335 void *data, 336 PtCallbackInfo_t *info) 337 { 338 if (blink_state == BLINK_ON) 339 { 340 gui_undraw_cursor(); 341 blink_state = BLINK_OFF; 342 PtSetResource(gui_ph_timer_cursor, Pt_ARG_TIMER_INITIAL, 343 blink_offtime, 0); 344 } 345 else 346 { 347 gui_update_cursor(TRUE, FALSE); 348 blink_state = BLINK_ON; 349 PtSetResource(gui_ph_timer_cursor, Pt_ARG_TIMER_INITIAL, 350 blink_ontime, 0); 351 } 352 return Pt_CONTINUE; 353 } 354 355 static int 356 gui_ph_handle_timer_timeout(PtWidget_t *widget, void *data, PtCallbackInfo_t *info) 357 { 358 is_timeout = TRUE; 359 360 return Pt_CONTINUE; 361 } 362 363 static int 364 gui_ph_handle_window_cb(PtWidget_t *widget, void *data, PtCallbackInfo_t *info) 365 { 366 PhWindowEvent_t *we = info->cbdata; 367 ushort_t *width, *height; 368 369 switch (we->event_f) { 370 case Ph_WM_CLOSE: 371 gui_shell_closed(); 372 break; 373 374 case Ph_WM_FOCUS: 375 /* Just in case it's hidden and needs to be shown */ 376 gui_mch_mousehide(MOUSE_SHOW); 377 378 if (we->event_state == Ph_WM_EVSTATE_FOCUS) 379 { 380 gui_focus_change(TRUE); 381 gui_mch_start_blink(); 382 } 383 else 384 { 385 gui_focus_change(FALSE); 386 gui_mch_stop_blink(); 387 } 388 break; 389 390 case Ph_WM_RESIZE: 391 PtGetResource(gui.vimWindow, Pt_ARG_WIDTH, &width, 0); 392 PtGetResource(gui.vimWindow, Pt_ARG_HEIGHT, &height, 0); 393 #ifdef USE_PANEL_GROUP 394 width -= (pg_margin_left + pg_margin_right); 395 height -= (pg_margin_top + pg_margin_bottom); 396 #endif 397 gui_resize_shell(*width, *height); 398 gui_set_shellsize(FALSE, FALSE, RESIZE_BOTH); 399 is_ignore_draw = FALSE; 400 PtEndFlux(gui.vimContainer); 401 PtContainerRelease(gui.vimContainer); 402 break; 403 404 default: 405 break; 406 } 407 408 return Pt_CONTINUE; 409 } 410 411 static int 412 gui_ph_handle_scrollbar(PtWidget_t *widget, void *data, PtCallbackInfo_t *info) 413 { 414 PtScrollbarCallback_t *scroll; 415 scrollbar_T *sb; 416 int value, dragging = FALSE; 417 418 scroll = info->cbdata; 419 420 sb = (scrollbar_T *) data; 421 if (sb != NULL) 422 { 423 value = scroll->position; 424 switch (scroll->action) 425 { 426 case Pt_SCROLL_DRAGGED: 427 dragging = TRUE; 428 break; 429 430 case Pt_SCROLL_SET: 431 /* FIXME: return straight away here? */ 432 return Pt_CONTINUE; 433 break; 434 } 435 436 gui_drag_scrollbar(sb, value, dragging); 437 } 438 return Pt_CONTINUE; 439 } 440 441 static int 442 gui_ph_handle_keyboard(PtWidget_t *widget, void *data, PtCallbackInfo_t *info) 443 { 444 PhKeyEvent_t *key; 445 unsigned char string[6]; 446 int len, i; 447 int ch, modifiers; 448 449 key = PhGetData(info->event); 450 451 ch = modifiers = len = 0; 452 453 if (p_mh) 454 gui_mch_mousehide(MOUSE_HIDE); 455 456 /* We're a good lil photon program, aren't we? yes we are, yeess wee arrr */ 457 if (key->key_flags & Pk_KF_Compose) 458 { 459 return Pt_CONTINUE; 460 } 461 462 if ((key->key_flags & Pk_KF_Cap_Valid) && 463 PkIsKeyDown(key->key_flags)) 464 { 465 #ifdef FEAT_MENU 466 /* 467 * Only show the menu if the Alt key is down, and the Shift & Ctrl 468 * keys aren't down, as well as the other conditions 469 */ 470 if (((key->key_mods & Pk_KM_Alt) && 471 !(key->key_mods & Pk_KM_Shift) && 472 !(key->key_mods & Pk_KM_Ctrl)) && 473 gui.menu_is_active && 474 (*p_wak == 'y' || 475 (*p_wak == 'm' && 476 gui_is_menu_shortcut(key->key_cap)))) 477 { 478 /* Fallthrough and let photon look for the hotkey */ 479 return Pt_CONTINUE; 480 } 481 #endif 482 483 for (i = 0; special_keys[i].key_sym != 0; i++) 484 { 485 if (special_keys[i].key_sym == key->key_cap) 486 { 487 len = 0; 488 if (special_keys[i].vim_code1 == NUL) 489 ch = special_keys[i].vim_code0; 490 else 491 { 492 /* Detect if a keypad number key has been pressed 493 * and change the key if Num Lock is on */ 494 if (key->key_cap >= Pk_KP_Enter && key->key_cap <= Pk_KP_9 495 && (key->key_mods & Pk_KM_Num_Lock)) 496 { 497 /* FIXME: For now, just map the key to a ascii value 498 * (see <photon/PkKeyDef.h>) */ 499 ch = key->key_cap - 0xf080; 500 } 501 else 502 ch = TO_SPECIAL(special_keys[i].vim_code0, 503 special_keys[i].vim_code1); 504 } 505 break; 506 } 507 } 508 509 if (key->key_mods & Pk_KM_Ctrl) 510 modifiers |= MOD_MASK_CTRL; 511 if (key->key_mods & Pk_KM_Alt) 512 modifiers |= MOD_MASK_ALT; 513 if (key->key_mods & Pk_KM_Shift) 514 modifiers |= MOD_MASK_SHIFT; 515 516 /* Is this not a special key? */ 517 if (special_keys[i].key_sym == 0) 518 { 519 ch = PhTo8859_1(key); 520 if (ch == -1 521 #ifdef FEAT_MBYTE 522 || (enc_utf8 && ch > 127) 523 #endif 524 ) 525 { 526 #ifdef FEAT_MBYTE 527 len = PhKeyToMb(string, key); 528 if (len > 0) 529 { 530 static char buf[6]; 531 int src_taken, dst_made; 532 if (enc_utf8 != TRUE) 533 { 534 PxTranslateFromUTF( 535 charset_translate, 536 string, 537 len, 538 &src_taken, 539 buf, 540 6, 541 &dst_made); 542 543 add_to_input_buf(buf, dst_made); 544 } 545 else 546 { 547 add_to_input_buf(string, len); 548 } 549 550 return Pt_CONSUME; 551 } 552 len = 0; 553 #endif 554 ch = key->key_cap; 555 if (ch < 0xff) 556 { 557 /* FIXME: is this the right thing to do? */ 558 if (modifiers & MOD_MASK_CTRL) 559 { 560 modifiers &= ~MOD_MASK_CTRL; 561 562 if ((ch >= 'a' && ch <= 'z') || 563 ch == '[' || 564 ch == ']' || 565 ch == '\\') 566 ch = Ctrl_chr(ch); 567 else if (ch == '2') 568 ch = NUL; 569 else if (ch == '6') 570 ch = 0x1e; 571 else if (ch == '-') 572 ch = 0x1f; 573 else 574 modifiers |= MOD_MASK_CTRL; 575 } 576 577 if (modifiers & MOD_MASK_ALT) 578 { 579 ch = Meta(ch); 580 modifiers &= ~MOD_MASK_ALT; 581 } 582 } 583 else 584 { 585 return Pt_CONTINUE; 586 } 587 } 588 else 589 modifiers &= ~MOD_MASK_SHIFT; 590 } 591 592 ch = simplify_key(ch, &modifiers); 593 if (modifiers) 594 { 595 string[ len++ ] = CSI; 596 string[ len++ ] = KS_MODIFIER; 597 string[ len++ ] = modifiers; 598 } 599 600 if (IS_SPECIAL(ch)) 601 { 602 string[ len++ ] = CSI; 603 string[ len++ ] = K_SECOND(ch); 604 string[ len++ ] = K_THIRD(ch); 605 } 606 else 607 { 608 string[ len++ ] = ch; 609 } 610 611 if (len == 1 && ((ch == Ctrl_C && ctrl_c_interrupts) 612 || ch == intr_char)) 613 { 614 trash_input_buf(); 615 got_int = TRUE; 616 } 617 618 if (len == 1 && string[0] == CSI) 619 { 620 /* Turn CSI into K_CSI. */ 621 string[ len++ ] = KS_EXTRA; 622 string[ len++ ] = KE_CSI; 623 } 624 625 if (len > 0) 626 { 627 add_to_input_buf(string, len); 628 return Pt_CONSUME; 629 } 630 } 631 632 return Pt_CONTINUE; 633 } 634 635 static int 636 gui_ph_handle_mouse(PtWidget_t *widget, void *data, PtCallbackInfo_t *info) 637 { 638 PhPointerEvent_t *pointer; 639 PhRect_t *pos; 640 int button = 0, repeated_click, modifiers = 0x0; 641 short mouse_x, mouse_y; 642 643 pointer = PhGetData(info->event); 644 pos = PhGetRects(info->event); 645 646 gui_mch_mousehide(MOUSE_SHOW); 647 648 /* 649 * Coordinates need to be relative to the base window, 650 * not relative to the vimTextArea widget 651 */ 652 mouse_x = pos->ul.x + gui.border_width; 653 mouse_y = pos->ul.y + gui.border_width; 654 655 if (info->event->type == Ph_EV_PTR_MOTION_NOBUTTON) 656 { 657 gui_mouse_moved(mouse_x, mouse_y); 658 return Pt_CONTINUE; 659 } 660 661 if (pointer->key_mods & Pk_KM_Shift) 662 modifiers |= MOUSE_SHIFT; 663 if (pointer->key_mods & Pk_KM_Ctrl) 664 modifiers |= MOUSE_CTRL; 665 if (pointer->key_mods & Pk_KM_Alt) 666 modifiers |= MOUSE_ALT; 667 668 /* 669 * FIXME More than one button may be involved, but for 670 * now just deal with one 671 */ 672 if (pointer->buttons & Ph_BUTTON_SELECT) 673 button = MOUSE_LEFT; 674 675 if (pointer->buttons & Ph_BUTTON_MENU) 676 { 677 button = MOUSE_RIGHT; 678 /* Need the absolute coordinates for the popup menu */ 679 abs_mouse.x = pointer->pos.x; 680 abs_mouse.y = pointer->pos.y; 681 } 682 683 if (pointer->buttons & Ph_BUTTON_ADJUST) 684 button = MOUSE_MIDDLE; 685 686 /* Catch a real release (not phantom or other releases */ 687 if (info->event->type == Ph_EV_BUT_RELEASE) 688 button = MOUSE_RELEASE; 689 690 if (info->event->type & Ph_EV_PTR_MOTION_BUTTON) 691 button = MOUSE_DRAG; 692 693 #if 0 694 /* Vim doesn't use button repeats */ 695 if (info->event->type & Ph_EV_BUT_REPEAT) 696 button = MOUSE_DRAG; 697 #endif 698 699 /* Don't do anything if it is one of the phantom mouse release events */ 700 if ((button != MOUSE_RELEASE) || 701 (info->event->subtype == Ph_EV_RELEASE_REAL)) 702 { 703 repeated_click = (pointer->click_count >= 2) ? TRUE : FALSE; 704 705 gui_send_mouse_event(button , mouse_x, mouse_y, repeated_click, modifiers); 706 } 707 708 return Pt_CONTINUE; 709 } 710 711 /* Handle a focus change of the PtRaw widget */ 712 static int 713 gui_ph_handle_focus(PtWidget_t *widget, void *data, PtCallbackInfo_t *info) 714 { 715 if (info->reason == Pt_CB_LOST_FOCUS) 716 { 717 PtRemoveEventHandler(gui.vimTextArea, Ph_EV_PTR_MOTION_NOBUTTON, 718 gui_ph_handle_mouse, NULL); 719 720 gui_mch_mousehide(MOUSE_SHOW); 721 } 722 else 723 { 724 PtAddEventHandler(gui.vimTextArea, Ph_EV_PTR_MOTION_NOBUTTON, 725 gui_ph_handle_mouse, NULL); 726 } 727 return Pt_CONTINUE; 728 } 729 730 static void 731 gui_ph_handle_raw_draw(PtWidget_t *widget, PhTile_t *damage) 732 { 733 PhRect_t *r; 734 PhPoint_t offset; 735 PhPoint_t translation; 736 737 if (is_ignore_draw == TRUE) 738 return; 739 740 PtSuperClassDraw(PtBasic, widget, damage); 741 PgGetTranslation(&translation); 742 PgClearTranslation(); 743 744 #if 0 745 /* 746 * This causes some weird problems, with drawing being done from 747 * within this raw drawing function (rather than just simple clearing 748 * and text drawing done by gui_redraw) 749 * 750 * The main problem is when PhBlit is used, and the cursor appearing 751 * in places where it shouldn't 752 */ 753 out_flush(); 754 #endif 755 756 PtWidgetOffset(widget, &offset); 757 PhTranslatePoint(&offset, PtWidgetPos(gui.vimTextArea, NULL)); 758 759 #if 1 760 /* Redraw individual damage regions */ 761 if (damage->next != NULL) 762 damage = damage->next; 763 764 while (damage != NULL) 765 { 766 r = &damage->rect; 767 gui_redraw( 768 r->ul.x - offset.x, r->ul.y - offset.y, 769 r->lr.x - r->ul.x + 1, 770 r->lr.y - r->ul.y + 1); 771 damage = damage->next; 772 } 773 #else 774 /* Redraw the rectangle that covers all the damaged regions */ 775 r = &damage->rect; 776 gui_redraw( 777 r->ul.x - offset.x, r->ul.y - offset.y, 778 r->lr.x - r->ul.x + 1, 779 r->lr.y - r->ul.y + 1); 780 #endif 781 782 PgSetTranslation(&translation, 0); 783 } 784 785 static int 786 gui_ph_handle_pulldown_menu( 787 PtWidget_t *widget, 788 void *data, 789 PtCallbackInfo_t *info) 790 { 791 if (data != NULL) 792 { 793 vimmenu_T *menu = (vimmenu_T *) data; 794 795 PtPositionMenu(menu->submenu_id, NULL); 796 PtRealizeWidget(menu->submenu_id); 797 } 798 799 return Pt_CONTINUE; 800 } 801 802 /* This is used for pulldown/popup menus and also toolbar buttons */ 803 static int 804 gui_ph_handle_menu(PtWidget_t *widget, void *data, PtCallbackInfo_t *info) 805 { 806 if (data != NULL) 807 { 808 vimmenu_T *menu = (vimmenu_T *) data; 809 gui_menu_cb(menu); 810 } 811 return Pt_CONTINUE; 812 } 813 814 /* Stop focus from disappearing into the menubar... */ 815 static int 816 gui_ph_handle_menu_unrealized( 817 PtWidget_t *widget, 818 void *data, 819 PtCallbackInfo_t *info) 820 { 821 PtGiveFocus(gui.vimTextArea, NULL); 822 return Pt_CONTINUE; 823 } 824 825 static int 826 gui_ph_handle_window_open( 827 PtWidget_t *widget, 828 void *data, 829 PtCallbackInfo_t *info) 830 { 831 gui_set_shellsize(FALSE, TRUE, RESIZE_BOTH); 832 return Pt_CONTINUE; 833 } 834 835 /****************************************************************************/ 836 837 #define DRAW_START gui_ph_draw_start() 838 #define DRAW_END gui_ph_draw_end() 839 840 /* TODO: Set a clipping rect? */ 841 static void 842 gui_ph_draw_start(void) 843 { 844 PhGC_t *gc; 845 846 gc = PgGetGC(); 847 PgSetRegion(PtWidgetRid(PtFindDisjoint(gui.vimTextArea))); 848 PgClearClippingsCx(gc); 849 PgClearTranslationCx(gc); 850 851 PtWidgetOffset(gui.vimTextArea, &gui_ph_raw_offset); 852 PhTranslatePoint(&gui_ph_raw_offset, PtWidgetPos(gui.vimTextArea, NULL)); 853 854 PgSetTranslation(&gui_ph_raw_offset, Pg_RELATIVE); 855 } 856 857 static void 858 gui_ph_draw_end(void) 859 { 860 gui_ph_raw_offset.x = -gui_ph_raw_offset.x; 861 gui_ph_raw_offset.y = -gui_ph_raw_offset.y; 862 PgSetTranslation(&gui_ph_raw_offset, Pg_RELATIVE); 863 } 864 865 #ifdef USE_PANEL_GROUP 866 static vimmenu_T * 867 gui_ph_find_buffer_item(char_u *name) 868 { 869 vimmenu_T *top_level = root_menu; 870 vimmenu_T *items = NULL; 871 872 while (top_level != NULL && 873 (STRCMP(top_level->dname, "Buffers") != 0)) 874 top_level = top_level->next; 875 876 if (top_level != NULL) 877 { 878 items = top_level->children; 879 880 while (items != NULL && 881 (STRCMP(items->dname, name) != 0)) 882 items = items->next; 883 } 884 return items; 885 } 886 887 static void 888 gui_ph_pg_set_buffer_num(int_u buf_num) 889 { 890 int i; 891 char search[16]; 892 char *mark; 893 894 if (gui.vimTextArea == NULL || buf_num == 0) 895 return; 896 897 search[0] = '('; 898 ultoa(buf_num, &search[1], 10); 899 STRCAT(search, ")"); 900 901 for (i = 0; i < num_panels; i++) 902 { 903 /* find the last "(" in the panel title and see if the buffer 904 * number in the title matches the one we're looking for */ 905 mark = STRRCHR(panel_titles[ i ], '('); 906 if (mark != NULL && STRCMP(mark, search) == 0) 907 { 908 PtSetResource(gui.vimPanelGroup, Pt_ARG_PG_CURRENT_INDEX, 909 i, 0); 910 } 911 } 912 } 913 914 static int 915 gui_ph_handle_pg_change( 916 PtWidget_t *widget, 917 void *data, 918 PtCallbackInfo_t *info) 919 { 920 vimmenu_T *menu; 921 PtPanelGroupCallback_t *panel; 922 923 if (info->event != NULL) 924 { 925 panel = info->cbdata; 926 if (panel->new_panel != NULL) 927 { 928 menu = gui_ph_find_buffer_item(panel->new_panel); 929 if (menu) 930 gui_menu_cb(menu); 931 } 932 } 933 return Pt_CONTINUE; 934 } 935 936 static void 937 gui_ph_get_panelgroup_margins( 938 short *top, 939 short *bottom, 940 short *left, 941 short *right) 942 { 943 unsigned short abs_raw_x, abs_raw_y, abs_panel_x, abs_panel_y; 944 const unsigned short *margin_top, *margin_bottom; 945 const unsigned short *margin_left, *margin_right; 946 947 PtGetAbsPosition(gui.vimTextArea, &abs_raw_x, &abs_raw_y); 948 PtGetAbsPosition(gui.vimPanelGroup, &abs_panel_x, &abs_panel_y); 949 950 PtGetResource(gui.vimPanelGroup, Pt_ARG_MARGIN_RIGHT, &margin_right, 0); 951 PtGetResource(gui.vimPanelGroup, Pt_ARG_MARGIN_BOTTOM, &margin_bottom, 0); 952 953 abs_raw_x -= abs_panel_x; 954 abs_raw_y -= abs_panel_y; 955 956 *top = abs_raw_y; 957 *bottom = *margin_bottom; 958 959 *left = abs_raw_x; 960 *right = *margin_right; 961 } 962 963 /* Used for the tabs for PtPanelGroup */ 964 static int 965 gui_ph_is_buffer_item(vimmenu_T *menu, vimmenu_T *parent) 966 { 967 char *mark; 968 969 if (STRCMP(parent->dname, "Buffers") == 0) 970 { 971 /* Look for '(' digits ')' */ 972 mark = vim_strchr(menu->dname, '('); 973 if (mark != NULL) 974 { 975 mark++; 976 while (isdigit(*mark)) 977 mark++; 978 979 if (*mark == ')') 980 return TRUE; 981 } 982 } 983 return FALSE; 984 } 985 986 static void 987 gui_ph_pg_add_buffer(char *name) 988 { 989 char **new_titles = NULL; 990 991 new_titles = (char **) alloc((num_panels + 1) * sizeof(char **)); 992 if (new_titles != NULL) 993 { 994 if (num_panels > 0) 995 memcpy(new_titles, panel_titles, num_panels * sizeof(char **)); 996 997 new_titles[ num_panels++ ] = name; 998 999 PtSetResource(gui.vimPanelGroup, Pt_ARG_PG_PANEL_TITLES, new_titles, 1000 num_panels); 1001 1002 vim_free(panel_titles); 1003 panel_titles = new_titles; 1004 } 1005 } 1006 1007 static void 1008 gui_ph_pg_remove_buffer(char *name) 1009 { 1010 int i; 1011 char **new_titles = NULL; 1012 1013 /* If there is only 1 panel, we just use the temporary place holder */ 1014 if (num_panels > 1) 1015 { 1016 new_titles = (char **) alloc((num_panels - 1) * sizeof(char **)); 1017 if (new_titles != NULL) 1018 { 1019 char **s = new_titles; 1020 /* Copy all the titles except the one we're removing */ 1021 for (i = 0; i < num_panels; i++) 1022 { 1023 if (STRCMP(panel_titles[ i ], name) != 0) 1024 { 1025 *s++ = panel_titles[ i ]; 1026 } 1027 } 1028 num_panels--; 1029 1030 PtSetResource(gui.vimPanelGroup, Pt_ARG_PG_PANEL_TITLES, new_titles, 1031 num_panels); 1032 1033 vim_free(panel_titles); 1034 panel_titles = new_titles; 1035 } 1036 } 1037 else 1038 { 1039 num_panels--; 1040 PtSetResource(gui.vimPanelGroup, Pt_ARG_PG_PANEL_TITLES, &empty_title, 1041 1); 1042 1043 vim_free(panel_titles); 1044 panel_titles = NULL; 1045 } 1046 } 1047 1048 /* When a buffer item is deleted from the buffer menu */ 1049 static int 1050 gui_ph_handle_buffer_remove( 1051 PtWidget_t *widget, 1052 void *data, 1053 PtCallbackInfo_t *info) 1054 { 1055 vimmenu_T *menu; 1056 1057 if (data != NULL) 1058 { 1059 menu = (vimmenu_T *) data; 1060 gui_ph_pg_remove_buffer(menu->dname); 1061 } 1062 1063 return Pt_CONTINUE; 1064 } 1065 #endif 1066 1067 static int 1068 gui_ph_pane_resize(PtWidget_t *widget, void *data, PtCallbackInfo_t *info) 1069 { 1070 if (PtWidgetIsRealized(widget)) 1071 { 1072 is_ignore_draw = TRUE; 1073 PtStartFlux(gui.vimContainer); 1074 PtContainerHold(gui.vimContainer); 1075 } 1076 1077 return Pt_CONTINUE; 1078 } 1079 1080 /****************************************************************************/ 1081 1082 #ifdef FEAT_MBYTE 1083 void 1084 gui_ph_encoding_changed(int new_encoding) 1085 { 1086 /* Default encoding is latin1 */ 1087 char *charset = "latin1"; 1088 int i; 1089 1090 struct { 1091 int encoding; 1092 char *name; 1093 } charsets[] = { 1094 { DBCS_JPN, "SHIFT_JIS" }, 1095 { DBCS_KOR, "csEUCKR" }, 1096 { DBCS_CHT, "big5" }, 1097 { DBCS_CHS, "gb" } 1098 }; 1099 1100 for (i = 0; i < ARRAY_LENGTH(charsets); i++) 1101 { 1102 if (new_encoding == charsets[ i ].encoding) 1103 charset = charsets[ i ].name; 1104 } 1105 1106 charset_translate = PxTranslateSet(charset_translate, charset); 1107 } 1108 #endif 1109 1110 /****************************************************************************/ 1111 /****************************************************************************/ 1112 1113 void 1114 gui_mch_prepare(argc, argv) 1115 int *argc; 1116 char **argv; 1117 { 1118 PtInit(NULL); 1119 } 1120 1121 int 1122 gui_mch_init(void) 1123 { 1124 PtArg_t args[10]; 1125 int flags = 0, n = 0; 1126 1127 PhDim_t window_size = {100, 100}; /* Arbitrary values */ 1128 PhPoint_t pos = {0, 0}; 1129 1130 gui.event_buffer = (PhEvent_t *) alloc(EVENT_BUFFER_SIZE); 1131 if (gui.event_buffer == NULL) 1132 return FAIL; 1133 1134 /* Get a translation so we can convert from ISO Latin-1 to UTF */ 1135 charset_translate = PxTranslateSet(NULL, "latin1"); 1136 1137 /* The +2 is for the 1 pixel dark line on each side */ 1138 gui.border_offset = gui.border_width = GUI_PH_MARGIN + 2; 1139 1140 /* Handle close events ourselves */ 1141 PtSetArg(&args[ n++ ], Pt_ARG_WINDOW_MANAGED_FLAGS, Pt_FALSE, Ph_WM_CLOSE); 1142 PtSetArg(&args[ n++ ], Pt_ARG_WINDOW_NOTIFY_FLAGS, Pt_TRUE, 1143 Ph_WM_CLOSE | Ph_WM_RESIZE | Ph_WM_FOCUS); 1144 PtSetArg(&args[ n++ ], Pt_ARG_DIM, &window_size, 0); 1145 gui.vimWindow = PtCreateWidget(PtWindow, NULL, n, args); 1146 if (gui.vimWindow == NULL) 1147 return FAIL; 1148 1149 PtAddCallback(gui.vimWindow, Pt_CB_WINDOW, gui_ph_handle_window_cb, NULL); 1150 PtAddCallback(gui.vimWindow, Pt_CB_WINDOW_OPENING, 1151 gui_ph_handle_window_open, NULL); 1152 1153 n = 0; 1154 PtSetArg(&args[ n++ ], Pt_ARG_ANCHOR_FLAGS, Pt_ANCHOR_ALL, Pt_IS_ANCHORED); 1155 PtSetArg(&args[ n++ ], Pt_ARG_DIM, &window_size, 0); 1156 PtSetArg(&args[ n++ ], Pt_ARG_POS, &pos, 0); 1157 1158 #ifdef USE_PANEL_GROUP 1159 /* Put in a temporary place holder title */ 1160 PtSetArg(&args[ n++ ], Pt_ARG_PG_PANEL_TITLES, &empty_title, 1); 1161 1162 gui.vimPanelGroup = PtCreateWidget(PtPanelGroup, gui.vimWindow, n, args); 1163 if (gui.vimPanelGroup == NULL) 1164 return FAIL; 1165 1166 PtAddCallback(gui.vimPanelGroup, Pt_CB_PG_PANEL_SWITCHING, 1167 gui_ph_handle_pg_change, NULL); 1168 #else 1169 /* Turn off all edge decorations */ 1170 PtSetArg(&args[ n++ ], Pt_ARG_BASIC_FLAGS, Pt_FALSE, Pt_ALL); 1171 PtSetArg(&args[ n++ ], Pt_ARG_BEVEL_WIDTH, 0, 0); 1172 PtSetArg(&args[ n++ ], Pt_ARG_MARGIN_WIDTH, 0, 0); 1173 PtSetArg(&args[ n++ ], Pt_ARG_MARGIN_HEIGHT, 0, 0); 1174 PtSetArg(&args[ n++ ], Pt_ARG_CONTAINER_FLAGS, Pt_TRUE, Pt_AUTO_EXTENT); 1175 1176 gui.vimContainer = PtCreateWidget(PtPane, gui.vimWindow, n, args); 1177 if (gui.vimContainer == NULL) 1178 return FAIL; 1179 1180 PtAddCallback(gui.vimContainer, Pt_CB_RESIZE, gui_ph_pane_resize, NULL); 1181 #endif 1182 1183 /* Size for the text area is set in gui_mch_set_text_area_pos */ 1184 n = 0; 1185 1186 PtSetArg(&args[ n++ ], Pt_ARG_RAW_DRAW_F, gui_ph_handle_raw_draw, 1); 1187 PtSetArg(&args[ n++ ], Pt_ARG_BEVEL_WIDTH, GUI_PH_MARGIN, 0); 1188 /* 1189 * Using focus render also causes the whole widget to be redrawn 1190 * whenever it changes focus, which is very annoying :p 1191 */ 1192 PtSetArg(&args[ n++ ], Pt_ARG_FLAGS, Pt_TRUE, 1193 Pt_GETS_FOCUS | Pt_HIGHLIGHTED); 1194 #ifndef FEAT_MOUSESHAPE 1195 PtSetArg(&args[ n++ ], Pt_ARG_CURSOR_TYPE, GUI_PH_MOUSE_TYPE, 0); 1196 PtSetArg(&args[ n++ ], Pt_ARG_CURSOR_COLOR, gui_ph_mouse_color, 0); 1197 #endif 1198 1199 gui.vimTextArea = PtCreateWidget(PtRaw, Pt_DFLT_PARENT, n, args); 1200 if (gui.vimTextArea == NULL) 1201 return FAIL; 1202 1203 /* TODO: use PtAddEventHandlers instead? */ 1204 /* Not using Ph_EV_BUT_REPEAT because vim wouldn't use it anyway */ 1205 PtAddEventHandler(gui.vimTextArea, 1206 Ph_EV_BUT_PRESS | Ph_EV_BUT_RELEASE | Ph_EV_PTR_MOTION_BUTTON, 1207 gui_ph_handle_mouse, NULL); 1208 PtAddEventHandler(gui.vimTextArea, Ph_EV_KEY, 1209 gui_ph_handle_keyboard, NULL); 1210 PtAddCallback(gui.vimTextArea, Pt_CB_GOT_FOCUS, 1211 gui_ph_handle_focus, NULL); 1212 PtAddCallback(gui.vimTextArea, Pt_CB_LOST_FOCUS, 1213 gui_ph_handle_focus, NULL); 1214 1215 /* 1216 * Now that the text area widget has been created, set up the colours, 1217 * which wil call PtSetResource from gui_mch_new_colors 1218 */ 1219 1220 /* 1221 * Create the two timers, not as accurate as using the kernel timer 1222 * functions, but good enough 1223 */ 1224 gui_ph_timer_cursor = PtCreateWidget(PtTimer, gui.vimWindow, 0, NULL); 1225 if (gui_ph_timer_cursor == NULL) 1226 return FAIL; 1227 1228 gui_ph_timer_timeout = PtCreateWidget(PtTimer, gui.vimWindow, 0, NULL); 1229 if (gui_ph_timer_timeout == NULL) 1230 return FAIL; 1231 1232 PtAddCallback(gui_ph_timer_cursor, Pt_CB_TIMER_ACTIVATE, 1233 gui_ph_handle_timer_cursor, NULL); 1234 PtAddCallback(gui_ph_timer_timeout, Pt_CB_TIMER_ACTIVATE, 1235 gui_ph_handle_timer_timeout, NULL); 1236 1237 #ifdef FEAT_MENU 1238 n = 0; 1239 PtSetArg(&args[ n++ ], Pt_ARG_WIDTH, window_size.w, 0); 1240 PtSetArg(&args[ n++ ], Pt_ARG_ANCHOR_FLAGS, Pt_ANCHOR_LEFT_RIGHT, 1241 Pt_IS_ANCHORED); 1242 gui.vimToolBarGroup = PtCreateWidget(PtToolbarGroup, gui.vimWindow, 1243 n, args); 1244 if (gui.vimToolBarGroup == NULL) 1245 return FAIL; 1246 1247 PtAddCallback(gui.vimToolBarGroup, Pt_CB_RESIZE, 1248 gui_ph_handle_menu_resize, NULL); 1249 1250 n = 0; 1251 flags = 0; 1252 PtSetArg(&args[ n++ ], Pt_ARG_WIDTH, window_size.w, 0); 1253 if (! vim_strchr(p_go, GO_MENUS)) 1254 { 1255 flags |= Pt_DELAY_REALIZE; 1256 PtSetArg(&args[ n++ ], Pt_ARG_FLAGS, Pt_TRUE, flags); 1257 } 1258 gui.vimMenuBar = PtCreateWidget(PtMenuBar, gui.vimToolBarGroup, n, args); 1259 if (gui.vimMenuBar == NULL) 1260 return FAIL; 1261 1262 # ifdef FEAT_TOOLBAR 1263 n = 0; 1264 1265 PtSetArg(&args[ n++ ], Pt_ARG_ANCHOR_FLAGS, 1266 Pt_ANCHOR_LEFT_RIGHT |Pt_TOP_ANCHORED_TOP, Pt_IS_ANCHORED); 1267 PtSetArg(&args[ n++ ], Pt_ARG_RESIZE_FLAGS, Pt_TRUE, 1268 Pt_RESIZE_Y_AS_REQUIRED); 1269 PtSetArg(&args[ n++ ], Pt_ARG_WIDTH, window_size.w, 0); 1270 1271 flags = Pt_GETS_FOCUS; 1272 if (! vim_strchr(p_go, GO_TOOLBAR)) 1273 flags |= Pt_DELAY_REALIZE; 1274 1275 PtSetArg(&args[ n++ ], Pt_ARG_FLAGS, Pt_DELAY_REALIZE, flags); 1276 1277 gui.vimToolBar = PtCreateWidget(PtToolbar, gui.vimToolBarGroup, n, args); 1278 if (gui.vimToolBar == NULL) 1279 return FAIL; 1280 1281 /* 1282 * Size for the toolbar is fetched in gui_mch_show_toolbar, after 1283 * the buttons have been added and the toolbar has resized it's height 1284 * for the buttons to fit 1285 */ 1286 # endif 1287 1288 #endif 1289 1290 return OK; 1291 } 1292 1293 int 1294 gui_mch_init_check(void) 1295 { 1296 return (is_photon_available == TRUE) ? OK : FAIL; 1297 } 1298 1299 int 1300 gui_mch_open(void) 1301 { 1302 gui.norm_pixel = Pg_BLACK; 1303 gui.back_pixel = Pg_WHITE; 1304 1305 set_normal_colors(); 1306 1307 gui_check_colors(); 1308 gui.def_norm_pixel = gui.norm_pixel; 1309 gui.def_back_pixel = gui.back_pixel; 1310 1311 highlight_gui_started(); 1312 1313 if (gui_win_x != -1 && gui_win_y != -1) 1314 gui_mch_set_winpos(gui_win_x, gui_win_y); 1315 1316 return (PtRealizeWidget(gui.vimWindow) == 0) ? OK : FAIL; 1317 } 1318 1319 void 1320 gui_mch_exit(int rc) 1321 { 1322 PtDestroyWidget(gui.vimWindow); 1323 1324 PxTranslateSet(charset_translate, NULL); 1325 1326 vim_free(gui.event_buffer); 1327 1328 #ifdef USE_PANEL_GROUPS 1329 vim_free(panel_titles); 1330 #endif 1331 } 1332 1333 /****************************************************************************/ 1334 /* events */ 1335 1336 /* When no events are available, photon will call this function, working is 1337 * set to FALSE, and the gui_mch_update loop will exit. */ 1338 static int 1339 exit_gui_mch_update(void *data) 1340 { 1341 *(int *)data = FALSE; 1342 return Pt_END; 1343 } 1344 1345 void 1346 gui_mch_update(void) 1347 { 1348 int working = TRUE; 1349 1350 PtAppAddWorkProc(NULL, exit_gui_mch_update, &working); 1351 while ((working == TRUE) && !vim_is_input_buf_full()) 1352 { 1353 PtProcessEvent(); 1354 } 1355 } 1356 1357 int 1358 gui_mch_wait_for_chars(int wtime) 1359 { 1360 is_timeout = FALSE; 1361 1362 if (wtime > 0) 1363 PtSetResource(gui_ph_timer_timeout, Pt_ARG_TIMER_INITIAL, wtime, 0); 1364 1365 while (1) 1366 { 1367 PtProcessEvent(); 1368 if (input_available()) 1369 { 1370 PtSetResource(gui_ph_timer_timeout, Pt_ARG_TIMER_INITIAL, 0, 0); 1371 return OK; 1372 } 1373 else if (is_timeout == TRUE) 1374 return FAIL; 1375 } 1376 } 1377 1378 #if defined(FEAT_BROWSE) || defined(PROTO) 1379 /* 1380 * Put up a file requester. 1381 * Returns the selected name in allocated memory, or NULL for Cancel. 1382 * saving, select file to write 1383 * title title for the window 1384 * default_name default name (well duh!) 1385 * ext not used (extension added) 1386 * initdir initial directory, NULL for current dir 1387 * filter not used (file name filter) 1388 */ 1389 char_u * 1390 gui_mch_browse( 1391 int saving, 1392 char_u *title, 1393 char_u *default_name, 1394 char_u *ext, 1395 char_u *initdir, 1396 char_u *filter) 1397 { 1398 PtFileSelectionInfo_t file; 1399 int flags; 1400 char_u *default_path; 1401 char_u *open_text = NULL; 1402 1403 flags = 0; 1404 memset(&file, 0, sizeof(file)); 1405 1406 default_path = alloc(MAXPATHL + 1 + NAME_MAX + 1); 1407 if (default_path != NULL) 1408 { 1409 if (saving == TRUE) 1410 { 1411 /* Don't need Pt_FSR_CONFIRM_EXISTING, vim will ask anyway */ 1412 flags |= Pt_FSR_NO_FCHECK; 1413 open_text = "&Save"; 1414 } 1415 1416 /* combine the directory and filename into a single path */ 1417 if (initdir == NULL || *initdir == NUL) 1418 { 1419 mch_dirname(default_path, MAXPATHL); 1420 initdir = default_path; 1421 } 1422 else 1423 { 1424 STRCPY(default_path, initdir); 1425 initdir = default_path; 1426 } 1427 1428 if (default_name != NULL) 1429 { 1430 if (default_path[ STRLEN(default_path) - 1 ] != '/') 1431 STRCAT(default_path, "/"); 1432 1433 STRCAT(default_path, default_name); 1434 } 1435 1436 /* TODO: add a filter? */ 1437 PtFileSelection( 1438 gui.vimWindow, 1439 NULL, 1440 title, 1441 default_path, 1442 NULL, 1443 open_text, 1444 NULL, 1445 NULL, 1446 &file, 1447 flags); 1448 1449 vim_free(default_path); 1450 1451 if (file.ret == Pt_FSDIALOG_BTN1) 1452 return vim_strsave(file.path); 1453 } 1454 return NULL; 1455 } 1456 #endif 1457 1458 #if defined(FEAT_GUI_DIALOG) || defined(PROTO) 1459 static PtWidget_t *gui_ph_dialog_text = NULL; 1460 1461 static int 1462 gui_ph_dialog_close(int button, void *data) 1463 { 1464 PtModalCtrl_t *modal_ctrl = data; 1465 char_u *dialog_text, *vim_text; 1466 1467 if (gui_ph_dialog_text != NULL) 1468 { 1469 PtGetResource(gui_ph_dialog_text, Pt_ARG_TEXT_STRING, &dialog_text, 0); 1470 PtGetResource(gui_ph_dialog_text, Pt_ARG_POINTER, &vim_text, 0); 1471 STRNCPY(vim_text, dialog_text, IOSIZE - 1); 1472 } 1473 1474 PtModalUnblock(modal_ctrl, (void *) button); 1475 1476 return Pt_TRUE; 1477 } 1478 1479 static int 1480 gui_ph_dialog_text_enter(PtWidget_t *widget, void *data, PtCallbackInfo_t *info) 1481 { 1482 if (info->reason_subtype == Pt_EDIT_ACTIVATE) 1483 gui_ph_dialog_close(1, data); 1484 return Pt_CONTINUE; 1485 } 1486 1487 static int 1488 gui_ph_dialog_esc(PtWidget_t *widget, void *data, PtCallbackInfo_t *info) 1489 { 1490 PhKeyEvent_t *key; 1491 1492 key = PhGetData(info->event); 1493 if ((key->key_flags & Pk_KF_Cap_Valid) && (key->key_cap == Pk_Escape)) 1494 { 1495 gui_ph_dialog_close(0, data); 1496 return Pt_CONSUME; 1497 } 1498 return Pt_PROCESS; 1499 } 1500 1501 int 1502 gui_mch_dialog( 1503 int type, 1504 char_u *title, 1505 char_u *message, 1506 char_u *buttons, 1507 int default_button, 1508 char_u *textfield, 1509 int ex_cmd) 1510 { 1511 char_u *str; 1512 char_u **button_array; 1513 char_u *buttons_copy; 1514 1515 int button_count; 1516 int i, len; 1517 int dialog_result = -1; 1518 1519 /* FIXME: the vertical option in guioptions is blatantly ignored */ 1520 /* FIXME: so is the type */ 1521 1522 button_count = len = i = 0; 1523 1524 if (buttons == NULL || *buttons == NUL) 1525 return -1; 1526 1527 /* There is one less separator than buttons, so bump up the button count */ 1528 button_count = 1; 1529 1530 /* Count string length and number of separators */ 1531 for (str = buttons; *str; str++) 1532 { 1533 len++; 1534 if (*str == DLG_BUTTON_SEP) 1535 button_count++; 1536 } 1537 1538 if (title == NULL) 1539 title = "Vim"; 1540 1541 buttons_copy = alloc(len + 1); 1542 button_array = (char_u **) alloc(button_count * sizeof(char_u *)); 1543 if (buttons_copy != NULL && button_array != NULL) 1544 { 1545 STRCPY(buttons_copy, buttons); 1546 1547 /* 1548 * Convert DLG_BUTTON_SEP into NUL's and fill in 1549 * button_array with the pointer to each NUL terminated string 1550 */ 1551 str = buttons_copy; 1552 for (i = 0; i < button_count; i++) 1553 { 1554 button_array[ i ] = str; 1555 for (; *str; str++) 1556 { 1557 if (*str == DLG_BUTTON_SEP) 1558 { 1559 *str++ = NUL; 1560 break; 1561 } 1562 } 1563 } 1564 #ifndef FEAT_GUI_TEXTDIALOG 1565 dialog_result = PtAlert( 1566 gui.vimWindow, NULL, 1567 title, 1568 NULL, 1569 message, NULL, 1570 button_count, (const char **) button_array, NULL, 1571 default_button, 0, Pt_MODAL); 1572 #else 1573 /* Writing the dialog ourselves lets us add extra features, like 1574 * trapping the escape key and returning 0 to vim */ 1575 { 1576 int n; 1577 PtArg_t args[5]; 1578 PtWidget_t *dialog, *pane; 1579 PtModalCtrl_t modal_ctrl; 1580 PtDialogInfo_t di; 1581 1582 memset(&di, 0, sizeof(di)); 1583 memset(&modal_ctrl, 0, sizeof(modal_ctrl)); 1584 1585 n = 0; 1586 PtSetArg(&args[n++], Pt_ARG_GROUP_ROWS_COLS, 0, 0); 1587 PtSetArg(&args[n++], Pt_ARG_WIDTH, 350, 0); 1588 PtSetArg(&args[n++], Pt_ARG_GROUP_ORIENTATION, 1589 Pt_GROUP_VERTICAL, 0); 1590 PtSetArg(&args[n++], Pt_ARG_GROUP_FLAGS, 1591 Pt_TRUE, Pt_GROUP_NO_KEYS | Pt_GROUP_STRETCH_HORIZONTAL); 1592 PtSetArg(&args[n++], Pt_ARG_CONTAINER_FLAGS, Pt_FALSE, Pt_TRUE); 1593 pane = PtCreateWidget(PtGroup, NULL, n, args); 1594 1595 n = 0; 1596 PtSetArg(&args[n++], Pt_ARG_TEXT_STRING, message, 0); 1597 PtCreateWidget(PtLabel, pane, n, args); 1598 1599 if (textfield != NULL) 1600 { 1601 n = 0; 1602 PtSetArg(&args[n++], Pt_ARG_MAX_LENGTH, IOSIZE - 1, 0); 1603 PtSetArg(&args[n++], Pt_ARG_TEXT_STRING, textfield, 0); 1604 PtSetArg(&args[n++], Pt_ARG_POINTER, textfield, 0); 1605 gui_ph_dialog_text = PtCreateWidget(PtText, pane, n, args); 1606 PtAddCallback(gui_ph_dialog_text, Pt_CB_ACTIVATE, 1607 gui_ph_dialog_text_enter, &modal_ctrl); 1608 } 1609 1610 di.parent = gui.vimWindow; 1611 di.pane = pane; 1612 di.title = title; 1613 di.buttons = (const char **) button_array; 1614 di.nbtns = button_count; 1615 di.def_btn = default_button; 1616 /* This is just to give the dialog the close button. 1617 * We check for the Escape key ourselves and return 0 */ 1618 di.esc_btn = button_count; 1619 di.callback = gui_ph_dialog_close; 1620 di.data = &modal_ctrl; 1621 1622 dialog = PtCreateDialog(&di); 1623 PtAddFilterCallback(dialog, Ph_EV_KEY, 1624 gui_ph_dialog_esc, &modal_ctrl); 1625 1626 if (gui_ph_dialog_text != NULL) 1627 PtGiveFocus(gui_ph_dialog_text, NULL); 1628 1629 /* Open dialog, block the vim window and wait for the dialog to close */ 1630 PtRealizeWidget(dialog); 1631 PtMakeModal(dialog, Ph_CURSOR_NOINPUT, Ph_CURSOR_DEFAULT_COLOR); 1632 dialog_result = (int) PtModalBlock(&modal_ctrl, 0); 1633 1634 PtDestroyWidget(dialog); 1635 gui_ph_dialog_text = NULL; 1636 } 1637 #endif 1638 } 1639 1640 vim_free(button_array); 1641 vim_free(buttons_copy); 1642 1643 return dialog_result; 1644 } 1645 #endif 1646 /****************************************************************************/ 1647 /* window size/position/state */ 1648 1649 int 1650 gui_mch_get_winpos(int *x, int *y) 1651 { 1652 PhPoint_t *pos; 1653 1654 pos = PtWidgetPos(gui.vimWindow, NULL); 1655 1656 *x = pos->x; 1657 *y = pos->y; 1658 1659 return OK; 1660 } 1661 1662 void 1663 gui_mch_set_winpos(int x, int y) 1664 { 1665 PhPoint_t pos = { x, y }; 1666 1667 PtSetResource(gui.vimWindow, Pt_ARG_POS, &pos, 0); 1668 } 1669 1670 void 1671 gui_mch_set_shellsize(int width, int height, 1672 int min_width, int min_height, int base_width, int base_height, 1673 int direction) 1674 { 1675 PhDim_t window_size = { width, height }; 1676 PhDim_t min_size = { min_width, min_height }; 1677 1678 #ifdef USE_PANEL_GROUP 1679 window_size.w += pg_margin_left + pg_margin_right; 1680 window_size.h += pg_margin_top + pg_margin_bottom; 1681 #endif 1682 1683 PtSetResource(gui.vimWindow, Pt_ARG_MINIMUM_DIM, &min_size, 0); 1684 PtSetResource(gui.vimWindow, Pt_ARG_DIM, &window_size, 0); 1685 1686 if (! PtWidgetIsRealized(gui.vimWindow)) 1687 gui_ph_resize_container(); 1688 } 1689 1690 /* 1691 * Return the amount of screen space that hasn't been allocated (such as 1692 * by the shelf). 1693 */ 1694 void 1695 gui_mch_get_screen_dimensions(int *screen_w, int *screen_h) 1696 { 1697 PhRect_t console; 1698 1699 PhWindowQueryVisible(Ph_QUERY_WORKSPACE, 0, 1700 PhInputGroup(NULL), &console); 1701 1702 *screen_w = console.lr.x - console.ul.x + 1; 1703 *screen_h = console.lr.y - console.ul.y + 1; 1704 } 1705 1706 void 1707 gui_mch_iconify(void) 1708 { 1709 PhWindowEvent_t event; 1710 1711 memset(&event, 0, sizeof (event)); 1712 event.event_f = Ph_WM_HIDE; 1713 event.event_state = Ph_WM_EVSTATE_HIDE; 1714 event.rid = PtWidgetRid(gui.vimWindow); 1715 PtForwardWindowEvent(&event); 1716 } 1717 1718 #if defined(FEAT_EVAL) || defined(PROTO) 1719 /* 1720 * Bring the Vim window to the foreground. 1721 */ 1722 void 1723 gui_mch_set_foreground() 1724 { 1725 PhWindowEvent_t event; 1726 1727 memset(&event, 0, sizeof (event)); 1728 event.event_f = Ph_WM_TOFRONT; 1729 event.event_state = Ph_WM_EVSTATE_FFRONT; 1730 event.rid = PtWidgetRid(gui.vimWindow); 1731 PtForwardWindowEvent(&event); 1732 } 1733 #endif 1734 1735 void 1736 gui_mch_settitle(char_u *title, char_u *icon) 1737 { 1738 #ifdef USE_PANEL_GROUP 1739 gui_ph_pg_set_buffer_num(curwin->w_buffer->b_fnum); 1740 #endif 1741 PtSetResource(gui.vimWindow, Pt_ARG_WINDOW_TITLE, title, 0); 1742 /* Not sure what to do with the icon text, set balloon text somehow? */ 1743 } 1744 1745 /****************************************************************************/ 1746 /* Scrollbar */ 1747 1748 void 1749 gui_mch_set_scrollbar_thumb(scrollbar_T *sb, int val, int size, int max) 1750 { 1751 int n = 0; 1752 PtArg_t args[3]; 1753 1754 PtSetArg(&args[ n++ ], Pt_ARG_MAXIMUM, max, 0); 1755 PtSetArg(&args[ n++ ], Pt_ARG_SLIDER_SIZE, size, 0); 1756 PtSetArg(&args[ n++ ], Pt_ARG_GAUGE_VALUE, val, 0); 1757 PtSetResources(sb->id, n, args); 1758 } 1759 1760 void 1761 gui_mch_set_scrollbar_pos(scrollbar_T *sb, int x, int y, int w, int h) 1762 { 1763 PhArea_t area = {{ x, y }, { w, h }}; 1764 1765 PtSetResource(sb->id, Pt_ARG_AREA, &area, 0); 1766 } 1767 1768 void 1769 gui_mch_create_scrollbar(scrollbar_T *sb, int orient) 1770 { 1771 int n = 0; 1772 /* int anchor_flags = 0;*/ 1773 PtArg_t args[4]; 1774 1775 /* 1776 * Stop the scrollbar from being realized when the parent 1777 * is realized, so it can be explicitly realized by vim. 1778 * 1779 * Also, don't let the scrollbar get focus 1780 */ 1781 PtSetArg(&args[ n++ ], Pt_ARG_FLAGS, Pt_DELAY_REALIZE, 1782 Pt_DELAY_REALIZE | Pt_GETS_FOCUS); 1783 PtSetArg(&args[ n++ ], Pt_ARG_SCROLLBAR_FLAGS, Pt_SCROLLBAR_SHOW_ARROWS, 0); 1784 #if 0 1785 /* Don't need this anchoring for the scrollbars */ 1786 if (orient == SBAR_HORIZ) 1787 { 1788 anchor_flags = Pt_BOTTOM_ANCHORED_BOTTOM | 1789 Pt_LEFT_ANCHORED_LEFT | Pt_RIGHT_ANCHORED_RIGHT; 1790 } 1791 else 1792 { 1793 anchor_flags = Pt_BOTTOM_ANCHORED_BOTTOM | Pt_TOP_ANCHORED_TOP; 1794 if (sb->wp != NULL) 1795 { 1796 if (sb == &sb->wp->w_scrollbars[ SBAR_LEFT ]) 1797 anchor_flags |= Pt_LEFT_ANCHORED_LEFT; 1798 else 1799 anchor_flags |= Pt_RIGHT_ANCHORED_RIGHT; 1800 } 1801 } 1802 PtSetArg(&args[ n++ ], Pt_ARG_ANCHOR_FLAGS, anchor_flags, Pt_IS_ANCHORED); 1803 #endif 1804 PtSetArg(&args[ n++ ], Pt_ARG_ORIENTATION, 1805 (orient == SBAR_HORIZ) ? Pt_HORIZONTAL : Pt_VERTICAL, 0); 1806 #ifdef USE_PANEL_GROUP 1807 sb->id = PtCreateWidget(PtScrollbar, gui.vimPanelGroup, n, args); 1808 #else 1809 sb->id = PtCreateWidget(PtScrollbar, gui.vimContainer, n, args); 1810 #endif 1811 1812 PtAddCallback(sb->id, Pt_CB_SCROLLBAR_MOVE, gui_ph_handle_scrollbar, sb); 1813 } 1814 1815 void 1816 gui_mch_enable_scrollbar(scrollbar_T *sb, int flag) 1817 { 1818 if (flag != 0) 1819 PtRealizeWidget(sb->id); 1820 else 1821 PtUnrealizeWidget(sb->id); 1822 } 1823 1824 void 1825 gui_mch_destroy_scrollbar(scrollbar_T *sb) 1826 { 1827 PtDestroyWidget(sb->id); 1828 sb->id = NULL; 1829 } 1830 1831 /****************************************************************************/ 1832 /* Mouse functions */ 1833 1834 #if defined(FEAT_MOUSESHAPE) || defined(PROTO) 1835 /* The last set mouse pointer shape is remembered, to be used when it goes 1836 * from hidden to not hidden. */ 1837 static int last_shape = 0; 1838 1839 /* Table for shape IDs. Keep in sync with the mshape_names[] table in 1840 * misc2.c! */ 1841 static int mshape_ids[] = 1842 { 1843 Ph_CURSOR_POINTER, /* arrow */ 1844 Ph_CURSOR_NONE, /* blank */ 1845 Ph_CURSOR_INSERT, /* beam */ 1846 Ph_CURSOR_DRAG_VERTICAL, /* updown */ 1847 Ph_CURSOR_DRAG_VERTICAL, /* udsizing */ 1848 Ph_CURSOR_DRAG_HORIZONTAL, /* leftright */ 1849 Ph_CURSOR_DRAG_HORIZONTAL, /* lrsizing */ 1850 Ph_CURSOR_WAIT, /* busy */ 1851 Ph_CURSOR_DONT, /* no */ 1852 Ph_CURSOR_CROSSHAIR, /* crosshair */ 1853 Ph_CURSOR_FINGER, /* hand1 */ 1854 Ph_CURSOR_FINGER, /* hand2 */ 1855 Ph_CURSOR_FINGER, /* pencil */ 1856 Ph_CURSOR_QUESTION_POINT, /* question */ 1857 Ph_CURSOR_POINTER, /* right-arrow */ 1858 Ph_CURSOR_POINTER, /* up-arrow */ 1859 Ph_CURSOR_POINTER /* last one */ 1860 }; 1861 1862 void 1863 mch_set_mouse_shape(shape) 1864 int shape; 1865 { 1866 int id; 1867 1868 if (!gui.in_use) 1869 return; 1870 1871 if (shape == MSHAPE_HIDE || gui.pointer_hidden) 1872 PtSetResource(gui.vimTextArea, Pt_ARG_CURSOR_TYPE, Ph_CURSOR_NONE, 1873 0); 1874 else 1875 { 1876 if (shape >= MSHAPE_NUMBERED) 1877 id = Ph_CURSOR_POINTER; 1878 else 1879 id = mshape_ids[shape]; 1880 1881 PtSetResource(gui.vimTextArea, Pt_ARG_CURSOR_TYPE, id, 0); 1882 } 1883 if (shape != MSHAPE_HIDE) 1884 last_shape = shape; 1885 } 1886 #endif 1887 1888 void 1889 gui_mch_mousehide(int hide) 1890 { 1891 if (gui.pointer_hidden != hide) 1892 { 1893 gui.pointer_hidden = hide; 1894 #ifdef FEAT_MOUSESHAPE 1895 if (hide) 1896 PtSetResource(gui.vimTextArea, Pt_ARG_CURSOR_TYPE, 1897 Ph_CURSOR_NONE, 0); 1898 else 1899 mch_set_mouse_shape(last_shape); 1900 #else 1901 PtSetResource(gui.vimTextArea, Pt_ARG_CURSOR_TYPE, 1902 (hide == MOUSE_SHOW) ? GUI_PH_MOUSE_TYPE : Ph_CURSOR_NONE, 1903 0); 1904 #endif 1905 } 1906 } 1907 1908 void 1909 gui_mch_getmouse(int *x, int *y) 1910 { 1911 PhCursorInfo_t info; 1912 short ix, iy; 1913 1914 /* FIXME: does this return the correct position, 1915 * with respect to the border? */ 1916 PhQueryCursor(PhInputGroup(NULL), &info); 1917 PtGetAbsPosition(gui.vimTextArea , &ix, &iy); 1918 1919 *x = info.pos.x - ix; 1920 *y = info.pos.y - iy; 1921 } 1922 1923 void 1924 gui_mch_setmouse(int x, int y) 1925 { 1926 short abs_x, abs_y; 1927 1928 PtGetAbsPosition(gui.vimTextArea, &abs_x, &abs_y); 1929 /* Add the border offset? */ 1930 PhMoveCursorAbs(PhInputGroup(NULL), abs_x + x, abs_y + y); 1931 } 1932 1933 /****************************************************************************/ 1934 /* Colours */ 1935 1936 /* 1937 * Return the RGB value of a pixel as a long. 1938 */ 1939 long_u 1940 gui_mch_get_rgb(guicolor_T pixel) 1941 { 1942 return PgRGB(PgRedValue(pixel), PgGreenValue(pixel), PgBlueValue(pixel)); 1943 } 1944 1945 void 1946 gui_mch_new_colors(void) 1947 { 1948 #if 0 /* Don't bother changing the cursor colour */ 1949 short color_diff; 1950 1951 /* 1952 * If there isn't enough difference between the background colour and 1953 * the mouse pointer colour then change the mouse pointer colour 1954 */ 1955 color_diff = gui_get_lightness(gui_ph_mouse_color) 1956 - gui_get_lightness(gui.back_pixel); 1957 1958 if (abs(color_diff) < 64) 1959 { 1960 short r, g, b; 1961 /* not a great algorithm... */ 1962 r = PgRedValue(gui_ph_mouse_color) ^ 255; 1963 g = PgGreenValue(gui_ph_mouse_color) ^ 255; 1964 b = PgBlueValue(gui_ph_mouse_color) ^ 255; 1965 1966 #ifndef FEAT_MOUSESHAPE 1967 gui_ph_mouse_color = PgRGB(r, g, b); 1968 PtSetResource(gui.vimTextArea, Pt_ARG_CURSOR_COLOR, 1969 gui_ph_mouse_color, 0); 1970 #endif 1971 } 1972 #endif 1973 1974 PtSetResource(gui.vimTextArea, Pt_ARG_FILL_COLOR, gui.back_pixel, 0); 1975 } 1976 1977 static int 1978 hex_digit(int c) 1979 { 1980 if (VIM_ISDIGIT(c)) 1981 return c - '0'; 1982 c = TOLOWER_ASC(c); 1983 if (c >= 'a' && c <= 'f') 1984 return c - 'a' + 10; 1985 return -1000; 1986 } 1987 1988 1989 /* 1990 * This should be split out into a separate file, 1991 * every port does basically the same thing. 1992 * 1993 * This is the gui_w32.c version (i think..) 1994 * Return INVALCOLOR when failed. 1995 */ 1996 1997 guicolor_T 1998 gui_mch_get_color(char_u *name) 1999 { 2000 int i; 2001 int r, g, b; 2002 2003 2004 typedef struct GuiColourTable 2005 { 2006 char *name; 2007 guicolor_T colour; 2008 } GuiColourTable; 2009 2010 static GuiColourTable table[] = 2011 { 2012 {"Black", RGB(0x00, 0x00, 0x00)}, 2013 {"DarkGray", RGB(0xA9, 0xA9, 0xA9)}, 2014 {"DarkGrey", RGB(0xA9, 0xA9, 0xA9)}, 2015 {"Gray", RGB(0xC0, 0xC0, 0xC0)}, 2016 {"Grey", RGB(0xC0, 0xC0, 0xC0)}, 2017 {"LightGray", RGB(0xD3, 0xD3, 0xD3)}, 2018 {"LightGrey", RGB(0xD3, 0xD3, 0xD3)}, 2019 {"Gray10", RGB(0x1A, 0x1A, 0x1A)}, 2020 {"Grey10", RGB(0x1A, 0x1A, 0x1A)}, 2021 {"Gray20", RGB(0x33, 0x33, 0x33)}, 2022 {"Grey20", RGB(0x33, 0x33, 0x33)}, 2023 {"Gray30", RGB(0x4D, 0x4D, 0x4D)}, 2024 {"Grey30", RGB(0x4D, 0x4D, 0x4D)}, 2025 {"Gray40", RGB(0x66, 0x66, 0x66)}, 2026 {"Grey40", RGB(0x66, 0x66, 0x66)}, 2027 {"Gray50", RGB(0x7F, 0x7F, 0x7F)}, 2028 {"Grey50", RGB(0x7F, 0x7F, 0x7F)}, 2029 {"Gray60", RGB(0x99, 0x99, 0x99)}, 2030 {"Grey60", RGB(0x99, 0x99, 0x99)}, 2031 {"Gray70", RGB(0xB3, 0xB3, 0xB3)}, 2032 {"Grey70", RGB(0xB3, 0xB3, 0xB3)}, 2033 {"Gray80", RGB(0xCC, 0xCC, 0xCC)}, 2034 {"Grey80", RGB(0xCC, 0xCC, 0xCC)}, 2035 {"Gray90", RGB(0xE5, 0xE5, 0xE5)}, 2036 {"Grey90", RGB(0xE5, 0xE5, 0xE5)}, 2037 {"White", RGB(0xFF, 0xFF, 0xFF)}, 2038 {"DarkRed", RGB(0x80, 0x00, 0x00)}, 2039 {"Red", RGB(0xFF, 0x00, 0x00)}, 2040 {"LightRed", RGB(0xFF, 0xA0, 0xA0)}, 2041 {"DarkBlue", RGB(0x00, 0x00, 0x80)}, 2042 {"Blue", RGB(0x00, 0x00, 0xFF)}, 2043 {"LightBlue", RGB(0xAD, 0xD8, 0xE6)}, 2044 {"DarkGreen", RGB(0x00, 0x80, 0x00)}, 2045 {"Green", RGB(0x00, 0xFF, 0x00)}, 2046 {"LightGreen", RGB(0x90, 0xEE, 0x90)}, 2047 {"DarkCyan", RGB(0x00, 0x80, 0x80)}, 2048 {"Cyan", RGB(0x00, 0xFF, 0xFF)}, 2049 {"LightCyan", RGB(0xE0, 0xFF, 0xFF)}, 2050 {"DarkMagenta", RGB(0x80, 0x00, 0x80)}, 2051 {"Magenta", RGB(0xFF, 0x00, 0xFF)}, 2052 {"LightMagenta", RGB(0xFF, 0xA0, 0xFF)}, 2053 {"Brown", RGB(0x80, 0x40, 0x40)}, 2054 {"Yellow", RGB(0xFF, 0xFF, 0x00)}, 2055 {"LightYellow", RGB(0xFF, 0xFF, 0xE0)}, 2056 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, 2057 {"Orange", RGB(0xFF, 0xA5, 0x00)}, 2058 {"Purple", RGB(0xA0, 0x20, 0xF0)}, 2059 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, 2060 {"Violet", RGB(0xEE, 0x82, 0xEE)}, 2061 }; 2062 2063 /* is name #rrggbb format? */ 2064 if (name[0] == '#' && STRLEN(name) == 7) 2065 { 2066 r = hex_digit(name[1]) * 16 + hex_digit(name[2]); 2067 g = hex_digit(name[3]) * 16 + hex_digit(name[4]); 2068 b = hex_digit(name[5]) * 16 + hex_digit(name[6]); 2069 if (r < 0 || g < 0 || b < 0) 2070 return INVALCOLOR; 2071 return RGB(r, g, b); 2072 } 2073 2074 for (i = 0; i < ARRAY_LENGTH(table); i++) 2075 { 2076 if (STRICMP(name, table[i].name) == 0) 2077 return table[i].colour; 2078 } 2079 2080 /* 2081 * Last attempt. Look in the file "$VIMRUNTIME/rgb.txt". 2082 */ 2083 { 2084 #define LINE_LEN 100 2085 FILE *fd; 2086 char line[LINE_LEN]; 2087 char_u *fname; 2088 2089 fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt"); 2090 if (fname == NULL) 2091 return INVALCOLOR; 2092 2093 fd = fopen((char *)fname, "rt"); 2094 vim_free(fname); 2095 if (fd == NULL) 2096 return INVALCOLOR; 2097 2098 while (!feof(fd)) 2099 { 2100 int len; 2101 int pos; 2102 char *color; 2103 2104 fgets(line, LINE_LEN, fd); 2105 len = STRLEN(line); 2106 2107 if (len <= 1 || line[len-1] != '\n') 2108 continue; 2109 2110 line[len-1] = '\0'; 2111 2112 i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos); 2113 if (i != 3) 2114 continue; 2115 2116 color = line + pos; 2117 2118 if (STRICMP(color, name) == 0) 2119 { 2120 fclose(fd); 2121 return (guicolor_T)RGB(r, g, b); 2122 } 2123 } 2124 2125 fclose(fd); 2126 } 2127 2128 2129 return INVALCOLOR; 2130 } 2131 2132 void 2133 gui_mch_set_fg_color(guicolor_T color) 2134 { 2135 PgSetTextColor(color); 2136 } 2137 2138 void 2139 gui_mch_set_bg_color(guicolor_T color) 2140 { 2141 PgSetFillColor(color); 2142 } 2143 2144 void 2145 gui_mch_set_sp_color(guicolor_T color) 2146 { 2147 } 2148 2149 void 2150 gui_mch_invert_rectangle(int row, int col, int nr, int nc) 2151 { 2152 PhRect_t rect; 2153 2154 rect.ul.x = FILL_X(col); 2155 rect.ul.y = FILL_Y(row); 2156 2157 /* FIXME: This has an off by one pixel problem */ 2158 rect.lr.x = rect.ul.x + nc * gui.char_width; 2159 rect.lr.y = rect.ul.y + nr * gui.char_height; 2160 if (nc > 0) 2161 rect.lr.x -= 1; 2162 if (nr > 0) 2163 rect.lr.y -= 1; 2164 2165 DRAW_START; 2166 PgSetDrawMode(Pg_DrawModeDSTINVERT); 2167 PgDrawRect(&rect, Pg_DRAW_FILL); 2168 PgSetDrawMode(Pg_DrawModeSRCCOPY); 2169 DRAW_END; 2170 } 2171 2172 void 2173 gui_mch_clear_block(int row1, int col1, int row2, int col2) 2174 { 2175 PhRect_t block = { 2176 { FILL_X(col1), FILL_Y(row1) }, 2177 { FILL_X(col2 + 1) - 1, FILL_Y(row2 + 1) - 1} 2178 }; 2179 2180 DRAW_START; 2181 gui_mch_set_bg_color(gui.back_pixel); 2182 PgDrawRect(&block, Pg_DRAW_FILL); 2183 DRAW_END; 2184 } 2185 2186 void 2187 gui_mch_clear_all() 2188 { 2189 PhRect_t text_rect = { 2190 { gui.border_width, gui.border_width }, 2191 { Columns * gui.char_width + gui.border_width - 1 , 2192 Rows * gui.char_height + gui.border_width - 1 } 2193 }; 2194 2195 if (is_ignore_draw == TRUE) 2196 return; 2197 2198 DRAW_START; 2199 gui_mch_set_bg_color(gui.back_pixel); 2200 PgDrawRect(&text_rect, Pg_DRAW_FILL); 2201 DRAW_END; 2202 } 2203 2204 void 2205 gui_mch_delete_lines(int row, int num_lines) 2206 { 2207 PhRect_t rect; 2208 PhPoint_t delta; 2209 2210 rect.ul.x = FILL_X(gui.scroll_region_left); 2211 rect.ul.y = FILL_Y(row + num_lines); 2212 2213 rect.lr.x = FILL_X(gui.scroll_region_right + 1) - 1; 2214 rect.lr.y = FILL_Y(gui.scroll_region_bot + 1) - 1; 2215 2216 PtWidgetOffset(gui.vimTextArea, &gui_ph_raw_offset); 2217 PhTranslatePoint(&gui_ph_raw_offset, PtWidgetPos(gui.vimTextArea, NULL)); 2218 PhTranslateRect(&rect, &gui_ph_raw_offset); 2219 2220 delta.x = 0; 2221 delta.y = -num_lines * gui.char_height; 2222 2223 PgFlush(); 2224 2225 PhBlit(PtWidgetRid(PtFindDisjoint(gui.vimTextArea)), &rect, &delta); 2226 2227 gui_clear_block( 2228 gui.scroll_region_bot - num_lines + 1, 2229 gui.scroll_region_left, 2230 gui.scroll_region_bot, 2231 gui.scroll_region_right); 2232 } 2233 2234 void 2235 gui_mch_insert_lines(int row, int num_lines) 2236 { 2237 PhRect_t rect; 2238 PhPoint_t delta; 2239 2240 rect.ul.x = FILL_X(gui.scroll_region_left); 2241 rect.ul.y = FILL_Y(row); 2242 2243 rect.lr.x = FILL_X(gui.scroll_region_right + 1) - 1; 2244 rect.lr.y = FILL_Y(gui.scroll_region_bot - num_lines + 1) - 1; 2245 2246 PtWidgetOffset(gui.vimTextArea, &gui_ph_raw_offset); 2247 PhTranslatePoint(&gui_ph_raw_offset, PtWidgetPos(gui.vimTextArea, NULL)); 2248 PhTranslateRect(&rect, &gui_ph_raw_offset); 2249 2250 delta.x = 0; 2251 delta.y = num_lines * gui.char_height; 2252 2253 PgFlush(); 2254 2255 PhBlit(PtWidgetRid(PtFindDisjoint(gui.vimTextArea)) , &rect, &delta); 2256 2257 gui_clear_block(row, gui.scroll_region_left, 2258 row + num_lines - 1, gui.scroll_region_right); 2259 } 2260 2261 void 2262 gui_mch_draw_string(int row, int col, char_u *s, int len, int flags) 2263 { 2264 static char *utf8_buffer = NULL; 2265 static int utf8_len = 0; 2266 2267 PhPoint_t pos = { TEXT_X(col), TEXT_Y(row) }; 2268 PhRect_t rect; 2269 2270 if (is_ignore_draw == TRUE) 2271 return; 2272 2273 DRAW_START; 2274 2275 if (!(flags & DRAW_TRANSP)) 2276 { 2277 PgDrawIRect( 2278 FILL_X(col), FILL_Y(row), 2279 FILL_X(col + len) - 1, FILL_Y(row + 1) - 1, 2280 Pg_DRAW_FILL); 2281 } 2282 2283 if (flags & DRAW_UNDERL) 2284 PgSetUnderline(gui.norm_pixel, Pg_TRANSPARENT, 0); 2285 2286 if (charset_translate != NULL 2287 #ifdef FEAT_MBYTE 2288 && enc_utf8 == 0 2289 #endif 2290 ) 2291 { 2292 int src_taken, dst_made; 2293 2294 /* Use a static buffer to avoid large amounts of de/allocations */ 2295 if (utf8_len < len) 2296 { 2297 utf8_buffer = realloc(utf8_buffer, len * MB_LEN_MAX); 2298 utf8_len = len; 2299 } 2300 2301 PxTranslateToUTF( 2302 charset_translate, 2303 s, 2304 len, 2305 &src_taken, 2306 utf8_buffer, 2307 utf8_len, 2308 &dst_made); 2309 s = utf8_buffer; 2310 len = dst_made; 2311 } 2312 2313 PgDrawText(s, len, &pos, 0); 2314 2315 if (flags & DRAW_BOLD) 2316 { 2317 /* FIXME: try and only calculate these values once... */ 2318 rect.ul.x = FILL_X(col) + 1; 2319 rect.ul.y = FILL_Y(row); 2320 rect.lr.x = FILL_X(col + len) - 1; 2321 rect.lr.y = FILL_Y(row + 1) - 1; 2322 /* PgSetUserClip(NULL) causes the scrollbar to not redraw... */ 2323 #if 0 2324 pos.x++; 2325 2326 PgSetUserClip(&rect); 2327 PgDrawText(s, len, &pos, 0); 2328 PgSetUserClip(NULL); 2329 #else 2330 rect.lr.y -= (p_linespace + 1) / 2; 2331 /* XXX: DrawTextArea doesn't work with phditto */ 2332 PgDrawTextArea(s, len, &rect, Pg_TEXT_BOTTOM); 2333 #endif 2334 } 2335 2336 if (flags & DRAW_UNDERL) 2337 PgSetUnderline(Pg_TRANSPARENT, Pg_TRANSPARENT, 0); 2338 2339 DRAW_END; 2340 } 2341 2342 /****************************************************************************/ 2343 /* Cursor */ 2344 2345 void 2346 gui_mch_draw_hollow_cursor(guicolor_T color) 2347 { 2348 PhRect_t r; 2349 2350 /* FIXME: Double width characters */ 2351 2352 r.ul.x = FILL_X(gui.col); 2353 r.ul.y = FILL_Y(gui.row); 2354 r.lr.x = r.ul.x + gui.char_width - 1; 2355 r.lr.y = r.ul.y + gui.char_height - 1; 2356 2357 DRAW_START; 2358 PgSetStrokeColor(color); 2359 PgDrawRect(&r, Pg_DRAW_STROKE); 2360 DRAW_END; 2361 } 2362 2363 void 2364 gui_mch_draw_part_cursor(int w, int h, guicolor_T color) 2365 { 2366 PhRect_t r; 2367 2368 r.ul.x = FILL_X(gui.col); 2369 r.ul.y = FILL_Y(gui.row) + gui.char_height - h; 2370 r.lr.x = r.ul.x + w - 1; 2371 r.lr.y = r.ul.y + h - 1; 2372 2373 DRAW_START; 2374 gui_mch_set_bg_color(color); 2375 PgDrawRect(&r, Pg_DRAW_FILL); 2376 DRAW_END; 2377 } 2378 2379 void 2380 gui_mch_set_blinking(long wait, long on, long off) 2381 { 2382 blink_waittime = wait; 2383 blink_ontime = on; 2384 blink_offtime = off; 2385 } 2386 2387 void 2388 gui_mch_start_blink(void) 2389 { 2390 /* Only turn on the timer on if none of the times are zero */ 2391 if (blink_waittime && blink_ontime && blink_offtime && gui.in_focus) 2392 { 2393 PtSetResource(gui_ph_timer_cursor, Pt_ARG_TIMER_INITIAL, 2394 blink_waittime, 0); 2395 blink_state = BLINK_ON; 2396 gui_update_cursor(TRUE, FALSE); 2397 } 2398 } 2399 2400 void 2401 gui_mch_stop_blink(void) 2402 { 2403 PtSetResource(gui_ph_timer_cursor, Pt_ARG_TIMER_INITIAL, 0, 0); 2404 2405 if (blink_state == BLINK_OFF) 2406 gui_update_cursor(TRUE, FALSE); 2407 2408 blink_state = BLINK_NONE; 2409 } 2410 2411 /****************************************************************************/ 2412 /* miscellaneous functions */ 2413 2414 void 2415 gui_mch_beep(void) 2416 { 2417 PtBeep(); 2418 } 2419 2420 void 2421 gui_mch_flash(int msec) 2422 { 2423 PgSetFillXORColor(Pg_BLACK, Pg_WHITE); 2424 PgSetDrawMode(Pg_DRAWMODE_XOR); 2425 gui_mch_clear_all(); 2426 gui_mch_flush(); 2427 2428 ui_delay((long) msec, TRUE); 2429 2430 gui_mch_clear_all(); 2431 PgSetDrawMode(Pg_DRAWMODE_OPAQUE); 2432 gui_mch_flush(); 2433 } 2434 2435 void 2436 gui_mch_flush(void) 2437 { 2438 PgFlush(); 2439 } 2440 2441 void 2442 gui_mch_set_text_area_pos(int x, int y, int w, int h) 2443 { 2444 PhArea_t area = {{x, y}, {w, h}}; 2445 2446 PtSetResource(gui.vimTextArea, Pt_ARG_AREA, &area, 0); 2447 } 2448 2449 int 2450 gui_mch_haskey(char_u *name) 2451 { 2452 int i; 2453 2454 for (i = 0; special_keys[i].key_sym != 0; i++) 2455 if (name[0] == special_keys[i].vim_code0 && 2456 name[1] == special_keys[i].vim_code1) 2457 return OK; 2458 return FAIL; 2459 } 2460 2461 /****************************************************************************/ 2462 /* Menu */ 2463 2464 #ifdef FEAT_TOOLBAR 2465 #include "toolbar.phi" 2466 2467 static PhImage_t *gui_ph_toolbar_images[] = { 2468 &tb_new_phi, 2469 &tb_open_phi, 2470 &tb_save_phi, 2471 &tb_undo_phi, 2472 &tb_redo_phi, 2473 &tb_cut_phi, 2474 &tb_copy_phi, 2475 &tb_paste_phi, 2476 &tb_print_phi, 2477 &tb_help_phi, 2478 &tb_find_phi, 2479 &tb_save_all_phi, 2480 &tb_save_session_phi, 2481 &tb_new_session_phi, 2482 &tb_load_session_phi, 2483 &tb_macro_phi, 2484 &tb_replace_phi, 2485 &tb_close_phi, 2486 &tb_maximize_phi, 2487 &tb_minimize_phi, 2488 &tb_split_phi, 2489 &tb_shell_phi, 2490 &tb_find_prev_phi, 2491 &tb_find_next_phi, 2492 &tb_find_help_phi, 2493 &tb_make_phi, 2494 &tb_jump_phi, 2495 &tb_ctags_phi, 2496 &tb_vsplit_phi, 2497 &tb_maxwidth_phi, 2498 &tb_minwidth_phi 2499 }; 2500 2501 static PhImage_t * 2502 gui_ph_toolbar_load_icon(char_u *iconfile) 2503 { 2504 static PhImage_t external_icon; 2505 PhImage_t *temp_phi = NULL; 2506 2507 temp_phi = PxLoadImage(iconfile, NULL); 2508 if (temp_phi != NULL) 2509 { 2510 /* The label widget will free the image/palette/etc. for us when 2511 * it's destroyed */ 2512 temp_phi->flags |= Ph_RELEASE_IMAGE_ALL; 2513 memcpy(&external_icon, temp_phi, sizeof(external_icon)); 2514 free(temp_phi); 2515 2516 temp_phi = &external_icon; 2517 } 2518 return temp_phi; 2519 } 2520 2521 /* 2522 * This returns either a builtin icon image, an external image or NULL 2523 * if it can't find either. The caller can't and doesn't need to try and 2524 * free() the returned image, and it can't store the image pointer. 2525 * (When setting the Pt_ARG_LABEL_IMAGE resource, the contents of the 2526 * PhImage_t are copied, and the original PhImage_t aren't needed anymore). 2527 */ 2528 static PhImage_t * 2529 gui_ph_toolbar_find_icon(vimmenu_T *menu) 2530 { 2531 char_u full_pathname[ MAXPATHL + 1 ]; 2532 PhImage_t *icon = NULL; 2533 2534 if (menu->icon_builtin == FALSE) 2535 { 2536 if (menu->iconfile != NULL) 2537 /* TODO: use gui_find_iconfile() */ 2538 icon = gui_ph_toolbar_load_icon(menu->iconfile); 2539 2540 /* TODO: Restrict loading to just .png? Search for any format? */ 2541 if ((icon == NULL) && 2542 ((gui_find_bitmap(menu->name, full_pathname, "gif") == OK) || 2543 (gui_find_bitmap(menu->name, full_pathname, "png") == OK))) 2544 icon = gui_ph_toolbar_load_icon(full_pathname); 2545 2546 if (icon != NULL) 2547 return icon; 2548 } 2549 2550 if (menu->iconidx >= 0 && 2551 (menu->iconidx < ARRAY_LENGTH(gui_ph_toolbar_images))) 2552 { 2553 return gui_ph_toolbar_images[menu->iconidx]; 2554 } 2555 2556 return NULL; 2557 } 2558 #endif 2559 2560 #if defined(FEAT_MENU) || defined(PROTO) 2561 void 2562 gui_mch_enable_menu(int flag) 2563 { 2564 if (flag != 0) 2565 PtRealizeWidget(gui.vimMenuBar); 2566 else 2567 PtUnrealizeWidget(gui.vimMenuBar); 2568 } 2569 2570 void 2571 gui_mch_set_menu_pos(int x, int y, int w, int h) 2572 { 2573 /* Nothing */ 2574 } 2575 2576 /* Change the position of a menu button in the parent */ 2577 static void 2578 gui_ph_position_menu(PtWidget_t *widget, int priority) 2579 { 2580 PtWidget_t *traverse; 2581 vimmenu_T *menu; 2582 2583 traverse = PtWidgetChildBack(PtWidgetParent(widget)); 2584 2585 /* Iterate through the list of widgets in traverse, until 2586 * we find the position we want to insert our widget into */ 2587 /* TODO: traverse from front to back, possible speedup? */ 2588 while (traverse != NULL) 2589 { 2590 PtGetResource(traverse, Pt_ARG_POINTER, &menu, 0); 2591 2592 if (menu != NULL && 2593 priority < menu->priority && 2594 widget != traverse) 2595 { 2596 /* Insert the widget before the current traverse widget */ 2597 PtWidgetInsert(widget, traverse, 1); 2598 return; 2599 } 2600 2601 traverse = PtWidgetBrotherInFront(traverse); 2602 } 2603 } 2604 2605 /* the index is ignored because it's not useful for our purposes */ 2606 void 2607 gui_mch_add_menu(vimmenu_T *menu, int index) 2608 { 2609 vimmenu_T *parent = menu->parent; 2610 char_u *accel_key; 2611 char_u mnemonic_str[MB_LEN_MAX]; 2612 int n; 2613 PtArg_t args[5]; 2614 2615 menu->submenu_id = menu->id = NULL; 2616 2617 if (menu_is_menubar(menu->name)) 2618 { 2619 2620 accel_key = vim_strchr(menu->name, '&'); 2621 if (accel_key != NULL) 2622 { 2623 mnemonic_str[0] = accel_key[1]; 2624 mnemonic_str[1] = NUL; 2625 } 2626 2627 /* Create the menu button */ 2628 n = 0; 2629 PtSetArg(&args[ n++ ], Pt_ARG_TEXT_STRING, menu->dname, 0); 2630 PtSetArg(&args[ n++ ], Pt_ARG_ACCEL_TEXT, menu->actext, 0); 2631 if (accel_key != NULL) 2632 PtSetArg(&args[ n++ ], Pt_ARG_ACCEL_KEY, mnemonic_str, 0); 2633 PtSetArg(&args[ n++ ], Pt_ARG_POINTER, menu, 0); 2634 2635 if (parent != NULL) 2636 PtSetArg(&args[ n++ ], Pt_ARG_BUTTON_TYPE, Pt_MENU_RIGHT, 0); 2637 2638 menu->id = PtCreateWidget(PtMenuButton, 2639 (parent == NULL) ? gui.vimMenuBar : parent->submenu_id, 2640 n, args); 2641 2642 PtAddCallback(menu->id, Pt_CB_ARM, gui_ph_handle_pulldown_menu, menu); 2643 2644 /* Create the actual menu */ 2645 n = 0; 2646 if (parent != NULL) 2647 PtSetArg(&args[ n++ ], Pt_ARG_MENU_FLAGS, Pt_TRUE, Pt_MENU_CHILD); 2648 2649 menu->submenu_id = PtCreateWidget(PtMenu, menu->id, n, args); 2650 2651 if (parent == NULL) 2652 { 2653 PtAddCallback(menu->submenu_id, Pt_CB_UNREALIZED, 2654 gui_ph_handle_menu_unrealized, menu); 2655 2656 if (menu->mnemonic != 0) 2657 { 2658 PtAddHotkeyHandler(gui.vimWindow, tolower(menu->mnemonic), 2659 Pk_KM_Alt, 0, menu, gui_ph_handle_pulldown_menu); 2660 } 2661 } 2662 2663 gui_ph_position_menu(menu->id, menu->priority); 2664 2665 /* Redraw menubar here instead of gui_mch_draw_menubar */ 2666 if (gui.menu_is_active) 2667 PtRealizeWidget(menu->id); 2668 } 2669 else if (menu_is_popup(menu->name)) 2670 { 2671 menu->submenu_id = PtCreateWidget(PtMenu, gui.vimWindow, 0, NULL); 2672 PtAddCallback(menu->submenu_id, Pt_CB_UNREALIZED, 2673 gui_ph_handle_menu_unrealized, menu); 2674 } 2675 } 2676 2677 void 2678 gui_mch_add_menu_item(vimmenu_T *menu, int index) 2679 { 2680 vimmenu_T *parent = menu->parent; 2681 char_u *accel_key; 2682 char_u mnemonic_str[MB_LEN_MAX]; 2683 int n; 2684 PtArg_t args[13]; 2685 2686 n = 0; 2687 PtSetArg(&args[ n++ ], Pt_ARG_POINTER, menu, 0); 2688 2689 #ifdef FEAT_TOOLBAR 2690 if (menu_is_toolbar(parent->name)) 2691 { 2692 if (menu_is_separator(menu->name)) 2693 { 2694 PtSetArg(&args[ n++ ], Pt_ARG_SEP_FLAGS, 2695 Pt_SEP_VERTICAL, Pt_SEP_ORIENTATION); 2696 PtSetArg(&args[ n++ ], Pt_ARG_SEP_TYPE, Pt_ETCHED_IN, 0); 2697 PtSetArg(&args[ n++ ], Pt_ARG_ANCHOR_FLAGS, 2698 Pt_TRUE, Pt_ANCHOR_TOP_BOTTOM); 2699 PtSetArg(&args[ n++ ], Pt_ARG_WIDTH, 2, 0); 2700 menu->id = PtCreateWidget(PtSeparator, gui.vimToolBar, n, args); 2701 } 2702 else 2703 { 2704 if (strstr((const char *) p_toolbar, "text") != NULL) 2705 { 2706 PtSetArg(&args[ n++ ], Pt_ARG_BALLOON_POSITION, 2707 Pt_BALLOON_BOTTOM, 0); 2708 PtSetArg(&args[ n++ ], Pt_ARG_TEXT_STRING, menu->dname, 0); 2709 PtSetArg(&args[ n++ ], Pt_ARG_TEXT_FONT, "TextFont08", 0); 2710 } 2711 if ((strstr((const char *) p_toolbar, "icons") != NULL) && 2712 (gui_ph_toolbar_images != NULL)) 2713 { 2714 PtSetArg(&args[ n++ ], Pt_ARG_LABEL_IMAGE, 2715 gui_ph_toolbar_find_icon(menu), 0); 2716 PtSetArg(&args[ n++ ], Pt_ARG_LABEL_TYPE, Pt_TEXT_IMAGE, 0); 2717 PtSetArg(&args[ n++ ], Pt_ARG_TEXT_IMAGE_SPACING, 0, 0); 2718 } 2719 if (strstr((const char *) p_toolbar, "tooltips") != NULL) 2720 { 2721 PtSetArg(&args[ n++ ], Pt_ARG_LABEL_BALLOON, 2722 gui_ph_show_tooltip, 0); 2723 PtSetArg(&args[ n++ ], Pt_ARG_LABEL_FLAGS, 2724 Pt_TRUE, Pt_SHOW_BALLOON); 2725 } 2726 PtSetArg(&args[ n++ ], Pt_ARG_MARGIN_HEIGHT, 1, 0); 2727 PtSetArg(&args[ n++ ], Pt_ARG_MARGIN_WIDTH, 1, 0); 2728 PtSetArg(&args[ n++ ], Pt_ARG_FLAGS, Pt_FALSE, 2729 Pt_HIGHLIGHTED | Pt_GETS_FOCUS); 2730 PtSetArg(&args[ n++ ], Pt_ARG_FILL_COLOR, Pg_TRANSPARENT, 0); 2731 menu->id = PtCreateWidget(PtButton, gui.vimToolBar, n, args); 2732 2733 PtAddCallback(menu->id, Pt_CB_ACTIVATE, gui_ph_handle_menu, menu); 2734 } 2735 /* Update toolbar if it's open */ 2736 if (PtWidgetIsRealized(gui.vimToolBar)) 2737 PtRealizeWidget(menu->id); 2738 } 2739 else 2740 #endif 2741 if (menu_is_separator(menu->name)) 2742 { 2743 menu->id = PtCreateWidget(PtSeparator, parent->submenu_id, n, args); 2744 } 2745 else 2746 { 2747 accel_key = vim_strchr(menu->name, '&'); 2748 if (accel_key != NULL) 2749 { 2750 mnemonic_str[0] = accel_key[1]; 2751 mnemonic_str[1] = NUL; 2752 } 2753 2754 PtSetArg(&args[ n++ ], Pt_ARG_TEXT_STRING, menu->dname, 0); 2755 if (accel_key != NULL) 2756 PtSetArg(&args[ n++ ], Pt_ARG_ACCEL_KEY, mnemonic_str, 2757 0); 2758 2759 PtSetArg(&args[ n++ ], Pt_ARG_ACCEL_TEXT, menu->actext, 0); 2760 2761 menu->id = PtCreateWidget(PtMenuButton, parent->submenu_id, n, args); 2762 2763 PtAddCallback(menu->id, Pt_CB_ACTIVATE, gui_ph_handle_menu, menu); 2764 2765 #ifdef USE_PANEL_GROUP 2766 if (gui_ph_is_buffer_item(menu, parent) == TRUE) 2767 { 2768 PtAddCallback(menu->id, Pt_CB_DESTROYED, 2769 gui_ph_handle_buffer_remove, menu); 2770 gui_ph_pg_add_buffer(menu->dname); 2771 } 2772 #endif 2773 } 2774 2775 gui_ph_position_menu(menu->id, menu->priority); 2776 } 2777 2778 void 2779 gui_mch_destroy_menu(vimmenu_T *menu) 2780 { 2781 if (menu->submenu_id != NULL) 2782 PtDestroyWidget(menu->submenu_id); 2783 if (menu->id != NULL) 2784 PtDestroyWidget(menu->id); 2785 2786 menu->submenu_id = NULL; 2787 menu->id = NULL; 2788 } 2789 2790 void 2791 gui_mch_menu_grey(vimmenu_T *menu, int grey) 2792 { 2793 long flags, mask, fields; 2794 2795 if (menu->id == NULL) 2796 return; 2797 2798 flags = PtWidgetFlags(menu->id); 2799 if (PtWidgetIsClass(menu->id, PtMenuButton) && 2800 PtWidgetIsClass(PtWidgetParent(menu->id), PtMenu)) 2801 { 2802 fields = Pt_FALSE; 2803 mask = Pt_SELECTABLE | Pt_HIGHLIGHTED; 2804 } 2805 else 2806 { 2807 fields = Pt_TRUE; 2808 mask = Pt_BLOCKED | Pt_GHOST; 2809 } 2810 2811 if (! grey) 2812 fields = ~fields; 2813 2814 PtSetResource(menu->id, Pt_ARG_FLAGS, fields, 2815 mask); 2816 } 2817 2818 void 2819 gui_mch_menu_hidden(vimmenu_T *menu, int hidden) 2820 { 2821 /* TODO: [un]realize the widget? */ 2822 } 2823 2824 void 2825 gui_mch_draw_menubar(void) 2826 { 2827 /* The only time a redraw is needed is when a menu button 2828 * is added to the menubar, and that is detected and the bar 2829 * redrawn in gui_mch_add_menu_item 2830 */ 2831 } 2832 2833 void 2834 gui_mch_show_popupmenu(vimmenu_T *menu) 2835 { 2836 PtSetResource(menu->submenu_id, Pt_ARG_POS, &abs_mouse, 0); 2837 PtRealizeWidget(menu->submenu_id); 2838 } 2839 2840 void 2841 gui_mch_toggle_tearoffs(int enable) 2842 { 2843 /* No tearoffs yet */ 2844 } 2845 2846 #endif 2847 2848 #if defined(FEAT_TOOLBAR) || defined(PROTO) 2849 void 2850 gui_mch_show_toolbar(int showit) 2851 { 2852 if (showit) 2853 PtRealizeWidget(gui.vimToolBar); 2854 else 2855 PtUnrealizeWidget(gui.vimToolBar); 2856 } 2857 #endif 2858 2859 /****************************************************************************/ 2860 /* Fonts */ 2861 2862 static GuiFont 2863 gui_ph_get_font( 2864 char_u *font_name, 2865 int_u font_flags, 2866 int_u font_size, 2867 /* Check whether the resulting font has the font flags and size that 2868 * was asked for */ 2869 int_u enforce 2870 ) 2871 { 2872 char_u *font_tag; 2873 FontQueryInfo info; 2874 int_u style; 2875 2876 font_tag = alloc(MAX_FONT_TAG); 2877 if (font_tag != NULL) 2878 { 2879 if (PfGenerateFontName(font_name, font_flags, font_size, 2880 font_tag) != NULL) 2881 { 2882 /* Enforce some limits on the font used */ 2883 style = PHFONT_INFO_FIXED; 2884 2885 if (enforce & PF_STYLE_BOLD) 2886 style |= PHFONT_INFO_BOLD; 2887 if (enforce & PF_STYLE_ANTIALIAS) 2888 style |= PHFONT_INFO_ALIAS; 2889 if (enforce & PF_STYLE_ITALIC) 2890 style |= PHFONT_INFO_ITALIC; 2891 2892 PfQueryFontInfo(font_tag, &info); 2893 2894 if (info.size == 0) 2895 font_size = 0; 2896 2897 /* Make sure font size matches, and that the font style 2898 * at least has the bits we're checking for */ 2899 if (font_size == info.size && 2900 style == (info.style & style)) 2901 return (GuiFont)font_tag; 2902 } 2903 vim_free(font_tag); 2904 } 2905 return NULL; 2906 } 2907 2908 /* 2909 * Split up the vim font name 2910 * 2911 * vim_font is in the form of 2912 * <name>:s<height>:a:b:i 2913 * 2914 * a = antialias 2915 * b = bold 2916 * i = italic 2917 * 2918 */ 2919 2920 static int 2921 gui_ph_parse_font_name( 2922 char_u *vim_font, 2923 char_u **font_name, 2924 int_u *font_flags, 2925 int_u *font_size) 2926 { 2927 char_u *mark; 2928 int_u name_len, size; 2929 2930 mark = vim_strchr(vim_font, ':'); 2931 if (mark == NULL) 2932 name_len = STRLEN(vim_font); 2933 else 2934 name_len = (int_u) (mark - vim_font); 2935 2936 *font_name = vim_strnsave(vim_font, name_len); 2937 if (*font_name != NULL) 2938 { 2939 if (mark != NULL) 2940 { 2941 while (*mark != NUL && *mark++ == ':') 2942 { 2943 switch (tolower(*mark++)) 2944 { 2945 case 'a': *font_flags |= PF_STYLE_ANTIALIAS; break; 2946 case 'b': *font_flags |= PF_STYLE_BOLD; break; 2947 case 'i': *font_flags |= PF_STYLE_ITALIC; break; 2948 2949 case 's': 2950 size = getdigits(&mark); 2951 /* Restrict the size to some vague limits */ 2952 if (size < 1 || size > 100) 2953 size = 8; 2954 2955 *font_size = size; 2956 break; 2957 2958 default: 2959 break; 2960 } 2961 } 2962 } 2963 return TRUE; 2964 } 2965 return FALSE; 2966 } 2967 2968 int 2969 gui_mch_init_font(char_u *vim_font_name, int fontset) 2970 { 2971 char_u *font_tag; 2972 char_u *font_name = NULL; 2973 int_u font_flags = 0; 2974 int_u font_size = 12; 2975 2976 FontQueryInfo info; 2977 PhRect_t extent; 2978 2979 if (vim_font_name == NULL) 2980 { 2981 /* Default font */ 2982 vim_font_name = "PC Terminal"; 2983 } 2984 2985 if (STRCMP(vim_font_name, "*") == 0) 2986 { 2987 font_tag = PtFontSelection(gui.vimWindow, NULL, NULL, 2988 "pcterm12", -1, PHFONT_FIXED, NULL); 2989 2990 if (font_tag == NULL) 2991 return FAIL; 2992 2993 gui_mch_free_font(gui.norm_font); 2994 gui.norm_font = font_tag; 2995 2996 PfQueryFontInfo(font_tag, &info); 2997 font_name = vim_strsave(info.font); 2998 } 2999 else 3000 { 3001 if (gui_ph_parse_font_name(vim_font_name, &font_name, &font_flags, 3002 &font_size) == FALSE) 3003 return FAIL; 3004 3005 font_tag = gui_ph_get_font(font_name, font_flags, font_size, 0); 3006 if (font_tag == NULL) 3007 { 3008 vim_free(font_name); 3009 return FAIL; 3010 } 3011 3012 gui_mch_free_font(gui.norm_font); 3013 gui.norm_font = font_tag; 3014 } 3015 3016 gui_mch_free_font(gui.bold_font); 3017 gui.bold_font = gui_ph_get_font(font_name, font_flags | PF_STYLE_BOLD, 3018 font_size, PF_STYLE_BOLD); 3019 3020 gui_mch_free_font(gui.ital_font); 3021 gui.ital_font = gui_ph_get_font(font_name, font_flags | PF_STYLE_ITALIC, 3022 font_size, PF_STYLE_ITALIC); 3023 3024 /* This extent was brought to you by the letter 'g' */ 3025 PfExtentText(&extent, NULL, font_tag, "g", 1); 3026 3027 gui.char_width = extent.lr.x - extent.ul.x + 1; 3028 gui.char_height = (- extent.ul.y) + extent.lr.y + 1; 3029 gui.char_ascent = - extent.ul.y; 3030 3031 vim_free(font_name); 3032 return OK; 3033 } 3034 3035 /* 3036 * Adjust gui.char_height (after 'linespace' was changed). 3037 */ 3038 int 3039 gui_mch_adjust_charheight(void) 3040 { 3041 FontQueryInfo info; 3042 3043 PfQueryFontInfo(gui.norm_font, &info); 3044 3045 gui.char_height = - info.ascender + info.descender + p_linespace; 3046 gui.char_ascent = - info.ascender + p_linespace / 2; 3047 3048 return OK; 3049 } 3050 3051 GuiFont 3052 gui_mch_get_font(char_u *vim_font_name, int report_error) 3053 { 3054 char_u *font_name; 3055 char_u *font_tag; 3056 int_u font_size = 12; 3057 int_u font_flags = 0; 3058 3059 if (gui_ph_parse_font_name(vim_font_name, &font_name, &font_flags, 3060 &font_size) != FALSE) 3061 { 3062 font_tag = gui_ph_get_font(font_name, font_flags, font_size, -1); 3063 vim_free(font_name); 3064 3065 if (font_tag != NULL) 3066 return (GuiFont)font_tag; 3067 } 3068 3069 if (report_error) 3070 EMSG2(e_font, vim_font_name); 3071 3072 return FAIL; 3073 } 3074 3075 #if defined(FEAT_EVAL) || defined(PROTO) 3076 /* 3077 * Return the name of font "font" in allocated memory. 3078 * Don't know how to get the actual name, thus use the provided name. 3079 */ 3080 char_u * 3081 gui_mch_get_fontname(font, name) 3082 GuiFont font; 3083 char_u *name; 3084 { 3085 if (name == NULL) 3086 return NULL; 3087 return vim_strsave(name); 3088 } 3089 #endif 3090 3091 void 3092 gui_mch_set_font(GuiFont font) 3093 { 3094 PgSetFont(font); 3095 } 3096 3097 void 3098 gui_mch_free_font(GuiFont font) 3099 { 3100 vim_free(font); 3101 } 3102 3103