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