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