1 /* vi:set ts=8 sts=4 sw=4 noet: 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 guicolor_T 1937 gui_mch_get_rgb(guicolor_T pixel) 1938 { 1939 return (guicolor_T)(PgRGB(PgRedValue(pixel), 1940 PgGreenValue(pixel), PgBlueValue(pixel))); 1941 } 1942 1943 void 1944 gui_mch_new_colors(void) 1945 { 1946 #if 0 /* Don't bother changing the cursor colour */ 1947 short color_diff; 1948 1949 /* 1950 * If there isn't enough difference between the background colour and 1951 * the mouse pointer colour then change the mouse pointer colour 1952 */ 1953 color_diff = gui_get_lightness(gui_ph_mouse_color) 1954 - gui_get_lightness(gui.back_pixel); 1955 1956 if (abs(color_diff) < 64) 1957 { 1958 short r, g, b; 1959 /* not a great algorithm... */ 1960 r = PgRedValue(gui_ph_mouse_color) ^ 255; 1961 g = PgGreenValue(gui_ph_mouse_color) ^ 255; 1962 b = PgBlueValue(gui_ph_mouse_color) ^ 255; 1963 1964 #ifndef FEAT_MOUSESHAPE 1965 gui_ph_mouse_color = PgRGB(r, g, b); 1966 PtSetResource(gui.vimTextArea, Pt_ARG_CURSOR_COLOR, 1967 gui_ph_mouse_color, 0); 1968 #endif 1969 } 1970 #endif 1971 1972 PtSetResource(gui.vimTextArea, Pt_ARG_FILL_COLOR, gui.back_pixel, 0); 1973 } 1974 1975 /* 1976 * This should be split out into a separate file, 1977 * every port does basically the same thing. 1978 * 1979 * This is the gui_w32.c version (i think..) 1980 * Return INVALCOLOR when failed. 1981 */ 1982 1983 guicolor_T 1984 gui_mch_get_color(char_u *name) 1985 { 1986 return gui_get_color_cmn(name); 1987 } 1988 1989 guicolor_T 1990 gui_mch_get_rgb_color(int r, int g, int b) 1991 { 1992 return gui_get_rgb_color_cmn(r, g, b); 1993 } 1994 1995 void 1996 gui_mch_set_fg_color(guicolor_T color) 1997 { 1998 PgSetTextColor(color); 1999 } 2000 2001 void 2002 gui_mch_set_bg_color(guicolor_T color) 2003 { 2004 PgSetFillColor(color); 2005 } 2006 2007 void 2008 gui_mch_set_sp_color(guicolor_T color) 2009 { 2010 } 2011 2012 void 2013 gui_mch_invert_rectangle(int row, int col, int nr, int nc) 2014 { 2015 PhRect_t rect; 2016 2017 rect.ul.x = FILL_X(col); 2018 rect.ul.y = FILL_Y(row); 2019 2020 /* FIXME: This has an off by one pixel problem */ 2021 rect.lr.x = rect.ul.x + nc * gui.char_width; 2022 rect.lr.y = rect.ul.y + nr * gui.char_height; 2023 if (nc > 0) 2024 rect.lr.x -= 1; 2025 if (nr > 0) 2026 rect.lr.y -= 1; 2027 2028 DRAW_START; 2029 PgSetDrawMode(Pg_DrawModeDSTINVERT); 2030 PgDrawRect(&rect, Pg_DRAW_FILL); 2031 PgSetDrawMode(Pg_DrawModeSRCCOPY); 2032 DRAW_END; 2033 } 2034 2035 void 2036 gui_mch_clear_block(int row1, int col1, int row2, int col2) 2037 { 2038 PhRect_t block = { 2039 { FILL_X(col1), FILL_Y(row1) }, 2040 { FILL_X(col2 + 1) - 1, FILL_Y(row2 + 1) - 1} 2041 }; 2042 2043 DRAW_START; 2044 gui_mch_set_bg_color(gui.back_pixel); 2045 PgDrawRect(&block, Pg_DRAW_FILL); 2046 DRAW_END; 2047 } 2048 2049 void 2050 gui_mch_clear_all(void) 2051 { 2052 PhRect_t text_rect = { 2053 { gui.border_width, gui.border_width }, 2054 { Columns * gui.char_width + gui.border_width - 1 , 2055 Rows * gui.char_height + gui.border_width - 1 } 2056 }; 2057 2058 if (is_ignore_draw == TRUE) 2059 return; 2060 2061 DRAW_START; 2062 gui_mch_set_bg_color(gui.back_pixel); 2063 PgDrawRect(&text_rect, Pg_DRAW_FILL); 2064 DRAW_END; 2065 } 2066 2067 void 2068 gui_mch_delete_lines(int row, int num_lines) 2069 { 2070 PhRect_t rect; 2071 PhPoint_t delta; 2072 2073 rect.ul.x = FILL_X(gui.scroll_region_left); 2074 rect.ul.y = FILL_Y(row + num_lines); 2075 2076 rect.lr.x = FILL_X(gui.scroll_region_right + 1) - 1; 2077 rect.lr.y = FILL_Y(gui.scroll_region_bot + 1) - 1; 2078 2079 PtWidgetOffset(gui.vimTextArea, &gui_ph_raw_offset); 2080 PhTranslatePoint(&gui_ph_raw_offset, PtWidgetPos(gui.vimTextArea, NULL)); 2081 PhTranslateRect(&rect, &gui_ph_raw_offset); 2082 2083 delta.x = 0; 2084 delta.y = -num_lines * gui.char_height; 2085 2086 PgFlush(); 2087 2088 PhBlit(PtWidgetRid(PtFindDisjoint(gui.vimTextArea)), &rect, &delta); 2089 2090 gui_clear_block( 2091 gui.scroll_region_bot - num_lines + 1, 2092 gui.scroll_region_left, 2093 gui.scroll_region_bot, 2094 gui.scroll_region_right); 2095 } 2096 2097 void 2098 gui_mch_insert_lines(int row, int num_lines) 2099 { 2100 PhRect_t rect; 2101 PhPoint_t delta; 2102 2103 rect.ul.x = FILL_X(gui.scroll_region_left); 2104 rect.ul.y = FILL_Y(row); 2105 2106 rect.lr.x = FILL_X(gui.scroll_region_right + 1) - 1; 2107 rect.lr.y = FILL_Y(gui.scroll_region_bot - num_lines + 1) - 1; 2108 2109 PtWidgetOffset(gui.vimTextArea, &gui_ph_raw_offset); 2110 PhTranslatePoint(&gui_ph_raw_offset, PtWidgetPos(gui.vimTextArea, NULL)); 2111 PhTranslateRect(&rect, &gui_ph_raw_offset); 2112 2113 delta.x = 0; 2114 delta.y = num_lines * gui.char_height; 2115 2116 PgFlush(); 2117 2118 PhBlit(PtWidgetRid(PtFindDisjoint(gui.vimTextArea)) , &rect, &delta); 2119 2120 gui_clear_block(row, gui.scroll_region_left, 2121 row + num_lines - 1, gui.scroll_region_right); 2122 } 2123 2124 void 2125 gui_mch_draw_string(int row, int col, char_u *s, int len, int flags) 2126 { 2127 static char *utf8_buffer = NULL; 2128 static int utf8_len = 0; 2129 2130 PhPoint_t pos = { TEXT_X(col), TEXT_Y(row) }; 2131 PhRect_t rect; 2132 2133 if (is_ignore_draw == TRUE) 2134 return; 2135 2136 DRAW_START; 2137 2138 if (!(flags & DRAW_TRANSP)) 2139 { 2140 PgDrawIRect( 2141 FILL_X(col), FILL_Y(row), 2142 FILL_X(col + len) - 1, FILL_Y(row + 1) - 1, 2143 Pg_DRAW_FILL); 2144 } 2145 2146 if (flags & DRAW_UNDERL) 2147 PgSetUnderline(gui.norm_pixel, Pg_TRANSPARENT, 0); 2148 2149 if (charset_translate != NULL 2150 #ifdef FEAT_MBYTE 2151 && enc_utf8 == 0 2152 #endif 2153 ) 2154 { 2155 int src_taken, dst_made; 2156 2157 /* Use a static buffer to avoid large amounts of de/allocations */ 2158 if (utf8_len < len) 2159 { 2160 utf8_buffer = realloc(utf8_buffer, len * MB_LEN_MAX); 2161 utf8_len = len; 2162 } 2163 2164 PxTranslateToUTF( 2165 charset_translate, 2166 s, 2167 len, 2168 &src_taken, 2169 utf8_buffer, 2170 utf8_len, 2171 &dst_made); 2172 s = utf8_buffer; 2173 len = dst_made; 2174 } 2175 2176 PgDrawText(s, len, &pos, 0); 2177 2178 if (flags & DRAW_BOLD) 2179 { 2180 /* FIXME: try and only calculate these values once... */ 2181 rect.ul.x = FILL_X(col) + 1; 2182 rect.ul.y = FILL_Y(row); 2183 rect.lr.x = FILL_X(col + len) - 1; 2184 rect.lr.y = FILL_Y(row + 1) - 1; 2185 /* PgSetUserClip(NULL) causes the scrollbar to not redraw... */ 2186 #if 0 2187 pos.x++; 2188 2189 PgSetUserClip(&rect); 2190 PgDrawText(s, len, &pos, 0); 2191 PgSetUserClip(NULL); 2192 #else 2193 rect.lr.y -= (p_linespace + 1) / 2; 2194 /* XXX: DrawTextArea doesn't work with phditto */ 2195 PgDrawTextArea(s, len, &rect, Pg_TEXT_BOTTOM); 2196 #endif 2197 } 2198 2199 if (flags & DRAW_UNDERL) 2200 PgSetUnderline(Pg_TRANSPARENT, Pg_TRANSPARENT, 0); 2201 2202 DRAW_END; 2203 } 2204 2205 /****************************************************************************/ 2206 /* Cursor */ 2207 2208 void 2209 gui_mch_draw_hollow_cursor(guicolor_T color) 2210 { 2211 PhRect_t r; 2212 2213 /* FIXME: Double width characters */ 2214 2215 r.ul.x = FILL_X(gui.col); 2216 r.ul.y = FILL_Y(gui.row); 2217 r.lr.x = r.ul.x + gui.char_width - 1; 2218 r.lr.y = r.ul.y + gui.char_height - 1; 2219 2220 DRAW_START; 2221 PgSetStrokeColor(color); 2222 PgDrawRect(&r, Pg_DRAW_STROKE); 2223 DRAW_END; 2224 } 2225 2226 void 2227 gui_mch_draw_part_cursor(int w, int h, guicolor_T color) 2228 { 2229 PhRect_t r; 2230 2231 r.ul.x = FILL_X(gui.col); 2232 r.ul.y = FILL_Y(gui.row) + gui.char_height - h; 2233 r.lr.x = r.ul.x + w - 1; 2234 r.lr.y = r.ul.y + h - 1; 2235 2236 DRAW_START; 2237 gui_mch_set_bg_color(color); 2238 PgDrawRect(&r, Pg_DRAW_FILL); 2239 DRAW_END; 2240 } 2241 2242 int 2243 gui_mch_is_blinking(void) 2244 { 2245 return blink_state != BLINK_NONE; 2246 } 2247 2248 int 2249 gui_mch_is_blink_off(void) 2250 { 2251 return blink_state == BLINK_OFF; 2252 } 2253 2254 void 2255 gui_mch_set_blinking(long wait, long on, long off) 2256 { 2257 blink_waittime = wait; 2258 blink_ontime = on; 2259 blink_offtime = off; 2260 } 2261 2262 void 2263 gui_mch_start_blink(void) 2264 { 2265 /* Only turn on the timer on if none of the times are zero */ 2266 if (blink_waittime && blink_ontime && blink_offtime && gui.in_focus) 2267 { 2268 PtSetResource(gui_ph_timer_cursor, Pt_ARG_TIMER_INITIAL, 2269 blink_waittime, 0); 2270 blink_state = BLINK_ON; 2271 gui_update_cursor(TRUE, FALSE); 2272 } 2273 } 2274 2275 void 2276 gui_mch_stop_blink(void) 2277 { 2278 PtSetResource(gui_ph_timer_cursor, Pt_ARG_TIMER_INITIAL, 0, 0); 2279 2280 if (blink_state == BLINK_OFF) 2281 gui_update_cursor(TRUE, FALSE); 2282 2283 blink_state = BLINK_NONE; 2284 } 2285 2286 /****************************************************************************/ 2287 /* miscellaneous functions */ 2288 2289 void 2290 gui_mch_beep(void) 2291 { 2292 PtBeep(); 2293 } 2294 2295 void 2296 gui_mch_flash(int msec) 2297 { 2298 PgSetFillXORColor(Pg_BLACK, Pg_WHITE); 2299 PgSetDrawMode(Pg_DRAWMODE_XOR); 2300 gui_mch_clear_all(); 2301 gui_mch_flush(); 2302 2303 ui_delay((long) msec, TRUE); 2304 2305 gui_mch_clear_all(); 2306 PgSetDrawMode(Pg_DRAWMODE_OPAQUE); 2307 gui_mch_flush(); 2308 } 2309 2310 void 2311 gui_mch_flush(void) 2312 { 2313 PgFlush(); 2314 } 2315 2316 void 2317 gui_mch_set_text_area_pos(int x, int y, int w, int h) 2318 { 2319 PhArea_t area = {{x, y}, {w, h}}; 2320 2321 PtSetResource(gui.vimTextArea, Pt_ARG_AREA, &area, 0); 2322 } 2323 2324 int 2325 gui_mch_haskey(char_u *name) 2326 { 2327 int i; 2328 2329 for (i = 0; special_keys[i].key_sym != 0; i++) 2330 if (name[0] == special_keys[i].vim_code0 && 2331 name[1] == special_keys[i].vim_code1) 2332 return OK; 2333 return FAIL; 2334 } 2335 2336 /****************************************************************************/ 2337 /* Menu */ 2338 2339 #ifdef FEAT_TOOLBAR 2340 #include "toolbar.phi" 2341 2342 static PhImage_t *gui_ph_toolbar_images[] = { 2343 &tb_new_phi, 2344 &tb_open_phi, 2345 &tb_save_phi, 2346 &tb_undo_phi, 2347 &tb_redo_phi, 2348 &tb_cut_phi, 2349 &tb_copy_phi, 2350 &tb_paste_phi, 2351 &tb_print_phi, 2352 &tb_help_phi, 2353 &tb_find_phi, 2354 &tb_save_all_phi, 2355 &tb_save_session_phi, 2356 &tb_new_session_phi, 2357 &tb_load_session_phi, 2358 &tb_macro_phi, 2359 &tb_replace_phi, 2360 &tb_close_phi, 2361 &tb_maximize_phi, 2362 &tb_minimize_phi, 2363 &tb_split_phi, 2364 &tb_shell_phi, 2365 &tb_find_prev_phi, 2366 &tb_find_next_phi, 2367 &tb_find_help_phi, 2368 &tb_make_phi, 2369 &tb_jump_phi, 2370 &tb_ctags_phi, 2371 &tb_vsplit_phi, 2372 &tb_maxwidth_phi, 2373 &tb_minwidth_phi 2374 }; 2375 2376 static PhImage_t * 2377 gui_ph_toolbar_load_icon(char_u *iconfile) 2378 { 2379 static PhImage_t external_icon; 2380 PhImage_t *temp_phi = NULL; 2381 2382 temp_phi = PxLoadImage(iconfile, NULL); 2383 if (temp_phi != NULL) 2384 { 2385 /* The label widget will free the image/palette/etc. for us when 2386 * it's destroyed */ 2387 temp_phi->flags |= Ph_RELEASE_IMAGE_ALL; 2388 memcpy(&external_icon, temp_phi, sizeof(external_icon)); 2389 free(temp_phi); 2390 2391 temp_phi = &external_icon; 2392 } 2393 return temp_phi; 2394 } 2395 2396 /* 2397 * This returns either a builtin icon image, an external image or NULL 2398 * if it can't find either. The caller can't and doesn't need to try and 2399 * free() the returned image, and it can't store the image pointer. 2400 * (When setting the Pt_ARG_LABEL_IMAGE resource, the contents of the 2401 * PhImage_t are copied, and the original PhImage_t aren't needed anymore). 2402 */ 2403 static PhImage_t * 2404 gui_ph_toolbar_find_icon(vimmenu_T *menu) 2405 { 2406 char_u full_pathname[ MAXPATHL + 1 ]; 2407 PhImage_t *icon = NULL; 2408 2409 if (menu->icon_builtin == FALSE) 2410 { 2411 if (menu->iconfile != NULL) 2412 /* TODO: use gui_find_iconfile() */ 2413 icon = gui_ph_toolbar_load_icon(menu->iconfile); 2414 2415 /* TODO: Restrict loading to just .png? Search for any format? */ 2416 if ((icon == NULL) && 2417 ((gui_find_bitmap(menu->name, full_pathname, "gif") == OK) || 2418 (gui_find_bitmap(menu->name, full_pathname, "png") == OK))) 2419 icon = gui_ph_toolbar_load_icon(full_pathname); 2420 2421 if (icon != NULL) 2422 return icon; 2423 } 2424 2425 if (menu->iconidx >= 0 && 2426 (menu->iconidx < ARRAY_LENGTH(gui_ph_toolbar_images))) 2427 { 2428 return gui_ph_toolbar_images[menu->iconidx]; 2429 } 2430 2431 return NULL; 2432 } 2433 #endif 2434 2435 #if defined(FEAT_MENU) || defined(PROTO) 2436 void 2437 gui_mch_enable_menu(int flag) 2438 { 2439 if (flag != 0) 2440 PtRealizeWidget(gui.vimMenuBar); 2441 else 2442 PtUnrealizeWidget(gui.vimMenuBar); 2443 } 2444 2445 void 2446 gui_mch_set_menu_pos(int x, int y, int w, int h) 2447 { 2448 /* Nothing */ 2449 } 2450 2451 /* Change the position of a menu button in the parent */ 2452 static void 2453 gui_ph_position_menu(PtWidget_t *widget, int priority) 2454 { 2455 PtWidget_t *traverse; 2456 vimmenu_T *menu; 2457 2458 traverse = PtWidgetChildBack(PtWidgetParent(widget)); 2459 2460 /* Iterate through the list of widgets in traverse, until 2461 * we find the position we want to insert our widget into */ 2462 /* TODO: traverse from front to back, possible speedup? */ 2463 while (traverse != NULL) 2464 { 2465 PtGetResource(traverse, Pt_ARG_POINTER, &menu, 0); 2466 2467 if (menu != NULL && 2468 priority < menu->priority && 2469 widget != traverse) 2470 { 2471 /* Insert the widget before the current traverse widget */ 2472 PtWidgetInsert(widget, traverse, 1); 2473 return; 2474 } 2475 2476 traverse = PtWidgetBrotherInFront(traverse); 2477 } 2478 } 2479 2480 /* the index is ignored because it's not useful for our purposes */ 2481 void 2482 gui_mch_add_menu(vimmenu_T *menu, int index) 2483 { 2484 vimmenu_T *parent = menu->parent; 2485 char_u *accel_key; 2486 char_u mnemonic_str[MB_LEN_MAX]; 2487 int n; 2488 PtArg_t args[5]; 2489 2490 menu->submenu_id = menu->id = NULL; 2491 2492 if (menu_is_menubar(menu->name)) 2493 { 2494 2495 accel_key = vim_strchr(menu->name, '&'); 2496 if (accel_key != NULL) 2497 { 2498 mnemonic_str[0] = accel_key[1]; 2499 mnemonic_str[1] = NUL; 2500 } 2501 2502 /* Create the menu button */ 2503 n = 0; 2504 PtSetArg(&args[ n++ ], Pt_ARG_TEXT_STRING, menu->dname, 0); 2505 PtSetArg(&args[ n++ ], Pt_ARG_ACCEL_TEXT, menu->actext, 0); 2506 if (accel_key != NULL) 2507 PtSetArg(&args[ n++ ], Pt_ARG_ACCEL_KEY, mnemonic_str, 0); 2508 PtSetArg(&args[ n++ ], Pt_ARG_POINTER, menu, 0); 2509 2510 if (parent != NULL) 2511 PtSetArg(&args[ n++ ], Pt_ARG_BUTTON_TYPE, Pt_MENU_RIGHT, 0); 2512 2513 menu->id = PtCreateWidget(PtMenuButton, 2514 (parent == NULL) ? gui.vimMenuBar : parent->submenu_id, 2515 n, args); 2516 2517 PtAddCallback(menu->id, Pt_CB_ARM, gui_ph_handle_pulldown_menu, menu); 2518 2519 /* Create the actual menu */ 2520 n = 0; 2521 if (parent != NULL) 2522 PtSetArg(&args[ n++ ], Pt_ARG_MENU_FLAGS, Pt_TRUE, Pt_MENU_CHILD); 2523 2524 menu->submenu_id = PtCreateWidget(PtMenu, menu->id, n, args); 2525 2526 if (parent == NULL) 2527 { 2528 PtAddCallback(menu->submenu_id, Pt_CB_UNREALIZED, 2529 gui_ph_handle_menu_unrealized, menu); 2530 2531 if (menu->mnemonic != 0) 2532 { 2533 PtAddHotkeyHandler(gui.vimWindow, tolower(menu->mnemonic), 2534 Pk_KM_Alt, 0, menu, gui_ph_handle_pulldown_menu); 2535 } 2536 } 2537 2538 gui_ph_position_menu(menu->id, menu->priority); 2539 2540 /* Redraw menubar here instead of gui_mch_draw_menubar */ 2541 if (gui.menu_is_active) 2542 PtRealizeWidget(menu->id); 2543 } 2544 else if (menu_is_popup(menu->name)) 2545 { 2546 menu->submenu_id = PtCreateWidget(PtMenu, gui.vimWindow, 0, NULL); 2547 PtAddCallback(menu->submenu_id, Pt_CB_UNREALIZED, 2548 gui_ph_handle_menu_unrealized, menu); 2549 } 2550 } 2551 2552 void 2553 gui_mch_add_menu_item(vimmenu_T *menu, int index) 2554 { 2555 vimmenu_T *parent = menu->parent; 2556 char_u *accel_key; 2557 char_u mnemonic_str[MB_LEN_MAX]; 2558 int n; 2559 PtArg_t args[13]; 2560 2561 n = 0; 2562 PtSetArg(&args[ n++ ], Pt_ARG_POINTER, menu, 0); 2563 2564 #ifdef FEAT_TOOLBAR 2565 if (menu_is_toolbar(parent->name)) 2566 { 2567 if (menu_is_separator(menu->name)) 2568 { 2569 PtSetArg(&args[ n++ ], Pt_ARG_SEP_FLAGS, 2570 Pt_SEP_VERTICAL, Pt_SEP_ORIENTATION); 2571 PtSetArg(&args[ n++ ], Pt_ARG_SEP_TYPE, Pt_ETCHED_IN, 0); 2572 PtSetArg(&args[ n++ ], Pt_ARG_ANCHOR_FLAGS, 2573 Pt_TRUE, Pt_ANCHOR_TOP_BOTTOM); 2574 PtSetArg(&args[ n++ ], Pt_ARG_WIDTH, 2, 0); 2575 menu->id = PtCreateWidget(PtSeparator, gui.vimToolBar, n, args); 2576 } 2577 else 2578 { 2579 if (strstr((const char *) p_toolbar, "text") != NULL) 2580 { 2581 PtSetArg(&args[ n++ ], Pt_ARG_BALLOON_POSITION, 2582 Pt_BALLOON_BOTTOM, 0); 2583 PtSetArg(&args[ n++ ], Pt_ARG_TEXT_STRING, menu->dname, 0); 2584 PtSetArg(&args[ n++ ], Pt_ARG_TEXT_FONT, "TextFont08", 0); 2585 } 2586 if ((strstr((const char *) p_toolbar, "icons") != NULL) && 2587 (gui_ph_toolbar_images != NULL)) 2588 { 2589 PtSetArg(&args[ n++ ], Pt_ARG_LABEL_IMAGE, 2590 gui_ph_toolbar_find_icon(menu), 0); 2591 PtSetArg(&args[ n++ ], Pt_ARG_LABEL_TYPE, Pt_TEXT_IMAGE, 0); 2592 PtSetArg(&args[ n++ ], Pt_ARG_TEXT_IMAGE_SPACING, 0, 0); 2593 } 2594 if (strstr((const char *) p_toolbar, "tooltips") != NULL) 2595 { 2596 PtSetArg(&args[ n++ ], Pt_ARG_LABEL_BALLOON, 2597 gui_ph_show_tooltip, 0); 2598 PtSetArg(&args[ n++ ], Pt_ARG_LABEL_FLAGS, 2599 Pt_TRUE, Pt_SHOW_BALLOON); 2600 } 2601 PtSetArg(&args[ n++ ], Pt_ARG_MARGIN_HEIGHT, 1, 0); 2602 PtSetArg(&args[ n++ ], Pt_ARG_MARGIN_WIDTH, 1, 0); 2603 PtSetArg(&args[ n++ ], Pt_ARG_FLAGS, Pt_FALSE, 2604 Pt_HIGHLIGHTED | Pt_GETS_FOCUS); 2605 PtSetArg(&args[ n++ ], Pt_ARG_FILL_COLOR, Pg_TRANSPARENT, 0); 2606 menu->id = PtCreateWidget(PtButton, gui.vimToolBar, n, args); 2607 2608 PtAddCallback(menu->id, Pt_CB_ACTIVATE, gui_ph_handle_menu, menu); 2609 } 2610 /* Update toolbar if it's open */ 2611 if (PtWidgetIsRealized(gui.vimToolBar)) 2612 PtRealizeWidget(menu->id); 2613 } 2614 else 2615 #endif 2616 if (menu_is_separator(menu->name)) 2617 { 2618 menu->id = PtCreateWidget(PtSeparator, parent->submenu_id, n, args); 2619 } 2620 else 2621 { 2622 accel_key = vim_strchr(menu->name, '&'); 2623 if (accel_key != NULL) 2624 { 2625 mnemonic_str[0] = accel_key[1]; 2626 mnemonic_str[1] = NUL; 2627 } 2628 2629 PtSetArg(&args[ n++ ], Pt_ARG_TEXT_STRING, menu->dname, 0); 2630 if (accel_key != NULL) 2631 PtSetArg(&args[ n++ ], Pt_ARG_ACCEL_KEY, mnemonic_str, 2632 0); 2633 2634 PtSetArg(&args[ n++ ], Pt_ARG_ACCEL_TEXT, menu->actext, 0); 2635 2636 menu->id = PtCreateWidget(PtMenuButton, parent->submenu_id, n, args); 2637 2638 PtAddCallback(menu->id, Pt_CB_ACTIVATE, gui_ph_handle_menu, menu); 2639 2640 #ifdef USE_PANEL_GROUP 2641 if (gui_ph_is_buffer_item(menu, parent) == TRUE) 2642 { 2643 PtAddCallback(menu->id, Pt_CB_DESTROYED, 2644 gui_ph_handle_buffer_remove, menu); 2645 gui_ph_pg_add_buffer(menu->dname); 2646 } 2647 #endif 2648 } 2649 2650 gui_ph_position_menu(menu->id, menu->priority); 2651 } 2652 2653 void 2654 gui_mch_destroy_menu(vimmenu_T *menu) 2655 { 2656 if (menu->submenu_id != NULL) 2657 PtDestroyWidget(menu->submenu_id); 2658 if (menu->id != NULL) 2659 PtDestroyWidget(menu->id); 2660 2661 menu->submenu_id = NULL; 2662 menu->id = NULL; 2663 } 2664 2665 void 2666 gui_mch_menu_grey(vimmenu_T *menu, int grey) 2667 { 2668 long flags, mask, fields; 2669 2670 if (menu->id == NULL) 2671 return; 2672 2673 flags = PtWidgetFlags(menu->id); 2674 if (PtWidgetIsClass(menu->id, PtMenuButton) && 2675 PtWidgetIsClass(PtWidgetParent(menu->id), PtMenu)) 2676 { 2677 fields = Pt_FALSE; 2678 mask = Pt_SELECTABLE | Pt_HIGHLIGHTED; 2679 } 2680 else 2681 { 2682 fields = Pt_TRUE; 2683 mask = Pt_BLOCKED | Pt_GHOST; 2684 } 2685 2686 if (! grey) 2687 fields = ~fields; 2688 2689 PtSetResource(menu->id, Pt_ARG_FLAGS, fields, 2690 mask); 2691 } 2692 2693 void 2694 gui_mch_menu_hidden(vimmenu_T *menu, int hidden) 2695 { 2696 /* TODO: [un]realize the widget? */ 2697 } 2698 2699 void 2700 gui_mch_draw_menubar(void) 2701 { 2702 /* The only time a redraw is needed is when a menu button 2703 * is added to the menubar, and that is detected and the bar 2704 * redrawn in gui_mch_add_menu_item 2705 */ 2706 } 2707 2708 void 2709 gui_mch_show_popupmenu(vimmenu_T *menu) 2710 { 2711 PtSetResource(menu->submenu_id, Pt_ARG_POS, &abs_mouse, 0); 2712 PtRealizeWidget(menu->submenu_id); 2713 } 2714 2715 void 2716 gui_mch_toggle_tearoffs(int enable) 2717 { 2718 /* No tearoffs yet */ 2719 } 2720 2721 #endif 2722 2723 #if defined(FEAT_TOOLBAR) || defined(PROTO) 2724 void 2725 gui_mch_show_toolbar(int showit) 2726 { 2727 if (showit) 2728 PtRealizeWidget(gui.vimToolBar); 2729 else 2730 PtUnrealizeWidget(gui.vimToolBar); 2731 } 2732 #endif 2733 2734 /****************************************************************************/ 2735 /* Fonts */ 2736 2737 static GuiFont 2738 gui_ph_get_font( 2739 char_u *font_name, 2740 int_u font_flags, 2741 int_u font_size, 2742 /* Check whether the resulting font has the font flags and size that 2743 * was asked for */ 2744 int_u enforce 2745 ) 2746 { 2747 char_u *font_tag; 2748 FontQueryInfo info; 2749 int_u style; 2750 2751 font_tag = alloc(MAX_FONT_TAG); 2752 if (font_tag != NULL) 2753 { 2754 if (PfGenerateFontName(font_name, font_flags, font_size, 2755 font_tag) != NULL) 2756 { 2757 /* Enforce some limits on the font used */ 2758 style = PHFONT_INFO_FIXED; 2759 2760 if (enforce & PF_STYLE_BOLD) 2761 style |= PHFONT_INFO_BOLD; 2762 if (enforce & PF_STYLE_ANTIALIAS) 2763 style |= PHFONT_INFO_ALIAS; 2764 if (enforce & PF_STYLE_ITALIC) 2765 style |= PHFONT_INFO_ITALIC; 2766 2767 PfQueryFontInfo(font_tag, &info); 2768 2769 if (info.size == 0) 2770 font_size = 0; 2771 2772 /* Make sure font size matches, and that the font style 2773 * at least has the bits we're checking for */ 2774 if (font_size == info.size && 2775 style == (info.style & style)) 2776 return (GuiFont)font_tag; 2777 } 2778 vim_free(font_tag); 2779 } 2780 return NULL; 2781 } 2782 2783 /* 2784 * Split up the vim font name 2785 * 2786 * vim_font is in the form of 2787 * <name>:s<height>:a:b:i 2788 * 2789 * a = antialias 2790 * b = bold 2791 * i = italic 2792 * 2793 */ 2794 2795 static int 2796 gui_ph_parse_font_name( 2797 char_u *vim_font, 2798 char_u **font_name, 2799 int_u *font_flags, 2800 int_u *font_size) 2801 { 2802 char_u *mark; 2803 int_u name_len, size; 2804 2805 mark = vim_strchr(vim_font, ':'); 2806 if (mark == NULL) 2807 name_len = STRLEN(vim_font); 2808 else 2809 name_len = (int_u) (mark - vim_font); 2810 2811 *font_name = vim_strnsave(vim_font, name_len); 2812 if (*font_name != NULL) 2813 { 2814 if (mark != NULL) 2815 { 2816 while (*mark != NUL && *mark++ == ':') 2817 { 2818 switch (tolower(*mark++)) 2819 { 2820 case 'a': *font_flags |= PF_STYLE_ANTIALIAS; break; 2821 case 'b': *font_flags |= PF_STYLE_BOLD; break; 2822 case 'i': *font_flags |= PF_STYLE_ITALIC; break; 2823 2824 case 's': 2825 size = getdigits(&mark); 2826 /* Restrict the size to some vague limits */ 2827 if (size < 1 || size > 100) 2828 size = 8; 2829 2830 *font_size = size; 2831 break; 2832 2833 default: 2834 break; 2835 } 2836 } 2837 } 2838 return TRUE; 2839 } 2840 return FALSE; 2841 } 2842 2843 int 2844 gui_mch_init_font(char_u *vim_font_name, int fontset) 2845 { 2846 char_u *font_tag; 2847 char_u *font_name = NULL; 2848 int_u font_flags = 0; 2849 int_u font_size = 12; 2850 2851 FontQueryInfo info; 2852 PhRect_t extent; 2853 2854 if (vim_font_name == NULL) 2855 { 2856 /* Default font */ 2857 vim_font_name = "PC Terminal"; 2858 } 2859 2860 if (STRCMP(vim_font_name, "*") == 0) 2861 { 2862 font_tag = PtFontSelection(gui.vimWindow, NULL, NULL, 2863 "pcterm12", -1, PHFONT_FIXED, NULL); 2864 2865 if (font_tag == NULL) 2866 return FAIL; 2867 2868 gui_mch_free_font(gui.norm_font); 2869 gui.norm_font = font_tag; 2870 2871 PfQueryFontInfo(font_tag, &info); 2872 font_name = vim_strsave(info.font); 2873 } 2874 else 2875 { 2876 if (gui_ph_parse_font_name(vim_font_name, &font_name, &font_flags, 2877 &font_size) == FALSE) 2878 return FAIL; 2879 2880 font_tag = gui_ph_get_font(font_name, font_flags, font_size, 0); 2881 if (font_tag == NULL) 2882 { 2883 vim_free(font_name); 2884 return FAIL; 2885 } 2886 2887 gui_mch_free_font(gui.norm_font); 2888 gui.norm_font = font_tag; 2889 } 2890 2891 gui_mch_free_font(gui.bold_font); 2892 gui.bold_font = gui_ph_get_font(font_name, font_flags | PF_STYLE_BOLD, 2893 font_size, PF_STYLE_BOLD); 2894 2895 gui_mch_free_font(gui.ital_font); 2896 gui.ital_font = gui_ph_get_font(font_name, font_flags | PF_STYLE_ITALIC, 2897 font_size, PF_STYLE_ITALIC); 2898 2899 /* This extent was brought to you by the letter 'g' */ 2900 PfExtentText(&extent, NULL, font_tag, "g", 1); 2901 2902 gui.char_width = extent.lr.x - extent.ul.x + 1; 2903 gui.char_height = (- extent.ul.y) + extent.lr.y + 1; 2904 gui.char_ascent = - extent.ul.y; 2905 2906 vim_free(font_name); 2907 return OK; 2908 } 2909 2910 /* 2911 * Adjust gui.char_height (after 'linespace' was changed). 2912 */ 2913 int 2914 gui_mch_adjust_charheight(void) 2915 { 2916 FontQueryInfo info; 2917 2918 PfQueryFontInfo(gui.norm_font, &info); 2919 2920 gui.char_height = - info.ascender + info.descender + p_linespace; 2921 gui.char_ascent = - info.ascender + p_linespace / 2; 2922 2923 return OK; 2924 } 2925 2926 GuiFont 2927 gui_mch_get_font(char_u *vim_font_name, int report_error) 2928 { 2929 char_u *font_name; 2930 char_u *font_tag; 2931 int_u font_size = 12; 2932 int_u font_flags = 0; 2933 2934 if (gui_ph_parse_font_name(vim_font_name, &font_name, &font_flags, 2935 &font_size) != FALSE) 2936 { 2937 font_tag = gui_ph_get_font(font_name, font_flags, font_size, -1); 2938 vim_free(font_name); 2939 2940 if (font_tag != NULL) 2941 return (GuiFont)font_tag; 2942 } 2943 2944 if (report_error) 2945 EMSG2(e_font, vim_font_name); 2946 2947 return FAIL; 2948 } 2949 2950 #if defined(FEAT_EVAL) || defined(PROTO) 2951 /* 2952 * Return the name of font "font" in allocated memory. 2953 * Don't know how to get the actual name, thus use the provided name. 2954 */ 2955 char_u * 2956 gui_mch_get_fontname(GuiFont font, char_u *name) 2957 { 2958 if (name == NULL) 2959 return NULL; 2960 return vim_strsave(name); 2961 } 2962 #endif 2963 2964 void 2965 gui_mch_set_font(GuiFont font) 2966 { 2967 PgSetFont(font); 2968 } 2969 2970 void 2971 gui_mch_free_font(GuiFont font) 2972 { 2973 vim_free(font); 2974 } 2975 2976