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(int *argc, char **argv) 1115 { 1116 PtInit(NULL); 1117 } 1118 1119 int 1120 gui_mch_init(void) 1121 { 1122 PtArg_t args[10]; 1123 int flags = 0, n = 0; 1124 1125 PhDim_t window_size = {100, 100}; /* Arbitrary values */ 1126 PhPoint_t pos = {0, 0}; 1127 1128 gui.event_buffer = (PhEvent_t *) alloc(EVENT_BUFFER_SIZE); 1129 if (gui.event_buffer == NULL) 1130 return FAIL; 1131 1132 /* Get a translation so we can convert from ISO Latin-1 to UTF */ 1133 charset_translate = PxTranslateSet(NULL, "latin1"); 1134 1135 /* The +2 is for the 1 pixel dark line on each side */ 1136 gui.border_offset = gui.border_width = GUI_PH_MARGIN + 2; 1137 1138 /* Handle close events ourselves */ 1139 PtSetArg(&args[ n++ ], Pt_ARG_WINDOW_MANAGED_FLAGS, Pt_FALSE, Ph_WM_CLOSE); 1140 PtSetArg(&args[ n++ ], Pt_ARG_WINDOW_NOTIFY_FLAGS, Pt_TRUE, 1141 Ph_WM_CLOSE | Ph_WM_RESIZE | Ph_WM_FOCUS); 1142 PtSetArg(&args[ n++ ], Pt_ARG_DIM, &window_size, 0); 1143 gui.vimWindow = PtCreateWidget(PtWindow, NULL, n, args); 1144 if (gui.vimWindow == NULL) 1145 return FAIL; 1146 1147 PtAddCallback(gui.vimWindow, Pt_CB_WINDOW, gui_ph_handle_window_cb, NULL); 1148 PtAddCallback(gui.vimWindow, Pt_CB_WINDOW_OPENING, 1149 gui_ph_handle_window_open, NULL); 1150 1151 n = 0; 1152 PtSetArg(&args[ n++ ], Pt_ARG_ANCHOR_FLAGS, Pt_ANCHOR_ALL, Pt_IS_ANCHORED); 1153 PtSetArg(&args[ n++ ], Pt_ARG_DIM, &window_size, 0); 1154 PtSetArg(&args[ n++ ], Pt_ARG_POS, &pos, 0); 1155 1156 #ifdef USE_PANEL_GROUP 1157 /* Put in a temporary place holder title */ 1158 PtSetArg(&args[ n++ ], Pt_ARG_PG_PANEL_TITLES, &empty_title, 1); 1159 1160 gui.vimPanelGroup = PtCreateWidget(PtPanelGroup, gui.vimWindow, n, args); 1161 if (gui.vimPanelGroup == NULL) 1162 return FAIL; 1163 1164 PtAddCallback(gui.vimPanelGroup, Pt_CB_PG_PANEL_SWITCHING, 1165 gui_ph_handle_pg_change, NULL); 1166 #else 1167 /* Turn off all edge decorations */ 1168 PtSetArg(&args[ n++ ], Pt_ARG_BASIC_FLAGS, Pt_FALSE, Pt_ALL); 1169 PtSetArg(&args[ n++ ], Pt_ARG_BEVEL_WIDTH, 0, 0); 1170 PtSetArg(&args[ n++ ], Pt_ARG_MARGIN_WIDTH, 0, 0); 1171 PtSetArg(&args[ n++ ], Pt_ARG_MARGIN_HEIGHT, 0, 0); 1172 PtSetArg(&args[ n++ ], Pt_ARG_CONTAINER_FLAGS, Pt_TRUE, Pt_AUTO_EXTENT); 1173 1174 gui.vimContainer = PtCreateWidget(PtPane, gui.vimWindow, n, args); 1175 if (gui.vimContainer == NULL) 1176 return FAIL; 1177 1178 PtAddCallback(gui.vimContainer, Pt_CB_RESIZE, gui_ph_pane_resize, NULL); 1179 #endif 1180 1181 /* Size for the text area is set in gui_mch_set_text_area_pos */ 1182 n = 0; 1183 1184 PtSetArg(&args[ n++ ], Pt_ARG_RAW_DRAW_F, gui_ph_handle_raw_draw, 1); 1185 PtSetArg(&args[ n++ ], Pt_ARG_BEVEL_WIDTH, GUI_PH_MARGIN, 0); 1186 /* 1187 * Using focus render also causes the whole widget to be redrawn 1188 * whenever it changes focus, which is very annoying :p 1189 */ 1190 PtSetArg(&args[ n++ ], Pt_ARG_FLAGS, Pt_TRUE, 1191 Pt_GETS_FOCUS | Pt_HIGHLIGHTED); 1192 #ifndef FEAT_MOUSESHAPE 1193 PtSetArg(&args[ n++ ], Pt_ARG_CURSOR_TYPE, GUI_PH_MOUSE_TYPE, 0); 1194 PtSetArg(&args[ n++ ], Pt_ARG_CURSOR_COLOR, gui_ph_mouse_color, 0); 1195 #endif 1196 1197 gui.vimTextArea = PtCreateWidget(PtRaw, Pt_DFLT_PARENT, n, args); 1198 if (gui.vimTextArea == NULL) 1199 return FAIL; 1200 1201 /* TODO: use PtAddEventHandlers instead? */ 1202 /* Not using Ph_EV_BUT_REPEAT because vim wouldn't use it anyway */ 1203 PtAddEventHandler(gui.vimTextArea, 1204 Ph_EV_BUT_PRESS | Ph_EV_BUT_RELEASE | Ph_EV_PTR_MOTION_BUTTON, 1205 gui_ph_handle_mouse, NULL); 1206 PtAddEventHandler(gui.vimTextArea, Ph_EV_KEY, 1207 gui_ph_handle_keyboard, NULL); 1208 PtAddCallback(gui.vimTextArea, Pt_CB_GOT_FOCUS, 1209 gui_ph_handle_focus, NULL); 1210 PtAddCallback(gui.vimTextArea, Pt_CB_LOST_FOCUS, 1211 gui_ph_handle_focus, NULL); 1212 1213 /* 1214 * Now that the text area widget has been created, set up the colours, 1215 * which wil call PtSetResource from gui_mch_new_colors 1216 */ 1217 1218 /* 1219 * Create the two timers, not as accurate as using the kernel timer 1220 * functions, but good enough 1221 */ 1222 gui_ph_timer_cursor = PtCreateWidget(PtTimer, gui.vimWindow, 0, NULL); 1223 if (gui_ph_timer_cursor == NULL) 1224 return FAIL; 1225 1226 gui_ph_timer_timeout = PtCreateWidget(PtTimer, gui.vimWindow, 0, NULL); 1227 if (gui_ph_timer_timeout == NULL) 1228 return FAIL; 1229 1230 PtAddCallback(gui_ph_timer_cursor, Pt_CB_TIMER_ACTIVATE, 1231 gui_ph_handle_timer_cursor, NULL); 1232 PtAddCallback(gui_ph_timer_timeout, Pt_CB_TIMER_ACTIVATE, 1233 gui_ph_handle_timer_timeout, NULL); 1234 1235 #ifdef FEAT_MENU 1236 n = 0; 1237 PtSetArg(&args[ n++ ], Pt_ARG_WIDTH, window_size.w, 0); 1238 PtSetArg(&args[ n++ ], Pt_ARG_ANCHOR_FLAGS, Pt_ANCHOR_LEFT_RIGHT, 1239 Pt_IS_ANCHORED); 1240 gui.vimToolBarGroup = PtCreateWidget(PtToolbarGroup, gui.vimWindow, 1241 n, args); 1242 if (gui.vimToolBarGroup == NULL) 1243 return FAIL; 1244 1245 PtAddCallback(gui.vimToolBarGroup, Pt_CB_RESIZE, 1246 gui_ph_handle_menu_resize, NULL); 1247 1248 n = 0; 1249 flags = 0; 1250 PtSetArg(&args[ n++ ], Pt_ARG_WIDTH, window_size.w, 0); 1251 if (! vim_strchr(p_go, GO_MENUS)) 1252 { 1253 flags |= Pt_DELAY_REALIZE; 1254 PtSetArg(&args[ n++ ], Pt_ARG_FLAGS, Pt_TRUE, flags); 1255 } 1256 gui.vimMenuBar = PtCreateWidget(PtMenuBar, gui.vimToolBarGroup, n, args); 1257 if (gui.vimMenuBar == NULL) 1258 return FAIL; 1259 1260 # ifdef FEAT_TOOLBAR 1261 n = 0; 1262 1263 PtSetArg(&args[ n++ ], Pt_ARG_ANCHOR_FLAGS, 1264 Pt_ANCHOR_LEFT_RIGHT |Pt_TOP_ANCHORED_TOP, Pt_IS_ANCHORED); 1265 PtSetArg(&args[ n++ ], Pt_ARG_RESIZE_FLAGS, Pt_TRUE, 1266 Pt_RESIZE_Y_AS_REQUIRED); 1267 PtSetArg(&args[ n++ ], Pt_ARG_WIDTH, window_size.w, 0); 1268 1269 flags = Pt_GETS_FOCUS; 1270 if (! vim_strchr(p_go, GO_TOOLBAR)) 1271 flags |= Pt_DELAY_REALIZE; 1272 1273 PtSetArg(&args[ n++ ], Pt_ARG_FLAGS, Pt_DELAY_REALIZE, flags); 1274 1275 gui.vimToolBar = PtCreateWidget(PtToolbar, gui.vimToolBarGroup, n, args); 1276 if (gui.vimToolBar == NULL) 1277 return FAIL; 1278 1279 /* 1280 * Size for the toolbar is fetched in gui_mch_show_toolbar, after 1281 * the buttons have been added and the toolbar has resized it's height 1282 * for the buttons to fit 1283 */ 1284 # endif 1285 1286 #endif 1287 1288 return OK; 1289 } 1290 1291 int 1292 gui_mch_init_check(void) 1293 { 1294 return (is_photon_available == TRUE) ? OK : FAIL; 1295 } 1296 1297 int 1298 gui_mch_open(void) 1299 { 1300 gui.norm_pixel = Pg_BLACK; 1301 gui.back_pixel = Pg_WHITE; 1302 1303 set_normal_colors(); 1304 1305 gui_check_colors(); 1306 gui.def_norm_pixel = gui.norm_pixel; 1307 gui.def_back_pixel = gui.back_pixel; 1308 1309 highlight_gui_started(); 1310 1311 if (gui_win_x != -1 && gui_win_y != -1) 1312 gui_mch_set_winpos(gui_win_x, gui_win_y); 1313 1314 return (PtRealizeWidget(gui.vimWindow) == 0) ? OK : FAIL; 1315 } 1316 1317 void 1318 gui_mch_exit(int rc) 1319 { 1320 PtDestroyWidget(gui.vimWindow); 1321 1322 PxTranslateSet(charset_translate, NULL); 1323 1324 vim_free(gui.event_buffer); 1325 1326 #ifdef USE_PANEL_GROUPS 1327 vim_free(panel_titles); 1328 #endif 1329 } 1330 1331 /****************************************************************************/ 1332 /* events */ 1333 1334 /* When no events are available, photon will call this function, working is 1335 * set to FALSE, and the gui_mch_update loop will exit. */ 1336 static int 1337 exit_gui_mch_update(void *data) 1338 { 1339 *(int *)data = FALSE; 1340 return Pt_END; 1341 } 1342 1343 void 1344 gui_mch_update(void) 1345 { 1346 int working = TRUE; 1347 1348 PtAppAddWorkProc(NULL, exit_gui_mch_update, &working); 1349 while ((working == TRUE) && !vim_is_input_buf_full()) 1350 { 1351 PtProcessEvent(); 1352 } 1353 } 1354 1355 int 1356 gui_mch_wait_for_chars(int wtime) 1357 { 1358 is_timeout = FALSE; 1359 1360 if (wtime > 0) 1361 PtSetResource(gui_ph_timer_timeout, Pt_ARG_TIMER_INITIAL, wtime, 0); 1362 1363 while (1) 1364 { 1365 PtProcessEvent(); 1366 if (input_available()) 1367 { 1368 PtSetResource(gui_ph_timer_timeout, Pt_ARG_TIMER_INITIAL, 0, 0); 1369 return OK; 1370 } 1371 else if (is_timeout == TRUE) 1372 return FAIL; 1373 } 1374 } 1375 1376 #if defined(FEAT_BROWSE) || defined(PROTO) 1377 /* 1378 * Put up a file requester. 1379 * Returns the selected name in allocated memory, or NULL for Cancel. 1380 * saving, select file to write 1381 * title title for the window 1382 * default_name default name (well duh!) 1383 * ext not used (extension added) 1384 * initdir initial directory, NULL for current dir 1385 * filter not used (file name filter) 1386 */ 1387 char_u * 1388 gui_mch_browse( 1389 int saving, 1390 char_u *title, 1391 char_u *default_name, 1392 char_u *ext, 1393 char_u *initdir, 1394 char_u *filter) 1395 { 1396 PtFileSelectionInfo_t file; 1397 int flags; 1398 char_u *default_path; 1399 char_u *open_text = NULL; 1400 1401 flags = 0; 1402 memset(&file, 0, sizeof(file)); 1403 1404 default_path = alloc(MAXPATHL + 1 + NAME_MAX + 1); 1405 if (default_path != NULL) 1406 { 1407 if (saving == TRUE) 1408 { 1409 /* Don't need Pt_FSR_CONFIRM_EXISTING, vim will ask anyway */ 1410 flags |= Pt_FSR_NO_FCHECK; 1411 open_text = "&Save"; 1412 } 1413 1414 /* combine the directory and filename into a single path */ 1415 if (initdir == NULL || *initdir == NUL) 1416 { 1417 mch_dirname(default_path, MAXPATHL); 1418 initdir = default_path; 1419 } 1420 else 1421 { 1422 STRCPY(default_path, initdir); 1423 initdir = default_path; 1424 } 1425 1426 if (default_name != NULL) 1427 { 1428 if (default_path[ STRLEN(default_path) - 1 ] != '/') 1429 STRCAT(default_path, "/"); 1430 1431 STRCAT(default_path, default_name); 1432 } 1433 1434 /* TODO: add a filter? */ 1435 PtFileSelection( 1436 gui.vimWindow, 1437 NULL, 1438 title, 1439 default_path, 1440 NULL, 1441 open_text, 1442 NULL, 1443 NULL, 1444 &file, 1445 flags); 1446 1447 vim_free(default_path); 1448 1449 if (file.ret == Pt_FSDIALOG_BTN1) 1450 return vim_strsave(file.path); 1451 } 1452 return NULL; 1453 } 1454 #endif 1455 1456 #if defined(FEAT_GUI_DIALOG) || defined(PROTO) 1457 static PtWidget_t *gui_ph_dialog_text = NULL; 1458 1459 static int 1460 gui_ph_dialog_close(int button, void *data) 1461 { 1462 PtModalCtrl_t *modal_ctrl = data; 1463 char_u *dialog_text, *vim_text; 1464 1465 if (gui_ph_dialog_text != NULL) 1466 { 1467 PtGetResource(gui_ph_dialog_text, Pt_ARG_TEXT_STRING, &dialog_text, 0); 1468 PtGetResource(gui_ph_dialog_text, Pt_ARG_POINTER, &vim_text, 0); 1469 STRNCPY(vim_text, dialog_text, IOSIZE - 1); 1470 } 1471 1472 PtModalUnblock(modal_ctrl, (void *) button); 1473 1474 return Pt_TRUE; 1475 } 1476 1477 static int 1478 gui_ph_dialog_text_enter(PtWidget_t *widget, void *data, PtCallbackInfo_t *info) 1479 { 1480 if (info->reason_subtype == Pt_EDIT_ACTIVATE) 1481 gui_ph_dialog_close(1, data); 1482 return Pt_CONTINUE; 1483 } 1484 1485 static int 1486 gui_ph_dialog_esc(PtWidget_t *widget, void *data, PtCallbackInfo_t *info) 1487 { 1488 PhKeyEvent_t *key; 1489 1490 key = PhGetData(info->event); 1491 if ((key->key_flags & Pk_KF_Cap_Valid) && (key->key_cap == Pk_Escape)) 1492 { 1493 gui_ph_dialog_close(0, data); 1494 return Pt_CONSUME; 1495 } 1496 return Pt_PROCESS; 1497 } 1498 1499 int 1500 gui_mch_dialog( 1501 int type, 1502 char_u *title, 1503 char_u *message, 1504 char_u *buttons, 1505 int default_button, 1506 char_u *textfield, 1507 int ex_cmd) 1508 { 1509 char_u *str; 1510 char_u **button_array; 1511 char_u *buttons_copy; 1512 1513 int button_count; 1514 int i, len; 1515 int dialog_result = -1; 1516 1517 /* FIXME: the vertical option in guioptions is blatantly ignored */ 1518 /* FIXME: so is the type */ 1519 1520 button_count = len = i = 0; 1521 1522 if (buttons == NULL || *buttons == NUL) 1523 return -1; 1524 1525 /* There is one less separator than buttons, so bump up the button count */ 1526 button_count = 1; 1527 1528 /* Count string length and number of separators */ 1529 for (str = buttons; *str; str++) 1530 { 1531 len++; 1532 if (*str == DLG_BUTTON_SEP) 1533 button_count++; 1534 } 1535 1536 if (title == NULL) 1537 title = "Vim"; 1538 1539 buttons_copy = alloc(len + 1); 1540 button_array = (char_u **) alloc(button_count * sizeof(char_u *)); 1541 if (buttons_copy != NULL && button_array != NULL) 1542 { 1543 STRCPY(buttons_copy, buttons); 1544 1545 /* 1546 * Convert DLG_BUTTON_SEP into NUL's and fill in 1547 * button_array with the pointer to each NUL terminated string 1548 */ 1549 str = buttons_copy; 1550 for (i = 0; i < button_count; i++) 1551 { 1552 button_array[ i ] = str; 1553 for (; *str; str++) 1554 { 1555 if (*str == DLG_BUTTON_SEP) 1556 { 1557 *str++ = NUL; 1558 break; 1559 } 1560 } 1561 } 1562 #ifndef FEAT_GUI_TEXTDIALOG 1563 dialog_result = PtAlert( 1564 gui.vimWindow, NULL, 1565 title, 1566 NULL, 1567 message, NULL, 1568 button_count, (const char **) button_array, NULL, 1569 default_button, 0, Pt_MODAL); 1570 #else 1571 /* Writing the dialog ourselves lets us add extra features, like 1572 * trapping the escape key and returning 0 to vim */ 1573 { 1574 int n; 1575 PtArg_t args[5]; 1576 PtWidget_t *dialog, *pane; 1577 PtModalCtrl_t modal_ctrl; 1578 PtDialogInfo_t di; 1579 1580 memset(&di, 0, sizeof(di)); 1581 memset(&modal_ctrl, 0, sizeof(modal_ctrl)); 1582 1583 n = 0; 1584 PtSetArg(&args[n++], Pt_ARG_GROUP_ROWS_COLS, 0, 0); 1585 PtSetArg(&args[n++], Pt_ARG_WIDTH, 350, 0); 1586 PtSetArg(&args[n++], Pt_ARG_GROUP_ORIENTATION, 1587 Pt_GROUP_VERTICAL, 0); 1588 PtSetArg(&args[n++], Pt_ARG_GROUP_FLAGS, 1589 Pt_TRUE, Pt_GROUP_NO_KEYS | Pt_GROUP_STRETCH_HORIZONTAL); 1590 PtSetArg(&args[n++], Pt_ARG_CONTAINER_FLAGS, Pt_FALSE, Pt_TRUE); 1591 pane = PtCreateWidget(PtGroup, NULL, n, args); 1592 1593 n = 0; 1594 PtSetArg(&args[n++], Pt_ARG_TEXT_STRING, message, 0); 1595 PtCreateWidget(PtLabel, pane, n, args); 1596 1597 if (textfield != NULL) 1598 { 1599 n = 0; 1600 PtSetArg(&args[n++], Pt_ARG_MAX_LENGTH, IOSIZE - 1, 0); 1601 PtSetArg(&args[n++], Pt_ARG_TEXT_STRING, textfield, 0); 1602 PtSetArg(&args[n++], Pt_ARG_POINTER, textfield, 0); 1603 gui_ph_dialog_text = PtCreateWidget(PtText, pane, n, args); 1604 PtAddCallback(gui_ph_dialog_text, Pt_CB_ACTIVATE, 1605 gui_ph_dialog_text_enter, &modal_ctrl); 1606 } 1607 1608 di.parent = gui.vimWindow; 1609 di.pane = pane; 1610 di.title = title; 1611 di.buttons = (const char **) button_array; 1612 di.nbtns = button_count; 1613 di.def_btn = default_button; 1614 /* This is just to give the dialog the close button. 1615 * We check for the Escape key ourselves and return 0 */ 1616 di.esc_btn = button_count; 1617 di.callback = gui_ph_dialog_close; 1618 di.data = &modal_ctrl; 1619 1620 dialog = PtCreateDialog(&di); 1621 PtAddFilterCallback(dialog, Ph_EV_KEY, 1622 gui_ph_dialog_esc, &modal_ctrl); 1623 1624 if (gui_ph_dialog_text != NULL) 1625 PtGiveFocus(gui_ph_dialog_text, NULL); 1626 1627 /* Open dialog, block the vim window and wait for the dialog to close */ 1628 PtRealizeWidget(dialog); 1629 PtMakeModal(dialog, Ph_CURSOR_NOINPUT, Ph_CURSOR_DEFAULT_COLOR); 1630 dialog_result = (int) PtModalBlock(&modal_ctrl, 0); 1631 1632 PtDestroyWidget(dialog); 1633 gui_ph_dialog_text = NULL; 1634 } 1635 #endif 1636 } 1637 1638 vim_free(button_array); 1639 vim_free(buttons_copy); 1640 1641 return dialog_result; 1642 } 1643 #endif 1644 /****************************************************************************/ 1645 /* window size/position/state */ 1646 1647 int 1648 gui_mch_get_winpos(int *x, int *y) 1649 { 1650 PhPoint_t *pos; 1651 1652 pos = PtWidgetPos(gui.vimWindow, NULL); 1653 1654 *x = pos->x; 1655 *y = pos->y; 1656 1657 return OK; 1658 } 1659 1660 void 1661 gui_mch_set_winpos(int x, int y) 1662 { 1663 PhPoint_t pos = { x, y }; 1664 1665 PtSetResource(gui.vimWindow, Pt_ARG_POS, &pos, 0); 1666 } 1667 1668 void 1669 gui_mch_set_shellsize(int width, int height, 1670 int min_width, int min_height, int base_width, int base_height, 1671 int direction) 1672 { 1673 PhDim_t window_size = { width, height }; 1674 PhDim_t min_size = { min_width, min_height }; 1675 1676 #ifdef USE_PANEL_GROUP 1677 window_size.w += pg_margin_left + pg_margin_right; 1678 window_size.h += pg_margin_top + pg_margin_bottom; 1679 #endif 1680 1681 PtSetResource(gui.vimWindow, Pt_ARG_MINIMUM_DIM, &min_size, 0); 1682 PtSetResource(gui.vimWindow, Pt_ARG_DIM, &window_size, 0); 1683 1684 if (! PtWidgetIsRealized(gui.vimWindow)) 1685 gui_ph_resize_container(); 1686 } 1687 1688 /* 1689 * Return the amount of screen space that hasn't been allocated (such as 1690 * by the shelf). 1691 */ 1692 void 1693 gui_mch_get_screen_dimensions(int *screen_w, int *screen_h) 1694 { 1695 PhRect_t console; 1696 1697 PhWindowQueryVisible(Ph_QUERY_WORKSPACE, 0, 1698 PhInputGroup(NULL), &console); 1699 1700 *screen_w = console.lr.x - console.ul.x + 1; 1701 *screen_h = console.lr.y - console.ul.y + 1; 1702 } 1703 1704 void 1705 gui_mch_iconify(void) 1706 { 1707 PhWindowEvent_t event; 1708 1709 memset(&event, 0, sizeof (event)); 1710 event.event_f = Ph_WM_HIDE; 1711 event.event_state = Ph_WM_EVSTATE_HIDE; 1712 event.rid = PtWidgetRid(gui.vimWindow); 1713 PtForwardWindowEvent(&event); 1714 } 1715 1716 #if defined(FEAT_EVAL) || defined(PROTO) 1717 /* 1718 * Bring the Vim window to the foreground. 1719 */ 1720 void 1721 gui_mch_set_foreground(void) 1722 { 1723 PhWindowEvent_t event; 1724 1725 memset(&event, 0, sizeof (event)); 1726 event.event_f = Ph_WM_TOFRONT; 1727 event.event_state = Ph_WM_EVSTATE_FFRONT; 1728 event.rid = PtWidgetRid(gui.vimWindow); 1729 PtForwardWindowEvent(&event); 1730 } 1731 #endif 1732 1733 void 1734 gui_mch_settitle(char_u *title, char_u *icon) 1735 { 1736 #ifdef USE_PANEL_GROUP 1737 gui_ph_pg_set_buffer_num(curwin->w_buffer->b_fnum); 1738 #endif 1739 PtSetResource(gui.vimWindow, Pt_ARG_WINDOW_TITLE, title, 0); 1740 /* Not sure what to do with the icon text, set balloon text somehow? */ 1741 } 1742 1743 /****************************************************************************/ 1744 /* Scrollbar */ 1745 1746 void 1747 gui_mch_set_scrollbar_thumb(scrollbar_T *sb, int val, int size, int max) 1748 { 1749 int n = 0; 1750 PtArg_t args[3]; 1751 1752 PtSetArg(&args[ n++ ], Pt_ARG_MAXIMUM, max, 0); 1753 PtSetArg(&args[ n++ ], Pt_ARG_SLIDER_SIZE, size, 0); 1754 PtSetArg(&args[ n++ ], Pt_ARG_GAUGE_VALUE, val, 0); 1755 PtSetResources(sb->id, n, args); 1756 } 1757 1758 void 1759 gui_mch_set_scrollbar_pos(scrollbar_T *sb, int x, int y, int w, int h) 1760 { 1761 PhArea_t area = {{ x, y }, { w, h }}; 1762 1763 PtSetResource(sb->id, Pt_ARG_AREA, &area, 0); 1764 } 1765 1766 void 1767 gui_mch_create_scrollbar(scrollbar_T *sb, int orient) 1768 { 1769 int n = 0; 1770 /* int anchor_flags = 0;*/ 1771 PtArg_t args[4]; 1772 1773 /* 1774 * Stop the scrollbar from being realized when the parent 1775 * is realized, so it can be explicitly realized by vim. 1776 * 1777 * Also, don't let the scrollbar get focus 1778 */ 1779 PtSetArg(&args[ n++ ], Pt_ARG_FLAGS, Pt_DELAY_REALIZE, 1780 Pt_DELAY_REALIZE | Pt_GETS_FOCUS); 1781 PtSetArg(&args[ n++ ], Pt_ARG_SCROLLBAR_FLAGS, Pt_SCROLLBAR_SHOW_ARROWS, 0); 1782 #if 0 1783 /* Don't need this anchoring for the scrollbars */ 1784 if (orient == SBAR_HORIZ) 1785 { 1786 anchor_flags = Pt_BOTTOM_ANCHORED_BOTTOM | 1787 Pt_LEFT_ANCHORED_LEFT | Pt_RIGHT_ANCHORED_RIGHT; 1788 } 1789 else 1790 { 1791 anchor_flags = Pt_BOTTOM_ANCHORED_BOTTOM | Pt_TOP_ANCHORED_TOP; 1792 if (sb->wp != NULL) 1793 { 1794 if (sb == &sb->wp->w_scrollbars[ SBAR_LEFT ]) 1795 anchor_flags |= Pt_LEFT_ANCHORED_LEFT; 1796 else 1797 anchor_flags |= Pt_RIGHT_ANCHORED_RIGHT; 1798 } 1799 } 1800 PtSetArg(&args[ n++ ], Pt_ARG_ANCHOR_FLAGS, anchor_flags, Pt_IS_ANCHORED); 1801 #endif 1802 PtSetArg(&args[ n++ ], Pt_ARG_ORIENTATION, 1803 (orient == SBAR_HORIZ) ? Pt_HORIZONTAL : Pt_VERTICAL, 0); 1804 #ifdef USE_PANEL_GROUP 1805 sb->id = PtCreateWidget(PtScrollbar, gui.vimPanelGroup, n, args); 1806 #else 1807 sb->id = PtCreateWidget(PtScrollbar, gui.vimContainer, n, args); 1808 #endif 1809 1810 PtAddCallback(sb->id, Pt_CB_SCROLLBAR_MOVE, gui_ph_handle_scrollbar, sb); 1811 } 1812 1813 void 1814 gui_mch_enable_scrollbar(scrollbar_T *sb, int flag) 1815 { 1816 if (flag != 0) 1817 PtRealizeWidget(sb->id); 1818 else 1819 PtUnrealizeWidget(sb->id); 1820 } 1821 1822 void 1823 gui_mch_destroy_scrollbar(scrollbar_T *sb) 1824 { 1825 PtDestroyWidget(sb->id); 1826 sb->id = NULL; 1827 } 1828 1829 /****************************************************************************/ 1830 /* Mouse functions */ 1831 1832 #if defined(FEAT_MOUSESHAPE) || defined(PROTO) 1833 /* The last set mouse pointer shape is remembered, to be used when it goes 1834 * from hidden to not hidden. */ 1835 static int last_shape = 0; 1836 1837 /* Table for shape IDs. Keep in sync with the mshape_names[] table in 1838 * misc2.c! */ 1839 static int mshape_ids[] = 1840 { 1841 Ph_CURSOR_POINTER, /* arrow */ 1842 Ph_CURSOR_NONE, /* blank */ 1843 Ph_CURSOR_INSERT, /* beam */ 1844 Ph_CURSOR_DRAG_VERTICAL, /* updown */ 1845 Ph_CURSOR_DRAG_VERTICAL, /* udsizing */ 1846 Ph_CURSOR_DRAG_HORIZONTAL, /* leftright */ 1847 Ph_CURSOR_DRAG_HORIZONTAL, /* lrsizing */ 1848 Ph_CURSOR_WAIT, /* busy */ 1849 Ph_CURSOR_DONT, /* no */ 1850 Ph_CURSOR_CROSSHAIR, /* crosshair */ 1851 Ph_CURSOR_FINGER, /* hand1 */ 1852 Ph_CURSOR_FINGER, /* hand2 */ 1853 Ph_CURSOR_FINGER, /* pencil */ 1854 Ph_CURSOR_QUESTION_POINT, /* question */ 1855 Ph_CURSOR_POINTER, /* right-arrow */ 1856 Ph_CURSOR_POINTER, /* up-arrow */ 1857 Ph_CURSOR_POINTER /* last one */ 1858 }; 1859 1860 void 1861 mch_set_mouse_shape(int shape) 1862 { 1863 int id; 1864 1865 if (!gui.in_use) 1866 return; 1867 1868 if (shape == MSHAPE_HIDE || gui.pointer_hidden) 1869 PtSetResource(gui.vimTextArea, Pt_ARG_CURSOR_TYPE, Ph_CURSOR_NONE, 1870 0); 1871 else 1872 { 1873 if (shape >= MSHAPE_NUMBERED) 1874 id = Ph_CURSOR_POINTER; 1875 else 1876 id = mshape_ids[shape]; 1877 1878 PtSetResource(gui.vimTextArea, Pt_ARG_CURSOR_TYPE, id, 0); 1879 } 1880 if (shape != MSHAPE_HIDE) 1881 last_shape = shape; 1882 } 1883 #endif 1884 1885 void 1886 gui_mch_mousehide(int hide) 1887 { 1888 if (gui.pointer_hidden != hide) 1889 { 1890 gui.pointer_hidden = hide; 1891 #ifdef FEAT_MOUSESHAPE 1892 if (hide) 1893 PtSetResource(gui.vimTextArea, Pt_ARG_CURSOR_TYPE, 1894 Ph_CURSOR_NONE, 0); 1895 else 1896 mch_set_mouse_shape(last_shape); 1897 #else 1898 PtSetResource(gui.vimTextArea, Pt_ARG_CURSOR_TYPE, 1899 (hide == MOUSE_SHOW) ? GUI_PH_MOUSE_TYPE : Ph_CURSOR_NONE, 1900 0); 1901 #endif 1902 } 1903 } 1904 1905 void 1906 gui_mch_getmouse(int *x, int *y) 1907 { 1908 PhCursorInfo_t info; 1909 short ix, iy; 1910 1911 /* FIXME: does this return the correct position, 1912 * with respect to the border? */ 1913 PhQueryCursor(PhInputGroup(NULL), &info); 1914 PtGetAbsPosition(gui.vimTextArea , &ix, &iy); 1915 1916 *x = info.pos.x - ix; 1917 *y = info.pos.y - iy; 1918 } 1919 1920 void 1921 gui_mch_setmouse(int x, int y) 1922 { 1923 short abs_x, abs_y; 1924 1925 PtGetAbsPosition(gui.vimTextArea, &abs_x, &abs_y); 1926 /* Add the border offset? */ 1927 PhMoveCursorAbs(PhInputGroup(NULL), abs_x + x, abs_y + y); 1928 } 1929 1930 /****************************************************************************/ 1931 /* Colours */ 1932 1933 /* 1934 * Return the RGB value of a pixel as a long. 1935 */ 1936 long_u 1937 gui_mch_get_rgb(guicolor_T pixel) 1938 { 1939 return PgRGB(PgRedValue(pixel), PgGreenValue(pixel), PgBlueValue(pixel)); 1940 } 1941 1942 void 1943 gui_mch_new_colors(void) 1944 { 1945 #if 0 /* Don't bother changing the cursor colour */ 1946 short color_diff; 1947 1948 /* 1949 * If there isn't enough difference between the background colour and 1950 * the mouse pointer colour then change the mouse pointer colour 1951 */ 1952 color_diff = gui_get_lightness(gui_ph_mouse_color) 1953 - gui_get_lightness(gui.back_pixel); 1954 1955 if (abs(color_diff) < 64) 1956 { 1957 short r, g, b; 1958 /* not a great algorithm... */ 1959 r = PgRedValue(gui_ph_mouse_color) ^ 255; 1960 g = PgGreenValue(gui_ph_mouse_color) ^ 255; 1961 b = PgBlueValue(gui_ph_mouse_color) ^ 255; 1962 1963 #ifndef FEAT_MOUSESHAPE 1964 gui_ph_mouse_color = PgRGB(r, g, b); 1965 PtSetResource(gui.vimTextArea, Pt_ARG_CURSOR_COLOR, 1966 gui_ph_mouse_color, 0); 1967 #endif 1968 } 1969 #endif 1970 1971 PtSetResource(gui.vimTextArea, Pt_ARG_FILL_COLOR, gui.back_pixel, 0); 1972 } 1973 1974 static int 1975 hex_digit(int c) 1976 { 1977 if (VIM_ISDIGIT(c)) 1978 return c - '0'; 1979 c = TOLOWER_ASC(c); 1980 if (c >= 'a' && c <= 'f') 1981 return c - 'a' + 10; 1982 return -1000; 1983 } 1984 1985 1986 /* 1987 * This should be split out into a separate file, 1988 * every port does basically the same thing. 1989 * 1990 * This is the gui_w32.c version (i think..) 1991 * Return INVALCOLOR when failed. 1992 */ 1993 1994 guicolor_T 1995 gui_mch_get_color(char_u *name) 1996 { 1997 int i; 1998 int r, g, b; 1999 2000 2001 typedef struct GuiColourTable 2002 { 2003 char *name; 2004 guicolor_T colour; 2005 } GuiColourTable; 2006 2007 static GuiColourTable table[] = 2008 { 2009 {"Black", RGB(0x00, 0x00, 0x00)}, 2010 {"DarkGray", RGB(0xA9, 0xA9, 0xA9)}, 2011 {"DarkGrey", RGB(0xA9, 0xA9, 0xA9)}, 2012 {"Gray", RGB(0xC0, 0xC0, 0xC0)}, 2013 {"Grey", RGB(0xC0, 0xC0, 0xC0)}, 2014 {"LightGray", RGB(0xD3, 0xD3, 0xD3)}, 2015 {"LightGrey", RGB(0xD3, 0xD3, 0xD3)}, 2016 {"Gray10", RGB(0x1A, 0x1A, 0x1A)}, 2017 {"Grey10", RGB(0x1A, 0x1A, 0x1A)}, 2018 {"Gray20", RGB(0x33, 0x33, 0x33)}, 2019 {"Grey20", RGB(0x33, 0x33, 0x33)}, 2020 {"Gray30", RGB(0x4D, 0x4D, 0x4D)}, 2021 {"Grey30", RGB(0x4D, 0x4D, 0x4D)}, 2022 {"Gray40", RGB(0x66, 0x66, 0x66)}, 2023 {"Grey40", RGB(0x66, 0x66, 0x66)}, 2024 {"Gray50", RGB(0x7F, 0x7F, 0x7F)}, 2025 {"Grey50", RGB(0x7F, 0x7F, 0x7F)}, 2026 {"Gray60", RGB(0x99, 0x99, 0x99)}, 2027 {"Grey60", RGB(0x99, 0x99, 0x99)}, 2028 {"Gray70", RGB(0xB3, 0xB3, 0xB3)}, 2029 {"Grey70", RGB(0xB3, 0xB3, 0xB3)}, 2030 {"Gray80", RGB(0xCC, 0xCC, 0xCC)}, 2031 {"Grey80", RGB(0xCC, 0xCC, 0xCC)}, 2032 {"Gray90", RGB(0xE5, 0xE5, 0xE5)}, 2033 {"Grey90", RGB(0xE5, 0xE5, 0xE5)}, 2034 {"White", RGB(0xFF, 0xFF, 0xFF)}, 2035 {"DarkRed", RGB(0x80, 0x00, 0x00)}, 2036 {"Red", RGB(0xFF, 0x00, 0x00)}, 2037 {"LightRed", RGB(0xFF, 0xA0, 0xA0)}, 2038 {"DarkBlue", RGB(0x00, 0x00, 0x80)}, 2039 {"Blue", RGB(0x00, 0x00, 0xFF)}, 2040 {"LightBlue", RGB(0xAD, 0xD8, 0xE6)}, 2041 {"DarkGreen", RGB(0x00, 0x80, 0x00)}, 2042 {"Green", RGB(0x00, 0xFF, 0x00)}, 2043 {"LightGreen", RGB(0x90, 0xEE, 0x90)}, 2044 {"DarkCyan", RGB(0x00, 0x80, 0x80)}, 2045 {"Cyan", RGB(0x00, 0xFF, 0xFF)}, 2046 {"LightCyan", RGB(0xE0, 0xFF, 0xFF)}, 2047 {"DarkMagenta", RGB(0x80, 0x00, 0x80)}, 2048 {"Magenta", RGB(0xFF, 0x00, 0xFF)}, 2049 {"LightMagenta", RGB(0xFF, 0xA0, 0xFF)}, 2050 {"Brown", RGB(0x80, 0x40, 0x40)}, 2051 {"Yellow", RGB(0xFF, 0xFF, 0x00)}, 2052 {"LightYellow", RGB(0xFF, 0xFF, 0xE0)}, 2053 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, 2054 {"Orange", RGB(0xFF, 0xA5, 0x00)}, 2055 {"Purple", RGB(0xA0, 0x20, 0xF0)}, 2056 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, 2057 {"Violet", RGB(0xEE, 0x82, 0xEE)}, 2058 }; 2059 2060 /* is name #rrggbb format? */ 2061 if (name[0] == '#' && STRLEN(name) == 7) 2062 { 2063 r = hex_digit(name[1]) * 16 + hex_digit(name[2]); 2064 g = hex_digit(name[3]) * 16 + hex_digit(name[4]); 2065 b = hex_digit(name[5]) * 16 + hex_digit(name[6]); 2066 if (r < 0 || g < 0 || b < 0) 2067 return INVALCOLOR; 2068 return RGB(r, g, b); 2069 } 2070 2071 for (i = 0; i < ARRAY_LENGTH(table); i++) 2072 { 2073 if (STRICMP(name, table[i].name) == 0) 2074 return table[i].colour; 2075 } 2076 2077 /* 2078 * Last attempt. Look in the file "$VIMRUNTIME/rgb.txt". 2079 */ 2080 { 2081 #define LINE_LEN 100 2082 FILE *fd; 2083 char line[LINE_LEN]; 2084 char_u *fname; 2085 2086 fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt"); 2087 if (fname == NULL) 2088 return INVALCOLOR; 2089 2090 fd = fopen((char *)fname, "rt"); 2091 vim_free(fname); 2092 if (fd == NULL) 2093 return INVALCOLOR; 2094 2095 while (!feof(fd)) 2096 { 2097 int len; 2098 int pos; 2099 char *color; 2100 2101 fgets(line, LINE_LEN, fd); 2102 len = STRLEN(line); 2103 2104 if (len <= 1 || line[len-1] != '\n') 2105 continue; 2106 2107 line[len-1] = '\0'; 2108 2109 i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos); 2110 if (i != 3) 2111 continue; 2112 2113 color = line + pos; 2114 2115 if (STRICMP(color, name) == 0) 2116 { 2117 fclose(fd); 2118 return (guicolor_T)RGB(r, g, b); 2119 } 2120 } 2121 2122 fclose(fd); 2123 } 2124 2125 2126 return INVALCOLOR; 2127 } 2128 2129 void 2130 gui_mch_set_fg_color(guicolor_T color) 2131 { 2132 PgSetTextColor(color); 2133 } 2134 2135 void 2136 gui_mch_set_bg_color(guicolor_T color) 2137 { 2138 PgSetFillColor(color); 2139 } 2140 2141 void 2142 gui_mch_set_sp_color(guicolor_T color) 2143 { 2144 } 2145 2146 void 2147 gui_mch_invert_rectangle(int row, int col, int nr, int nc) 2148 { 2149 PhRect_t rect; 2150 2151 rect.ul.x = FILL_X(col); 2152 rect.ul.y = FILL_Y(row); 2153 2154 /* FIXME: This has an off by one pixel problem */ 2155 rect.lr.x = rect.ul.x + nc * gui.char_width; 2156 rect.lr.y = rect.ul.y + nr * gui.char_height; 2157 if (nc > 0) 2158 rect.lr.x -= 1; 2159 if (nr > 0) 2160 rect.lr.y -= 1; 2161 2162 DRAW_START; 2163 PgSetDrawMode(Pg_DrawModeDSTINVERT); 2164 PgDrawRect(&rect, Pg_DRAW_FILL); 2165 PgSetDrawMode(Pg_DrawModeSRCCOPY); 2166 DRAW_END; 2167 } 2168 2169 void 2170 gui_mch_clear_block(int row1, int col1, int row2, int col2) 2171 { 2172 PhRect_t block = { 2173 { FILL_X(col1), FILL_Y(row1) }, 2174 { FILL_X(col2 + 1) - 1, FILL_Y(row2 + 1) - 1} 2175 }; 2176 2177 DRAW_START; 2178 gui_mch_set_bg_color(gui.back_pixel); 2179 PgDrawRect(&block, Pg_DRAW_FILL); 2180 DRAW_END; 2181 } 2182 2183 void 2184 gui_mch_clear_all(void) 2185 { 2186 PhRect_t text_rect = { 2187 { gui.border_width, gui.border_width }, 2188 { Columns * gui.char_width + gui.border_width - 1 , 2189 Rows * gui.char_height + gui.border_width - 1 } 2190 }; 2191 2192 if (is_ignore_draw == TRUE) 2193 return; 2194 2195 DRAW_START; 2196 gui_mch_set_bg_color(gui.back_pixel); 2197 PgDrawRect(&text_rect, Pg_DRAW_FILL); 2198 DRAW_END; 2199 } 2200 2201 void 2202 gui_mch_delete_lines(int row, int num_lines) 2203 { 2204 PhRect_t rect; 2205 PhPoint_t delta; 2206 2207 rect.ul.x = FILL_X(gui.scroll_region_left); 2208 rect.ul.y = FILL_Y(row + num_lines); 2209 2210 rect.lr.x = FILL_X(gui.scroll_region_right + 1) - 1; 2211 rect.lr.y = FILL_Y(gui.scroll_region_bot + 1) - 1; 2212 2213 PtWidgetOffset(gui.vimTextArea, &gui_ph_raw_offset); 2214 PhTranslatePoint(&gui_ph_raw_offset, PtWidgetPos(gui.vimTextArea, NULL)); 2215 PhTranslateRect(&rect, &gui_ph_raw_offset); 2216 2217 delta.x = 0; 2218 delta.y = -num_lines * gui.char_height; 2219 2220 PgFlush(); 2221 2222 PhBlit(PtWidgetRid(PtFindDisjoint(gui.vimTextArea)), &rect, &delta); 2223 2224 gui_clear_block( 2225 gui.scroll_region_bot - num_lines + 1, 2226 gui.scroll_region_left, 2227 gui.scroll_region_bot, 2228 gui.scroll_region_right); 2229 } 2230 2231 void 2232 gui_mch_insert_lines(int row, int num_lines) 2233 { 2234 PhRect_t rect; 2235 PhPoint_t delta; 2236 2237 rect.ul.x = FILL_X(gui.scroll_region_left); 2238 rect.ul.y = FILL_Y(row); 2239 2240 rect.lr.x = FILL_X(gui.scroll_region_right + 1) - 1; 2241 rect.lr.y = FILL_Y(gui.scroll_region_bot - num_lines + 1) - 1; 2242 2243 PtWidgetOffset(gui.vimTextArea, &gui_ph_raw_offset); 2244 PhTranslatePoint(&gui_ph_raw_offset, PtWidgetPos(gui.vimTextArea, NULL)); 2245 PhTranslateRect(&rect, &gui_ph_raw_offset); 2246 2247 delta.x = 0; 2248 delta.y = num_lines * gui.char_height; 2249 2250 PgFlush(); 2251 2252 PhBlit(PtWidgetRid(PtFindDisjoint(gui.vimTextArea)) , &rect, &delta); 2253 2254 gui_clear_block(row, gui.scroll_region_left, 2255 row + num_lines - 1, gui.scroll_region_right); 2256 } 2257 2258 void 2259 gui_mch_draw_string(int row, int col, char_u *s, int len, int flags) 2260 { 2261 static char *utf8_buffer = NULL; 2262 static int utf8_len = 0; 2263 2264 PhPoint_t pos = { TEXT_X(col), TEXT_Y(row) }; 2265 PhRect_t rect; 2266 2267 if (is_ignore_draw == TRUE) 2268 return; 2269 2270 DRAW_START; 2271 2272 if (!(flags & DRAW_TRANSP)) 2273 { 2274 PgDrawIRect( 2275 FILL_X(col), FILL_Y(row), 2276 FILL_X(col + len) - 1, FILL_Y(row + 1) - 1, 2277 Pg_DRAW_FILL); 2278 } 2279 2280 if (flags & DRAW_UNDERL) 2281 PgSetUnderline(gui.norm_pixel, Pg_TRANSPARENT, 0); 2282 2283 if (charset_translate != NULL 2284 #ifdef FEAT_MBYTE 2285 && enc_utf8 == 0 2286 #endif 2287 ) 2288 { 2289 int src_taken, dst_made; 2290 2291 /* Use a static buffer to avoid large amounts of de/allocations */ 2292 if (utf8_len < len) 2293 { 2294 utf8_buffer = realloc(utf8_buffer, len * MB_LEN_MAX); 2295 utf8_len = len; 2296 } 2297 2298 PxTranslateToUTF( 2299 charset_translate, 2300 s, 2301 len, 2302 &src_taken, 2303 utf8_buffer, 2304 utf8_len, 2305 &dst_made); 2306 s = utf8_buffer; 2307 len = dst_made; 2308 } 2309 2310 PgDrawText(s, len, &pos, 0); 2311 2312 if (flags & DRAW_BOLD) 2313 { 2314 /* FIXME: try and only calculate these values once... */ 2315 rect.ul.x = FILL_X(col) + 1; 2316 rect.ul.y = FILL_Y(row); 2317 rect.lr.x = FILL_X(col + len) - 1; 2318 rect.lr.y = FILL_Y(row + 1) - 1; 2319 /* PgSetUserClip(NULL) causes the scrollbar to not redraw... */ 2320 #if 0 2321 pos.x++; 2322 2323 PgSetUserClip(&rect); 2324 PgDrawText(s, len, &pos, 0); 2325 PgSetUserClip(NULL); 2326 #else 2327 rect.lr.y -= (p_linespace + 1) / 2; 2328 /* XXX: DrawTextArea doesn't work with phditto */ 2329 PgDrawTextArea(s, len, &rect, Pg_TEXT_BOTTOM); 2330 #endif 2331 } 2332 2333 if (flags & DRAW_UNDERL) 2334 PgSetUnderline(Pg_TRANSPARENT, Pg_TRANSPARENT, 0); 2335 2336 DRAW_END; 2337 } 2338 2339 /****************************************************************************/ 2340 /* Cursor */ 2341 2342 void 2343 gui_mch_draw_hollow_cursor(guicolor_T color) 2344 { 2345 PhRect_t r; 2346 2347 /* FIXME: Double width characters */ 2348 2349 r.ul.x = FILL_X(gui.col); 2350 r.ul.y = FILL_Y(gui.row); 2351 r.lr.x = r.ul.x + gui.char_width - 1; 2352 r.lr.y = r.ul.y + gui.char_height - 1; 2353 2354 DRAW_START; 2355 PgSetStrokeColor(color); 2356 PgDrawRect(&r, Pg_DRAW_STROKE); 2357 DRAW_END; 2358 } 2359 2360 void 2361 gui_mch_draw_part_cursor(int w, int h, guicolor_T color) 2362 { 2363 PhRect_t r; 2364 2365 r.ul.x = FILL_X(gui.col); 2366 r.ul.y = FILL_Y(gui.row) + gui.char_height - h; 2367 r.lr.x = r.ul.x + w - 1; 2368 r.lr.y = r.ul.y + h - 1; 2369 2370 DRAW_START; 2371 gui_mch_set_bg_color(color); 2372 PgDrawRect(&r, Pg_DRAW_FILL); 2373 DRAW_END; 2374 } 2375 2376 void 2377 gui_mch_set_blinking(long wait, long on, long off) 2378 { 2379 blink_waittime = wait; 2380 blink_ontime = on; 2381 blink_offtime = off; 2382 } 2383 2384 void 2385 gui_mch_start_blink(void) 2386 { 2387 /* Only turn on the timer on if none of the times are zero */ 2388 if (blink_waittime && blink_ontime && blink_offtime && gui.in_focus) 2389 { 2390 PtSetResource(gui_ph_timer_cursor, Pt_ARG_TIMER_INITIAL, 2391 blink_waittime, 0); 2392 blink_state = BLINK_ON; 2393 gui_update_cursor(TRUE, FALSE); 2394 } 2395 } 2396 2397 void 2398 gui_mch_stop_blink(void) 2399 { 2400 PtSetResource(gui_ph_timer_cursor, Pt_ARG_TIMER_INITIAL, 0, 0); 2401 2402 if (blink_state == BLINK_OFF) 2403 gui_update_cursor(TRUE, FALSE); 2404 2405 blink_state = BLINK_NONE; 2406 } 2407 2408 /****************************************************************************/ 2409 /* miscellaneous functions */ 2410 2411 void 2412 gui_mch_beep(void) 2413 { 2414 PtBeep(); 2415 } 2416 2417 void 2418 gui_mch_flash(int msec) 2419 { 2420 PgSetFillXORColor(Pg_BLACK, Pg_WHITE); 2421 PgSetDrawMode(Pg_DRAWMODE_XOR); 2422 gui_mch_clear_all(); 2423 gui_mch_flush(); 2424 2425 ui_delay((long) msec, TRUE); 2426 2427 gui_mch_clear_all(); 2428 PgSetDrawMode(Pg_DRAWMODE_OPAQUE); 2429 gui_mch_flush(); 2430 } 2431 2432 void 2433 gui_mch_flush(void) 2434 { 2435 PgFlush(); 2436 } 2437 2438 void 2439 gui_mch_set_text_area_pos(int x, int y, int w, int h) 2440 { 2441 PhArea_t area = {{x, y}, {w, h}}; 2442 2443 PtSetResource(gui.vimTextArea, Pt_ARG_AREA, &area, 0); 2444 } 2445 2446 int 2447 gui_mch_haskey(char_u *name) 2448 { 2449 int i; 2450 2451 for (i = 0; special_keys[i].key_sym != 0; i++) 2452 if (name[0] == special_keys[i].vim_code0 && 2453 name[1] == special_keys[i].vim_code1) 2454 return OK; 2455 return FAIL; 2456 } 2457 2458 /****************************************************************************/ 2459 /* Menu */ 2460 2461 #ifdef FEAT_TOOLBAR 2462 #include "toolbar.phi" 2463 2464 static PhImage_t *gui_ph_toolbar_images[] = { 2465 &tb_new_phi, 2466 &tb_open_phi, 2467 &tb_save_phi, 2468 &tb_undo_phi, 2469 &tb_redo_phi, 2470 &tb_cut_phi, 2471 &tb_copy_phi, 2472 &tb_paste_phi, 2473 &tb_print_phi, 2474 &tb_help_phi, 2475 &tb_find_phi, 2476 &tb_save_all_phi, 2477 &tb_save_session_phi, 2478 &tb_new_session_phi, 2479 &tb_load_session_phi, 2480 &tb_macro_phi, 2481 &tb_replace_phi, 2482 &tb_close_phi, 2483 &tb_maximize_phi, 2484 &tb_minimize_phi, 2485 &tb_split_phi, 2486 &tb_shell_phi, 2487 &tb_find_prev_phi, 2488 &tb_find_next_phi, 2489 &tb_find_help_phi, 2490 &tb_make_phi, 2491 &tb_jump_phi, 2492 &tb_ctags_phi, 2493 &tb_vsplit_phi, 2494 &tb_maxwidth_phi, 2495 &tb_minwidth_phi 2496 }; 2497 2498 static PhImage_t * 2499 gui_ph_toolbar_load_icon(char_u *iconfile) 2500 { 2501 static PhImage_t external_icon; 2502 PhImage_t *temp_phi = NULL; 2503 2504 temp_phi = PxLoadImage(iconfile, NULL); 2505 if (temp_phi != NULL) 2506 { 2507 /* The label widget will free the image/palette/etc. for us when 2508 * it's destroyed */ 2509 temp_phi->flags |= Ph_RELEASE_IMAGE_ALL; 2510 memcpy(&external_icon, temp_phi, sizeof(external_icon)); 2511 free(temp_phi); 2512 2513 temp_phi = &external_icon; 2514 } 2515 return temp_phi; 2516 } 2517 2518 /* 2519 * This returns either a builtin icon image, an external image or NULL 2520 * if it can't find either. The caller can't and doesn't need to try and 2521 * free() the returned image, and it can't store the image pointer. 2522 * (When setting the Pt_ARG_LABEL_IMAGE resource, the contents of the 2523 * PhImage_t are copied, and the original PhImage_t aren't needed anymore). 2524 */ 2525 static PhImage_t * 2526 gui_ph_toolbar_find_icon(vimmenu_T *menu) 2527 { 2528 char_u full_pathname[ MAXPATHL + 1 ]; 2529 PhImage_t *icon = NULL; 2530 2531 if (menu->icon_builtin == FALSE) 2532 { 2533 if (menu->iconfile != NULL) 2534 /* TODO: use gui_find_iconfile() */ 2535 icon = gui_ph_toolbar_load_icon(menu->iconfile); 2536 2537 /* TODO: Restrict loading to just .png? Search for any format? */ 2538 if ((icon == NULL) && 2539 ((gui_find_bitmap(menu->name, full_pathname, "gif") == OK) || 2540 (gui_find_bitmap(menu->name, full_pathname, "png") == OK))) 2541 icon = gui_ph_toolbar_load_icon(full_pathname); 2542 2543 if (icon != NULL) 2544 return icon; 2545 } 2546 2547 if (menu->iconidx >= 0 && 2548 (menu->iconidx < ARRAY_LENGTH(gui_ph_toolbar_images))) 2549 { 2550 return gui_ph_toolbar_images[menu->iconidx]; 2551 } 2552 2553 return NULL; 2554 } 2555 #endif 2556 2557 #if defined(FEAT_MENU) || defined(PROTO) 2558 void 2559 gui_mch_enable_menu(int flag) 2560 { 2561 if (flag != 0) 2562 PtRealizeWidget(gui.vimMenuBar); 2563 else 2564 PtUnrealizeWidget(gui.vimMenuBar); 2565 } 2566 2567 void 2568 gui_mch_set_menu_pos(int x, int y, int w, int h) 2569 { 2570 /* Nothing */ 2571 } 2572 2573 /* Change the position of a menu button in the parent */ 2574 static void 2575 gui_ph_position_menu(PtWidget_t *widget, int priority) 2576 { 2577 PtWidget_t *traverse; 2578 vimmenu_T *menu; 2579 2580 traverse = PtWidgetChildBack(PtWidgetParent(widget)); 2581 2582 /* Iterate through the list of widgets in traverse, until 2583 * we find the position we want to insert our widget into */ 2584 /* TODO: traverse from front to back, possible speedup? */ 2585 while (traverse != NULL) 2586 { 2587 PtGetResource(traverse, Pt_ARG_POINTER, &menu, 0); 2588 2589 if (menu != NULL && 2590 priority < menu->priority && 2591 widget != traverse) 2592 { 2593 /* Insert the widget before the current traverse widget */ 2594 PtWidgetInsert(widget, traverse, 1); 2595 return; 2596 } 2597 2598 traverse = PtWidgetBrotherInFront(traverse); 2599 } 2600 } 2601 2602 /* the index is ignored because it's not useful for our purposes */ 2603 void 2604 gui_mch_add_menu(vimmenu_T *menu, int index) 2605 { 2606 vimmenu_T *parent = menu->parent; 2607 char_u *accel_key; 2608 char_u mnemonic_str[MB_LEN_MAX]; 2609 int n; 2610 PtArg_t args[5]; 2611 2612 menu->submenu_id = menu->id = NULL; 2613 2614 if (menu_is_menubar(menu->name)) 2615 { 2616 2617 accel_key = vim_strchr(menu->name, '&'); 2618 if (accel_key != NULL) 2619 { 2620 mnemonic_str[0] = accel_key[1]; 2621 mnemonic_str[1] = NUL; 2622 } 2623 2624 /* Create the menu button */ 2625 n = 0; 2626 PtSetArg(&args[ n++ ], Pt_ARG_TEXT_STRING, menu->dname, 0); 2627 PtSetArg(&args[ n++ ], Pt_ARG_ACCEL_TEXT, menu->actext, 0); 2628 if (accel_key != NULL) 2629 PtSetArg(&args[ n++ ], Pt_ARG_ACCEL_KEY, mnemonic_str, 0); 2630 PtSetArg(&args[ n++ ], Pt_ARG_POINTER, menu, 0); 2631 2632 if (parent != NULL) 2633 PtSetArg(&args[ n++ ], Pt_ARG_BUTTON_TYPE, Pt_MENU_RIGHT, 0); 2634 2635 menu->id = PtCreateWidget(PtMenuButton, 2636 (parent == NULL) ? gui.vimMenuBar : parent->submenu_id, 2637 n, args); 2638 2639 PtAddCallback(menu->id, Pt_CB_ARM, gui_ph_handle_pulldown_menu, menu); 2640 2641 /* Create the actual menu */ 2642 n = 0; 2643 if (parent != NULL) 2644 PtSetArg(&args[ n++ ], Pt_ARG_MENU_FLAGS, Pt_TRUE, Pt_MENU_CHILD); 2645 2646 menu->submenu_id = PtCreateWidget(PtMenu, menu->id, n, args); 2647 2648 if (parent == NULL) 2649 { 2650 PtAddCallback(menu->submenu_id, Pt_CB_UNREALIZED, 2651 gui_ph_handle_menu_unrealized, menu); 2652 2653 if (menu->mnemonic != 0) 2654 { 2655 PtAddHotkeyHandler(gui.vimWindow, tolower(menu->mnemonic), 2656 Pk_KM_Alt, 0, menu, gui_ph_handle_pulldown_menu); 2657 } 2658 } 2659 2660 gui_ph_position_menu(menu->id, menu->priority); 2661 2662 /* Redraw menubar here instead of gui_mch_draw_menubar */ 2663 if (gui.menu_is_active) 2664 PtRealizeWidget(menu->id); 2665 } 2666 else if (menu_is_popup(menu->name)) 2667 { 2668 menu->submenu_id = PtCreateWidget(PtMenu, gui.vimWindow, 0, NULL); 2669 PtAddCallback(menu->submenu_id, Pt_CB_UNREALIZED, 2670 gui_ph_handle_menu_unrealized, menu); 2671 } 2672 } 2673 2674 void 2675 gui_mch_add_menu_item(vimmenu_T *menu, int index) 2676 { 2677 vimmenu_T *parent = menu->parent; 2678 char_u *accel_key; 2679 char_u mnemonic_str[MB_LEN_MAX]; 2680 int n; 2681 PtArg_t args[13]; 2682 2683 n = 0; 2684 PtSetArg(&args[ n++ ], Pt_ARG_POINTER, menu, 0); 2685 2686 #ifdef FEAT_TOOLBAR 2687 if (menu_is_toolbar(parent->name)) 2688 { 2689 if (menu_is_separator(menu->name)) 2690 { 2691 PtSetArg(&args[ n++ ], Pt_ARG_SEP_FLAGS, 2692 Pt_SEP_VERTICAL, Pt_SEP_ORIENTATION); 2693 PtSetArg(&args[ n++ ], Pt_ARG_SEP_TYPE, Pt_ETCHED_IN, 0); 2694 PtSetArg(&args[ n++ ], Pt_ARG_ANCHOR_FLAGS, 2695 Pt_TRUE, Pt_ANCHOR_TOP_BOTTOM); 2696 PtSetArg(&args[ n++ ], Pt_ARG_WIDTH, 2, 0); 2697 menu->id = PtCreateWidget(PtSeparator, gui.vimToolBar, n, args); 2698 } 2699 else 2700 { 2701 if (strstr((const char *) p_toolbar, "text") != NULL) 2702 { 2703 PtSetArg(&args[ n++ ], Pt_ARG_BALLOON_POSITION, 2704 Pt_BALLOON_BOTTOM, 0); 2705 PtSetArg(&args[ n++ ], Pt_ARG_TEXT_STRING, menu->dname, 0); 2706 PtSetArg(&args[ n++ ], Pt_ARG_TEXT_FONT, "TextFont08", 0); 2707 } 2708 if ((strstr((const char *) p_toolbar, "icons") != NULL) && 2709 (gui_ph_toolbar_images != NULL)) 2710 { 2711 PtSetArg(&args[ n++ ], Pt_ARG_LABEL_IMAGE, 2712 gui_ph_toolbar_find_icon(menu), 0); 2713 PtSetArg(&args[ n++ ], Pt_ARG_LABEL_TYPE, Pt_TEXT_IMAGE, 0); 2714 PtSetArg(&args[ n++ ], Pt_ARG_TEXT_IMAGE_SPACING, 0, 0); 2715 } 2716 if (strstr((const char *) p_toolbar, "tooltips") != NULL) 2717 { 2718 PtSetArg(&args[ n++ ], Pt_ARG_LABEL_BALLOON, 2719 gui_ph_show_tooltip, 0); 2720 PtSetArg(&args[ n++ ], Pt_ARG_LABEL_FLAGS, 2721 Pt_TRUE, Pt_SHOW_BALLOON); 2722 } 2723 PtSetArg(&args[ n++ ], Pt_ARG_MARGIN_HEIGHT, 1, 0); 2724 PtSetArg(&args[ n++ ], Pt_ARG_MARGIN_WIDTH, 1, 0); 2725 PtSetArg(&args[ n++ ], Pt_ARG_FLAGS, Pt_FALSE, 2726 Pt_HIGHLIGHTED | Pt_GETS_FOCUS); 2727 PtSetArg(&args[ n++ ], Pt_ARG_FILL_COLOR, Pg_TRANSPARENT, 0); 2728 menu->id = PtCreateWidget(PtButton, gui.vimToolBar, n, args); 2729 2730 PtAddCallback(menu->id, Pt_CB_ACTIVATE, gui_ph_handle_menu, menu); 2731 } 2732 /* Update toolbar if it's open */ 2733 if (PtWidgetIsRealized(gui.vimToolBar)) 2734 PtRealizeWidget(menu->id); 2735 } 2736 else 2737 #endif 2738 if (menu_is_separator(menu->name)) 2739 { 2740 menu->id = PtCreateWidget(PtSeparator, parent->submenu_id, n, args); 2741 } 2742 else 2743 { 2744 accel_key = vim_strchr(menu->name, '&'); 2745 if (accel_key != NULL) 2746 { 2747 mnemonic_str[0] = accel_key[1]; 2748 mnemonic_str[1] = NUL; 2749 } 2750 2751 PtSetArg(&args[ n++ ], Pt_ARG_TEXT_STRING, menu->dname, 0); 2752 if (accel_key != NULL) 2753 PtSetArg(&args[ n++ ], Pt_ARG_ACCEL_KEY, mnemonic_str, 2754 0); 2755 2756 PtSetArg(&args[ n++ ], Pt_ARG_ACCEL_TEXT, menu->actext, 0); 2757 2758 menu->id = PtCreateWidget(PtMenuButton, parent->submenu_id, n, args); 2759 2760 PtAddCallback(menu->id, Pt_CB_ACTIVATE, gui_ph_handle_menu, menu); 2761 2762 #ifdef USE_PANEL_GROUP 2763 if (gui_ph_is_buffer_item(menu, parent) == TRUE) 2764 { 2765 PtAddCallback(menu->id, Pt_CB_DESTROYED, 2766 gui_ph_handle_buffer_remove, menu); 2767 gui_ph_pg_add_buffer(menu->dname); 2768 } 2769 #endif 2770 } 2771 2772 gui_ph_position_menu(menu->id, menu->priority); 2773 } 2774 2775 void 2776 gui_mch_destroy_menu(vimmenu_T *menu) 2777 { 2778 if (menu->submenu_id != NULL) 2779 PtDestroyWidget(menu->submenu_id); 2780 if (menu->id != NULL) 2781 PtDestroyWidget(menu->id); 2782 2783 menu->submenu_id = NULL; 2784 menu->id = NULL; 2785 } 2786 2787 void 2788 gui_mch_menu_grey(vimmenu_T *menu, int grey) 2789 { 2790 long flags, mask, fields; 2791 2792 if (menu->id == NULL) 2793 return; 2794 2795 flags = PtWidgetFlags(menu->id); 2796 if (PtWidgetIsClass(menu->id, PtMenuButton) && 2797 PtWidgetIsClass(PtWidgetParent(menu->id), PtMenu)) 2798 { 2799 fields = Pt_FALSE; 2800 mask = Pt_SELECTABLE | Pt_HIGHLIGHTED; 2801 } 2802 else 2803 { 2804 fields = Pt_TRUE; 2805 mask = Pt_BLOCKED | Pt_GHOST; 2806 } 2807 2808 if (! grey) 2809 fields = ~fields; 2810 2811 PtSetResource(menu->id, Pt_ARG_FLAGS, fields, 2812 mask); 2813 } 2814 2815 void 2816 gui_mch_menu_hidden(vimmenu_T *menu, int hidden) 2817 { 2818 /* TODO: [un]realize the widget? */ 2819 } 2820 2821 void 2822 gui_mch_draw_menubar(void) 2823 { 2824 /* The only time a redraw is needed is when a menu button 2825 * is added to the menubar, and that is detected and the bar 2826 * redrawn in gui_mch_add_menu_item 2827 */ 2828 } 2829 2830 void 2831 gui_mch_show_popupmenu(vimmenu_T *menu) 2832 { 2833 PtSetResource(menu->submenu_id, Pt_ARG_POS, &abs_mouse, 0); 2834 PtRealizeWidget(menu->submenu_id); 2835 } 2836 2837 void 2838 gui_mch_toggle_tearoffs(int enable) 2839 { 2840 /* No tearoffs yet */ 2841 } 2842 2843 #endif 2844 2845 #if defined(FEAT_TOOLBAR) || defined(PROTO) 2846 void 2847 gui_mch_show_toolbar(int showit) 2848 { 2849 if (showit) 2850 PtRealizeWidget(gui.vimToolBar); 2851 else 2852 PtUnrealizeWidget(gui.vimToolBar); 2853 } 2854 #endif 2855 2856 /****************************************************************************/ 2857 /* Fonts */ 2858 2859 static GuiFont 2860 gui_ph_get_font( 2861 char_u *font_name, 2862 int_u font_flags, 2863 int_u font_size, 2864 /* Check whether the resulting font has the font flags and size that 2865 * was asked for */ 2866 int_u enforce 2867 ) 2868 { 2869 char_u *font_tag; 2870 FontQueryInfo info; 2871 int_u style; 2872 2873 font_tag = alloc(MAX_FONT_TAG); 2874 if (font_tag != NULL) 2875 { 2876 if (PfGenerateFontName(font_name, font_flags, font_size, 2877 font_tag) != NULL) 2878 { 2879 /* Enforce some limits on the font used */ 2880 style = PHFONT_INFO_FIXED; 2881 2882 if (enforce & PF_STYLE_BOLD) 2883 style |= PHFONT_INFO_BOLD; 2884 if (enforce & PF_STYLE_ANTIALIAS) 2885 style |= PHFONT_INFO_ALIAS; 2886 if (enforce & PF_STYLE_ITALIC) 2887 style |= PHFONT_INFO_ITALIC; 2888 2889 PfQueryFontInfo(font_tag, &info); 2890 2891 if (info.size == 0) 2892 font_size = 0; 2893 2894 /* Make sure font size matches, and that the font style 2895 * at least has the bits we're checking for */ 2896 if (font_size == info.size && 2897 style == (info.style & style)) 2898 return (GuiFont)font_tag; 2899 } 2900 vim_free(font_tag); 2901 } 2902 return NULL; 2903 } 2904 2905 /* 2906 * Split up the vim font name 2907 * 2908 * vim_font is in the form of 2909 * <name>:s<height>:a:b:i 2910 * 2911 * a = antialias 2912 * b = bold 2913 * i = italic 2914 * 2915 */ 2916 2917 static int 2918 gui_ph_parse_font_name( 2919 char_u *vim_font, 2920 char_u **font_name, 2921 int_u *font_flags, 2922 int_u *font_size) 2923 { 2924 char_u *mark; 2925 int_u name_len, size; 2926 2927 mark = vim_strchr(vim_font, ':'); 2928 if (mark == NULL) 2929 name_len = STRLEN(vim_font); 2930 else 2931 name_len = (int_u) (mark - vim_font); 2932 2933 *font_name = vim_strnsave(vim_font, name_len); 2934 if (*font_name != NULL) 2935 { 2936 if (mark != NULL) 2937 { 2938 while (*mark != NUL && *mark++ == ':') 2939 { 2940 switch (tolower(*mark++)) 2941 { 2942 case 'a': *font_flags |= PF_STYLE_ANTIALIAS; break; 2943 case 'b': *font_flags |= PF_STYLE_BOLD; break; 2944 case 'i': *font_flags |= PF_STYLE_ITALIC; break; 2945 2946 case 's': 2947 size = getdigits(&mark); 2948 /* Restrict the size to some vague limits */ 2949 if (size < 1 || size > 100) 2950 size = 8; 2951 2952 *font_size = size; 2953 break; 2954 2955 default: 2956 break; 2957 } 2958 } 2959 } 2960 return TRUE; 2961 } 2962 return FALSE; 2963 } 2964 2965 int 2966 gui_mch_init_font(char_u *vim_font_name, int fontset) 2967 { 2968 char_u *font_tag; 2969 char_u *font_name = NULL; 2970 int_u font_flags = 0; 2971 int_u font_size = 12; 2972 2973 FontQueryInfo info; 2974 PhRect_t extent; 2975 2976 if (vim_font_name == NULL) 2977 { 2978 /* Default font */ 2979 vim_font_name = "PC Terminal"; 2980 } 2981 2982 if (STRCMP(vim_font_name, "*") == 0) 2983 { 2984 font_tag = PtFontSelection(gui.vimWindow, NULL, NULL, 2985 "pcterm12", -1, PHFONT_FIXED, NULL); 2986 2987 if (font_tag == NULL) 2988 return FAIL; 2989 2990 gui_mch_free_font(gui.norm_font); 2991 gui.norm_font = font_tag; 2992 2993 PfQueryFontInfo(font_tag, &info); 2994 font_name = vim_strsave(info.font); 2995 } 2996 else 2997 { 2998 if (gui_ph_parse_font_name(vim_font_name, &font_name, &font_flags, 2999 &font_size) == FALSE) 3000 return FAIL; 3001 3002 font_tag = gui_ph_get_font(font_name, font_flags, font_size, 0); 3003 if (font_tag == NULL) 3004 { 3005 vim_free(font_name); 3006 return FAIL; 3007 } 3008 3009 gui_mch_free_font(gui.norm_font); 3010 gui.norm_font = font_tag; 3011 } 3012 3013 gui_mch_free_font(gui.bold_font); 3014 gui.bold_font = gui_ph_get_font(font_name, font_flags | PF_STYLE_BOLD, 3015 font_size, PF_STYLE_BOLD); 3016 3017 gui_mch_free_font(gui.ital_font); 3018 gui.ital_font = gui_ph_get_font(font_name, font_flags | PF_STYLE_ITALIC, 3019 font_size, PF_STYLE_ITALIC); 3020 3021 /* This extent was brought to you by the letter 'g' */ 3022 PfExtentText(&extent, NULL, font_tag, "g", 1); 3023 3024 gui.char_width = extent.lr.x - extent.ul.x + 1; 3025 gui.char_height = (- extent.ul.y) + extent.lr.y + 1; 3026 gui.char_ascent = - extent.ul.y; 3027 3028 vim_free(font_name); 3029 return OK; 3030 } 3031 3032 /* 3033 * Adjust gui.char_height (after 'linespace' was changed). 3034 */ 3035 int 3036 gui_mch_adjust_charheight(void) 3037 { 3038 FontQueryInfo info; 3039 3040 PfQueryFontInfo(gui.norm_font, &info); 3041 3042 gui.char_height = - info.ascender + info.descender + p_linespace; 3043 gui.char_ascent = - info.ascender + p_linespace / 2; 3044 3045 return OK; 3046 } 3047 3048 GuiFont 3049 gui_mch_get_font(char_u *vim_font_name, int report_error) 3050 { 3051 char_u *font_name; 3052 char_u *font_tag; 3053 int_u font_size = 12; 3054 int_u font_flags = 0; 3055 3056 if (gui_ph_parse_font_name(vim_font_name, &font_name, &font_flags, 3057 &font_size) != FALSE) 3058 { 3059 font_tag = gui_ph_get_font(font_name, font_flags, font_size, -1); 3060 vim_free(font_name); 3061 3062 if (font_tag != NULL) 3063 return (GuiFont)font_tag; 3064 } 3065 3066 if (report_error) 3067 EMSG2(e_font, vim_font_name); 3068 3069 return FAIL; 3070 } 3071 3072 #if defined(FEAT_EVAL) || defined(PROTO) 3073 /* 3074 * Return the name of font "font" in allocated memory. 3075 * Don't know how to get the actual name, thus use the provided name. 3076 */ 3077 char_u * 3078 gui_mch_get_fontname(GuiFont font, char_u *name) 3079 { 3080 if (name == NULL) 3081 return NULL; 3082 return vim_strsave(name); 3083 } 3084 #endif 3085 3086 void 3087 gui_mch_set_font(GuiFont font) 3088 { 3089 PgSetFont(font); 3090 } 3091 3092 void 3093 gui_mch_free_font(GuiFont font) 3094 { 3095 vim_free(font); 3096 } 3097 3098