UNIXworkcode

1 /* 2 * Copyright 2019 Olaf Wintermann 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 * DEALINGS IN THE SOFTWARE. 21 */ 22 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 27 #include <Xm/XmAll.h> 28 #include <Xm/XmP.h> 29 30 #include <X11/Xft/Xft.h> 31 #include <fontconfig/fontconfig.h> 32 33 #include "nedit_malloc.h" 34 #include "misc.h" 35 36 #include "fontsel.h" 37 38 #define PREVIEW_STR "ABCDEFGHIJabcdefghijklmn[](){}.:,;-_$%&/\"''" 39 40 #define MONOSPACE_ONLY_DEFAULT 1 41 42 static XftColor default_fg_color; 43 static Pixel default_bg_pix; 44 static int default_colors_set = 0; 45 46 typedef struct FontSelector { 47 FcPattern *filter; 48 FcFontSet *list; 49 50 Widget pattern; 51 Widget fontlist; 52 Widget size; 53 Widget preview; 54 Widget name; 55 56 XftFont *font; 57 XftFont *bold; 58 XftFont *italic; 59 XftDraw *draw; 60 XftColor color; 61 Boolean enable_bg; 62 63 int selected_item; 64 int end; 65 int cancel; 66 } FontSelector; 67 68 static void UpdatePreview(FontSelector *sel, const char *fontStr) 69 { 70 Display *dp = XtDisplay(sel->preview); 71 XftFont *font = XftFontOpenName(dp, DefaultScreen(dp), fontStr); 72 if(!font) { 73 return; 74 } 75 if(sel->font) { 76 XftFontClose(dp, sel->font); 77 } 78 79 size_t fontStrLen = strlen(fontStr); 80 char *boldFontStr = FontNameAddAttribute(fontStr, fontStrLen, 81 "weight", "bold"); 82 char *italicFontStr = FontNameAddAttribute(fontStr, fontStrLen, 83 "slant", "italic"); 84 85 XftFont *boldFont = XftFontOpenName(dp, DefaultScreen(dp), boldFontStr); 86 XftFont *italicFont = XftFontOpenName(dp, DefaultScreen(dp), italicFontStr); 87 88 NEditFree(boldFontStr); 89 NEditFree(italicFontStr); 90 91 if(sel->bold) { 92 XftFontClose(dp, sel->bold); 93 } 94 if(sel->italic) { 95 XftFontClose(dp, sel->italic); 96 } 97 98 sel->font = font; 99 sel->bold = boldFont; 100 sel->italic = italicFont; 101 } 102 103 static void InitXftDraw(FontSelector *sel) 104 { 105 if(sel->draw) { 106 return; 107 } 108 109 XWindowAttributes attributes; 110 XGetWindowAttributes(XtDisplay(sel->preview), XtWindow(sel->preview), &attributes); 111 Screen *screen = XtScreen(sel->preview); 112 Visual *visual = screen->root_visual; 113 114 Cardinal depth; 115 Colormap colormap; 116 XtVaGetValues(sel->preview, XtNdepth, &depth, XtNcolormap, &colormap, NULL); 117 118 for(int i=0;i<screen->ndepths;i++) { 119 Depth d = screen->depths[i]; 120 if(d.depth == depth) { 121 visual = d.visuals; 122 break; 123 } 124 } 125 126 Display *dp = XtDisplay(sel->preview); 127 sel->draw = XftDrawCreate( 128 dp, 129 XtWindow(sel->preview), 130 visual, 131 colormap); 132 133 Pixel previewFg; 134 XtVaGetValues(sel->preview, XmNforeground, &previewFg, NULL); 135 136 XColor xcolor; 137 memset(&xcolor, 0, sizeof(XColor)); 138 xcolor.pixel = previewFg; 139 XQueryColor(XtDisplay(sel->preview), sel->preview->core.colormap, &xcolor); 140 141 sel->color.pixel = previewFg; 142 sel->color.color.red = xcolor.red; 143 sel->color.color.green = xcolor.green; 144 sel->color.color.blue = xcolor.blue; 145 sel->color.color.alpha = 0xFFFF; 146 147 if(default_colors_set) { 148 sel->color = default_fg_color; 149 sel->enable_bg = True; 150 XtVaSetValues(sel->preview, XmNbackground, default_bg_pix, NULL); 151 } 152 } 153 154 static void exposeFontPreview(Widget w, FontSelector *sel, XtPointer data) 155 { 156 InitXftDraw(sel); 157 if(!sel->font) { 158 return; 159 } 160 161 Dimension width, height; 162 XtVaGetValues( 163 w, 164 XmNwidth, 165 &width, 166 XmNheight, 167 &height, 168 NULL); 169 170 XClearWindow(XtDisplay(w), XtWindow(w)); 171 172 int fontHeight = sel->font->ascent + sel->font->descent; 173 174 int boldHeight = 0; 175 int italicHeight = 0; 176 int extraSpace = 0; 177 if(sel->bold) { 178 boldHeight = sel->bold->ascent + sel->bold->descent; 179 extraSpace += 5; 180 } 181 if(sel->italic) { 182 italicHeight = sel->italic->ascent + sel->italic->descent; 183 extraSpace += 5; 184 } 185 186 int space = height - fontHeight - boldHeight - italicHeight - extraSpace; 187 188 int y = space/2; 189 XftDrawStringUtf8( 190 sel->draw, 191 &sel->color, 192 sel->font, 193 10, 194 y + sel->font->ascent, 195 (unsigned char*) PREVIEW_STR, 196 sizeof(PREVIEW_STR)-1); 197 y += fontHeight + 5; 198 199 if(sel->bold) { 200 XftDrawStringUtf8( 201 sel->draw, 202 &sel->color, 203 sel->bold, 204 10, 205 y + sel->bold->ascent, 206 (unsigned char*) PREVIEW_STR, 207 sizeof(PREVIEW_STR)-1); 208 y += boldHeight + 5; 209 } 210 if(sel->italic) { 211 XftDrawStringUtf8( 212 sel->draw, 213 &sel->color, 214 sel->italic, 215 10, 216 y + sel->italic->ascent, 217 (unsigned char*) PREVIEW_STR, 218 sizeof(PREVIEW_STR)-1); 219 } 220 } 221 222 static int compare_font(const void *d1, const void *d2) { 223 const FcPattern *f1 = *((const FcPattern**)d1); 224 const FcPattern *f2 = *((const FcPattern**)d2); 225 226 FcChar8 *name1 = NULL; 227 FcChar8 *name2 = NULL; 228 FcPatternGetString(f1, FC_FULLNAME, 0, &name1); 229 FcPatternGetString(f2, FC_FULLNAME, 0, &name2); 230 231 FcChar8 *family1 = NULL; 232 FcChar8 *family2 = NULL; 233 FcPatternGetString(f1, FC_FAMILY, 0, &family1); 234 FcPatternGetString(f2, FC_FAMILY, 0, &family2); 235 236 if(name1 && name2) { 237 return strcmp((char*)name1, (char*)name2); 238 } else if(family1 && family2) { 239 return strcmp((char*)family1, (char*)family2); 240 } else { 241 return 0; 242 } 243 } 244 245 static char* CreateFontName(FcChar8 *family, FcChar8 *style) { 246 size_t flen = family ? strlen((char*)family) : 0; 247 size_t slen = style ? strlen((char*)style) : 0; 248 249 size_t len = flen + slen + 4; 250 char *name = NEditMalloc(len); 251 252 if(!family) { 253 snprintf(name, len, "-"); 254 } else if(style) { 255 snprintf(name, len, "%s %s", (char*)family, (char*)style); 256 } else { 257 snprintf(name, len, "%s", (char*)family); 258 } 259 return name; 260 } 261 262 static void UpdateFontList(FontSelector *sel, const char *pattern) 263 { 264 XmStringTable items; 265 FcChar8 *name; 266 FcChar8 *family; 267 FcChar8 *style; 268 int nfonts, nfound; 269 270 if(pattern) { 271 if(sel->filter) { 272 FcPatternDestroy(sel->filter); 273 sel->filter = NULL; 274 } 275 sel->filter = FcNameParse((FcChar8*)pattern); 276 } 277 if(!sel->filter) { 278 sel->filter = FcPatternCreate(); 279 } 280 281 FcObjectSet *os = FcObjectSetCreate(); 282 FcObjectSetAdd(os, FC_FAMILY); 283 FcObjectSetAdd(os, FC_STYLE); 284 FcObjectSetAdd(os, FC_FULLNAME); 285 FcObjectSetAdd(os, FC_SCALABLE); 286 FcObjectSetAdd(os, FC_SPACING); 287 288 if(sel->list) { 289 FcFontSetDestroy(sel->list); 290 } 291 sel->list = FcFontList(NULL, sel->filter, os); 292 FcObjectSetDestroy(os); 293 294 nfonts = sel->list->nfont; 295 nfound = 0; 296 297 // sort fonts 298 qsort(sel->list->fonts, nfonts, sizeof(FcPattern*), compare_font); 299 300 items = NEditCalloc(sel->list->nfont, sizeof(XmString)); 301 for(int i=0;i<nfonts;i++) { 302 FcBool scalable = 0; 303 FcPatternGetBool(sel->list->fonts[i], FC_SCALABLE, 0, &scalable); 304 int spacing = 0; 305 FcPatternGetInteger(sel->list->fonts[i], FC_SPACING, 0, &spacing); 306 307 name = NULL; 308 FcPatternGetString(sel->list->fonts[i], FC_FULLNAME, 0, &name); 309 310 family = NULL; 311 FcPatternGetString(sel->list->fonts[i], FC_FAMILY, 0, &family); 312 313 style = NULL; 314 FcPatternGetString(sel->list->fonts[i], FC_STYLE, 0, &style); 315 316 if(name) { 317 items[nfound] = XmStringCreateSimple((char*)name); 318 } else { 319 name = (FcChar8*)CreateFontName(family, style); 320 items[nfound] = XmStringCreateSimple((char*)name); 321 NEditFree(name); 322 } 323 324 nfound++; 325 } 326 327 XtVaSetValues(sel->fontlist, XmNitems, items, XmNitemCount, nfound, NULL); 328 for(int i=0;i<nfound;i++) { 329 XmStringFree(items[i]); 330 } 331 NEditFree(items); 332 } 333 334 static void MatchFont(const char *name, XmString *retName, XmString *retSize) 335 { 336 *retName = NULL; 337 *retSize = NULL; 338 339 FcPattern* pat = FcNameParse((const FcChar8*)name); 340 341 FcConfigSubstitute(NULL, pat, FcMatchPattern); 342 FcDefaultSubstitute(pat); 343 FcResult result; 344 FcPattern* font = FcFontMatch(NULL, pat, &result); 345 if(font) { 346 FcChar8* nameStr = NULL; 347 FcChar8* familyStr = NULL; 348 double fontSize = 0; 349 if (FcPatternGetString(font, FC_FULLNAME, 0, &nameStr) == FcResultMatch) { 350 *retName = XmStringCreateSimple((char*)nameStr); 351 } else if (FcPatternGetString(font, FC_FAMILY, 0, &familyStr) == FcResultMatch) { 352 FcChar8 *styleStr = NULL; 353 FcPatternGetString(font, FC_STYLE, 0, &styleStr); 354 if(styleStr) { 355 char *fontName = CreateFontName(familyStr, styleStr); 356 *retName = XmStringCreateSimple(fontName); 357 NEditFree(fontName); 358 } 359 } 360 if(FcPatternGetDouble(font, FC_SIZE, 0, &fontSize) == FcResultMatch) { 361 char buf[8]; 362 snprintf(buf, 8, "%d", (int)fontSize); 363 *retSize = XmStringCreateSimple(buf); 364 } 365 FcPatternDestroy(font); 366 } 367 FcPatternDestroy(pat); 368 } 369 370 static void CreateSizeList(Widget w) 371 { 372 XmStringTable items = NEditCalloc(30, sizeof(XmString)); 373 char buf[8]; 374 for(int i=0;i<30;i++) { 375 snprintf(buf, 8, "%d", i+5); 376 items[i] = XmStringCreateSimple(buf); 377 } 378 379 XtVaSetValues(w, XmNitems, items, XmNitemCount, 30, NULL); 380 for(int i=0;i<30;i++) { 381 XmStringFree(items[i]); 382 } 383 NEditFree(items); 384 } 385 386 static char* GetFontString(FontSelector *sel) 387 { 388 XmStringTable table = NULL; 389 int count = 0; 390 int i = sel->selected_item - 1; 391 char *font = NULL; 392 char *style = NULL; 393 char *size = NULL; 394 size_t fontLen, styleLen, sizeLen, outLen; 395 char *out; 396 397 if(i < 0) return NULL; 398 399 FcPatternGetString(sel->list->fonts[i], FC_FAMILY, 0, (FcChar8**)&font); 400 FcPatternGetString(sel->list->fonts[i], FC_STYLE, 0, (FcChar8**)&style); 401 402 XtVaGetValues( 403 sel->size, 404 XmNselectedItems, 405 &table, 406 XmNselectedItemCount, 407 &count, 408 NULL); 409 if(count > 0) { 410 XmStringGetLtoR(table[0], XmFONTLIST_DEFAULT_TAG, &size); 411 } 412 413 if(style && !strcmp(style, "Regular")) { 414 style = NULL; 415 } 416 417 fontLen = font ? strlen(font) : 0; 418 styleLen = style ? strlen(style) : 0; 419 sizeLen = size ? strlen(size) : 0; 420 421 if(style && size) { 422 outLen = fontLen + styleLen + sizeLen + 16; 423 out = XtMalloc(outLen); 424 snprintf(out, outLen, "%s:style=%s:size=%s", font, style, size); 425 XmTextSetString(sel->name, out); 426 XtFree(size); 427 return out; 428 } else if(size) { 429 outLen = fontLen + sizeLen + 16; 430 out = XtMalloc(outLen); 431 snprintf(out, outLen, "%s:size=%s", font, size); 432 XmTextSetString(sel->name, out); 433 XtFree(size); 434 return out; 435 } else { 436 return font; 437 } 438 } 439 440 static void UpdateFontName(FontSelector *sel) 441 { 442 char *fontStr = GetFontString(sel); 443 if(fontStr) { 444 UpdatePreview(sel, fontStr); 445 exposeFontPreview(sel->preview, sel, NULL); 446 XmTextSetString(sel->name, fontStr); 447 XtFree(fontStr); 448 } 449 } 450 451 static void fontlist_callback(Widget w, FontSelector *sel, XmListCallbackStruct *cb) 452 { 453 sel->selected_item = cb->item_position; 454 UpdateFontName(sel); 455 } 456 457 static void SetMonospaceFilter(FontSelector *sel, Boolean on) 458 { 459 if(sel->filter) { 460 FcPatternDestroy(sel->filter); 461 } 462 sel->filter = FcPatternCreate(); 463 if(on) { 464 FcPatternAddInteger(sel->filter, FC_SPACING, FC_MONO); 465 } 466 } 467 468 void fontlist_toggle_monospace(Widget w, FontSelector *sel, XmToggleButtonCallbackStruct *cb) 469 { 470 SetMonospaceFilter(sel, cb->set); 471 UpdateFontList(sel, NULL); 472 } 473 474 void size_callback (Widget w, FontSelector *sel, XtPointer data) 475 { 476 UpdateFontName(sel); 477 } 478 479 static void ok_callback(Widget w, FontSelector *sel, XtPointer data) 480 { 481 sel->end = 1; 482 } 483 484 static void cancel_callback(Widget w, FontSelector *sel, XtPointer data) 485 { 486 sel->end = 1; 487 sel->cancel = 1; 488 } 489 490 static void FreeFontSelector(FontSelector *sel) 491 { 492 FcPatternDestroy(sel->filter); 493 Display *dp = XtDisplay(sel->preview); 494 495 XftDrawDestroy(sel->draw); 496 if(sel->font) { 497 XftFontClose(dp, sel->font); 498 } 499 if(sel->bold) { 500 XftFontClose(dp, sel->bold); 501 } 502 if(sel->italic) { 503 XftFontClose(dp, sel->italic); 504 } 505 if(sel->list) { 506 FcFontSetDestroy(sel->list); 507 } 508 509 NEditFree(sel); 510 } 511 512 char *FontSel(Widget parent, const char *curFont) 513 { 514 Arg args[32]; 515 int n = 0; 516 XmString str; 517 518 FontSelector *sel = NEditMalloc(sizeof(FontSelector)); 519 memset(sel, 0, sizeof(FontSelector)); 520 521 Widget dialog = CreateDialogShell(parent, "Font Selector", args, 0); 522 AddMotifCloseCallback(dialog, (XtCallbackProc)cancel_callback, sel); 523 Widget form = XmCreateForm(dialog, "form", args, 0); 524 525 /* ok button */ 526 n = 0; 527 str = XmStringCreateSimple("OK"); 528 XtSetArg(args[n], XmNtopOffset, 2); n++; 529 XtSetArg(args[n], XmNleftOffset, 5); n++; 530 XtSetArg(args[n], XmNbottomOffset, 5); n++; 531 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; 532 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; 533 XtSetArg(args[n], XmNlabelString, str); n++; 534 Widget okButton = XmCreatePushButton(form, "button", args, n); 535 XtManageChild(okButton); 536 XmStringFree(str); 537 XtAddCallback( 538 okButton, 539 XmNactivateCallback, 540 (XtCallbackProc)ok_callback, 541 sel); 542 543 /* cancel button */ 544 n = 0; 545 str = XmStringCreateSimple("Cancel"); 546 XtSetArg(args[n], XmNtopOffset, 2); n++; 547 XtSetArg(args[n], XmNrightOffset, 5); n++; 548 XtSetArg(args[n], XmNbottomOffset, 5); n++; 549 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; 550 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; 551 XtSetArg(args[n], XmNlabelString, str); n++; 552 Widget cancelButton = XmCreatePushButton(form, "button", args, n); 553 XtManageChild(cancelButton); 554 XmStringFree(str); 555 XtAddCallback( 556 cancelButton, 557 XmNactivateCallback, 558 (XtCallbackProc)cancel_callback, 559 sel); 560 561 /* font name */ 562 n = 0; 563 XtSetArg(args[n], XmNbottomOffset, 2); n++; 564 XtSetArg(args[n], XmNleftOffset, 5); n++; 565 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; 566 XtSetArg(args[n], XmNleftOffset, 5); n++; 567 XtSetArg(args[n], XmNrightOffset, 5); n++; 568 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; 569 XtSetArg(args[n], XmNwidth, 400); n++; 570 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; 571 XtSetArg(args[n], XmNbottomWidget, okButton); n++; 572 sel->name = XmCreateText(form, "fcname_textfield", args, n); 573 XtManageChild(sel->name); 574 575 /* font name label */ 576 n = 0; 577 str = XmStringCreateSimple("Font name:"); 578 XtSetArg(args[n], XmNbottomOffset, 2); n++; 579 XtSetArg(args[n], XmNleftOffset, 5); n++; 580 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; 581 XtSetArg(args[n], XmNlabelString, str); n++; 582 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; 583 XtSetArg(args[n], XmNbottomWidget, sel->name); n++; 584 Widget fontNameLabel = XmCreateLabel(form, "label", args, n); 585 XtManageChild(fontNameLabel); 586 XmStringFree(str); 587 588 /* preview */ 589 n = 0; 590 XtSetArg(args[n], XmNbottomOffset, 2); n++; 591 XtSetArg(args[n], XmNleftOffset, 5); n++; 592 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; 593 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; 594 XtSetArg(args[n], XmNrightOffset, 5); n++; 595 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; 596 XtSetArg(args[n], XmNbottomWidget, fontNameLabel); n++; 597 XtSetArg(args[n], XmNshadowType, XmSHADOW_IN); n++; 598 XtSetArg(args[n], XmNmarginWidth, 3); n++; 599 XtSetArg(args[n], XmNmarginHeight, 3); n++; 600 Widget previewFrame = XmCreateFrame(form, "frame", args, n); 601 XtManageChild(previewFrame); 602 603 n = 0; 604 sel->preview = XmCreateDrawingArea(previewFrame, "fontpreview", args, n); 605 Dimension w, h; 606 XtMakeResizeRequest(sel->preview, 450, 180, &w, &h); 607 XtManageChild(sel->preview); 608 609 XtAddCallback( 610 sel->preview, 611 XmNexposeCallback, 612 (XtCallbackProc)exposeFontPreview, 613 sel); 614 615 /* toggle monospace */ 616 n = 0; 617 str = XmStringCreateSimple("Show only non-proportional fonts"); 618 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; 619 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; 620 XtSetArg(args[n], XmNtopOffset, 5); n++; 621 XtSetArg(args[n], XmNleftOffset, 5); n++; 622 XtSetArg(args[n], XmNlabelString, str); n++; 623 XtSetArg(args[n], XmNset, MONOSPACE_ONLY_DEFAULT); n++; 624 Widget toggleMonospace = XmCreateToggleButton(form, "toggle_monospace", args, n); 625 XtManageChild(toggleMonospace); 626 XmStringFree(str); 627 XtAddCallback( 628 toggleMonospace, 629 XmNvalueChangedCallback, 630 (XtCallbackProc)fontlist_toggle_monospace, 631 sel); 632 633 /* label */ 634 n = 0; 635 str = XmStringCreateSimple("Font:"); 636 XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; 637 XtSetArg(args[n], XmNtopWidget, toggleMonospace); n++; 638 XtSetArg(args[n], XmNtopOffset, 5); n++; 639 XtSetArg(args[n], XmNleftOffset, 5); n++; 640 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; 641 XtSetArg(args[n], XmNlabelString, str); n++; 642 Widget fontListLabel = XmCreateLabel(form, "label", args, n); 643 XtManageChild(fontListLabel); 644 XmStringFree(str); 645 646 n = 0; 647 str = XmStringCreateSimple("Size:"); 648 XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; 649 XtSetArg(args[n], XmNtopWidget, toggleMonospace); n++; 650 XtSetArg(args[n], XmNtopOffset, 5); n++; 651 XtSetArg(args[n], XmNrightOffset, 5); n++; 652 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; 653 XtSetArg(args[n], XmNlabelString, str); n++; 654 Widget fontSizeLabel = XmCreateLabel(form, "label", args, n); 655 XtManageChild(fontSizeLabel); 656 XmStringFree(str); 657 658 /* font size list */ 659 n = 0; 660 XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; 661 XtSetArg(args[n], XmNtopWidget, fontSizeLabel); n++; 662 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; 663 XtSetArg(args[n], XmNrightOffset, 5); n++; 664 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; 665 XtSetArg(args[n], XmNbottomWidget, previewFrame); n++; 666 XtSetArg(args[n], XmNleftOffset, 2); n++; 667 XtSetArg(args[n], XmNbottomOffset, 2); n++; 668 XtSetArg(args[n], XmNtopOffset, 2); n++; 669 sel->size = XmCreateScrolledList(form, "sizelist", args, n); 670 CreateSizeList(sel->size); 671 XtAddCallback (sel->size, XmNbrowseSelectionCallback, (XtCallbackProc)size_callback, sel); 672 XmListSelectPos(sel->size, 6, 0); 673 XtManageChild(sel->size); 674 675 Dimension szListWidth; 676 XtVaGetValues(sel->size, XmNwidth, &szListWidth, NULL); 677 if(szListWidth > 0 && szListWidth < 40) { 678 XtVaSetValues(sel->size, XmNwidth, 40, NULL); 679 } 680 681 /* font list */ 682 n = 0; 683 XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; 684 XtSetArg(args[n], XmNtopWidget, fontListLabel); n++; 685 XtSetArg(args[n], XmNtopOffset, 2); n++; 686 XtSetArg(args[n], XmNbottomOffset, 2); n++; 687 XtSetArg(args[n], XmNleftOffset, 5); n++; 688 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; 689 XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; 690 XtSetArg(args[n], XmNrightWidget, sel->size); n++; 691 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; 692 XtSetArg(args[n], XmNbottomWidget, previewFrame); n++; 693 XtSetArg(args[n], XmNvisibleItemCount, 10); n++; 694 sel->fontlist = XmCreateScrolledList(form, "fontlist", args, n); 695 AddMouseWheelSupport(sel->fontlist); 696 XtManageChild(sel->fontlist); 697 XtAddCallback( 698 sel->fontlist, 699 XmNbrowseSelectionCallback, 700 (XtCallbackProc)fontlist_callback, 701 sel); 702 703 704 UpdatePreview(sel, curFont); 705 706 SetMonospaceFilter(sel, MONOSPACE_ONLY_DEFAULT); 707 UpdateFontList(sel, NULL); 708 XmString fontSelection; 709 XmString sizeSelection; 710 MatchFont(curFont, &fontSelection, &sizeSelection); 711 if(fontSelection) { 712 XmListSelectItem(sel->fontlist, fontSelection, 0); 713 XmStringFree(fontSelection); 714 int *pos; 715 int selcount = 0; 716 if(XmListGetSelectedPos(sel->fontlist, &pos, &selcount)) { 717 sel->selected_item = pos[0]; 718 XtFree((void*)pos); 719 } 720 } 721 if(sizeSelection) { 722 XmListSelectItem(sel->size, sizeSelection, 0); 723 XmStringFree(sizeSelection); 724 } 725 726 ManageDialogCenteredOnPointer(form); 727 728 XtAppContext app = XtWidgetToApplicationContext(dialog); 729 while(!sel->end && !XtAppGetExitFlag(app)) { 730 XEvent event; 731 XtAppNextEvent(app, &event); 732 XtDispatchEvent(&event); 733 } 734 735 XtDestroyWidget(dialog); 736 char *retStr = NULL; 737 if(!sel->cancel) { 738 retStr = GetFontString(sel); 739 } 740 if(!retStr) { 741 retStr = NEditStrdup(curFont); 742 } 743 744 FreeFontSelector(sel); 745 return retStr; 746 } 747 748 749 char* FontNameAddAttribute( 750 const char *name, 751 size_t len, 752 const char *attribute, 753 const char *value) 754 { 755 size_t attributelen = strlen(attribute); 756 size_t valuelen = strlen(value); 757 size_t newlen = len + attributelen + valuelen + 4; 758 char *attr = NEditMalloc(attributelen+3); 759 char *newfont = NEditMalloc(newlen); 760 char *oldattr; 761 int i = len; 762 int b = 0; 763 int e = 0; 764 765 /* check if the font name already has this attribute */ 766 attr[0] = ':'; 767 memcpy(attr+1, attribute, attributelen); 768 attr[attributelen+1] = '='; 769 attr[attributelen+2] = '\0'; 770 oldattr = strstr(name, attr); 771 if(oldattr) { 772 b = (int)(oldattr - name)+1; 773 e = len; 774 for(i=b;i<len;i++) { 775 if(name[i] == ':') { 776 e = i; 777 break; 778 } 779 } 780 } 781 NEditFree(attr); 782 783 if(b < len) { 784 if(b > 0 && name[b-1] == ':') b--; 785 snprintf(newfont, newlen, "%.*s%.*s:%s=%s", b, name, (int)(len-e), name+e, attribute, value); 786 } else { 787 snprintf(newfont, newlen, "%s:%s=%s", name, attribute, value); 788 } 789 790 return newfont; 791 } 792 793 void FontSelSetColors(XftColor fg, Pixel bg) { 794 default_fg_color = fg; 795 default_bg_pix = bg; 796 default_colors_set = 1; 797 } 798