1/* 2 3Copyright (c) 1991 X Consortium 4 5Permission is hereby granted, free of charge, to any person obtaining 6a copy of this software and associated documentation files (the 7"Software"), to deal in the Software without restriction, including 8without limitation the rights to use, copy, modify, merge, publish, 9distribute, sublicense, and/or sell copies of the Software, and to 10permit persons to whom the Software is furnished to do so, subject to 11the following conditions: 12 13The above copyright notice and this permission notice shall be included 14in all copies or substantial portions of the Software. 15 16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR 20OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22OTHER DEALINGS IN THE SOFTWARE. 23 24Except as contained in this notice, the name of the X Consortium shall 25not be used in advertising or otherwise to promote the sale, use or 26other dealings in this Software without prior written authorization 27from the X Consortium. 28 29*/ 30 31/* xgc 32** 33** main.c 34** 35** Contains the bare minimum necessary to oversee the whole operation. 36*/ 37 38#include <X11/Intrinsic.h> 39#include <X11/StringDefs.h> 40#include <X11/Xaw/Form.h> 41#include <X11/Xaw/Command.h> 42#include <X11/Xaw/AsciiText.h> 43#include <X11/Shell.h> 44#include <stdio.h> 45#include <stdlib.h> 46 47#include "xgc.h" 48#define DEFINE_TILE 49#include "tile" 50 51static void fill_up_commandform(Widget); 52static void quit(void); 53static void quitAction(Widget, XEvent *, String *, Cardinal *); 54static void clear_test_window(void); 55static void clear_result_window(void); 56static void set_foreground_and_background(void); 57 58/* The three columns in the XgcData arrays are: 59** name: the name of the toggle button 60** text: the corresponding text in the xgc syntax 61** code: the integer that the text corresponds to, for sending stuff 62** to X calls, etc. 63*/ 64 65static XgcData FunctionData[NUM_FUNCTIONS] = { 66 {"clear", "clear", GXclear}, 67 {"and", "and", GXand}, 68 {"andReverse", "andReverse", GXandReverse}, 69 {"copy", "copy", GXcopy}, 70 {"andInverted", "andInverted", GXandInverted}, 71 {"noop", "noop", GXnoop}, 72 {"xor", "xor", GXxor}, 73 {"or", "or", GXor}, 74 {"nor", "nor", GXnor}, 75 {"equiv", "equiv", GXequiv}, 76 {"invert", "invert", GXinvert}, 77 {"orReverse", "orReverse", GXorReverse}, 78 {"copyInverted", "copyInverted", GXcopyInverted}, 79 {"orInverted", "orInverted", GXorInverted}, 80 {"nand", "nand", GXnand}, 81 {"set", "set", GXset} 82}; 83 84/* The two rows in the XgcStuff structure are: 85** name of label, xgc syntax text, # of toggles, # of columns of toggles 86** (0 columns means 1 row, as many columns as necessary) 87** appropriate XgcData 88*/ 89 90XgcStuff FunctionStuff = { 91 {"Function","function",NUM_FUNCTIONS,4}, 92 FunctionData 93}; 94 95static XgcData TestData[NUM_TESTS] = { 96 {"Copy Area", "CopyArea", CopyArea}, 97 {"Copy Plane", "CopyPlane", CopyPlane}, 98 {"Points", "PolyPoint", PolyPoint}, 99 {"Lines", "PolyLine", PolyLine}, 100 {"Segments", "PolySegment", PolySegment}, 101 {"Rectangles", "PolyRectangle", PolyRectangle}, 102 {"Arcs", "PolyArc", PolyArc}, 103 {"(Filled Polygons)", "FillPolygon", FillPolygon}, 104 {"Filled Rectangles", "PolyFillRect", PolyFillRect}, 105 {"Filled Arcs", "PolyFillArc", PolyFillArc}, 106 {"Put Image", "PutImage", PutImage}, 107 {"(Get Image)", "GetImage", GetImage}, 108 {"Text 8", "PolyText8", PolyText8}, 109 {"Image Text 8", "ImageText8", ImageText8}, 110 {"Text 16", "PolyText16", PolyText16}, 111 {"Image Text 16", "ImageText16", ImageText16} 112}; 113 114XgcStuff TestStuff = { 115 {"Test","test",NUM_TESTS,2}, 116 TestData 117}; 118 119static XgcData LinestyleData[NUM_LINESTYLES] = { 120 {"Solid", "Solid", LineSolid}, 121 {"OnOffDash", "OnOffDash", LineOnOffDash}, 122 {"DoubleDash", "DoubleDash", LineDoubleDash} 123}; 124 125XgcStuff LinestyleStuff = { 126 {"LineStyle","linestyle",NUM_LINESTYLES,0}, 127 LinestyleData 128}; 129 130static XgcData CapstyleData[NUM_CAPSTYLES] = { 131 {"NotLast", "NotLast", CapNotLast}, 132 {"Butt", "Butt", CapButt}, 133 {"Round", "Round", CapRound}, 134 {"Projecting", "Projecting", CapProjecting} 135}; 136 137XgcStuff CapstyleStuff = { 138 {"CapStyle","capstyle",NUM_CAPSTYLES,2}, 139 CapstyleData 140}; 141 142static XgcData JoinstyleData[NUM_JOINSTYLES] = { 143 {"Miter", "Miter", JoinMiter}, 144 {"Round", "Round", JoinRound}, 145 {"Bevel", "Bevel", JoinBevel} 146}; 147 148XgcStuff JoinstyleStuff = { 149 {"JoinStyle","joinstyle",NUM_JOINSTYLES,0}, 150 JoinstyleData 151}; 152 153static XgcData FillstyleData[NUM_FILLSTYLES] = { 154 {"Solid", "Solid", FillSolid}, 155 {"Tiled", "Tiled", FillTiled}, 156 {"Stippled", "Stippled", FillStippled}, 157 {"OpaqueStippled", "OpaqueStippled", FillOpaqueStippled} 158}; 159 160XgcStuff FillstyleStuff = { 161 {"FillStyle","fillstyle",NUM_FILLSTYLES,2}, 162 FillstyleData 163}; 164 165static XgcData FillruleData[NUM_FILLRULES] = { 166 {"EvenOdd", "EvenOdd", EvenOddRule}, 167 {"Winding", "Winding", WindingRule} 168}; 169 170XgcStuff FillruleStuff = { 171 {"FillRule","fillrule",NUM_FILLRULES,0}, 172 FillruleData 173}; 174 175static XgcData ArcmodeData[NUM_ARCMODES] = { 176 {"Chord", "Chord", ArcChord}, 177 {"PieSlice", "PieSlice", ArcPieSlice} 178}; 179 180XgcStuff ArcmodeStuff = { 181 {"ArcMode","arcmode",NUM_ARCMODES,0}, 182 ArcmodeData 183}; 184 185/* Pointers to all the Xgcstuffs so we can run them through a loop */ 186 187static XgcStuff *Everything[8] = { 188 &FunctionStuff, 189 &LinestyleStuff, 190 &CapstyleStuff, 191 &JoinstyleStuff, 192 &FillstyleStuff, 193 &FillruleStuff, 194 &ArcmodeStuff, 195 &TestStuff 196}; 197 198#ifdef notdef 199int fildes[2]; /* for pipe */ 200FILE *outend; 201#endif 202 203XStuff X; /* GC stuff plus some global variables */ 204Boolean recording = FALSE; /* Whether we're recording into a file */ 205XtAppContext appcontext; /* To make Xt happy */ 206static Atom wm_delete_window; 207static XtActionsRec actions[] = { 208 {"quit", quitAction} 209}; 210 211static Widget bigdaddy; /* the top level widget */ 212 Widget topform; /* form surrounding the whole thing */ 213 Widget GCform; /* form in which you choose the GC */ 214static Widget Testform; /* form in which you choose the test */ 215 Widget testchoiceform; /* form inside that */ 216 ChoiceDesc *testchoicedesc; /* record of what widgets are in the 217 test choice form */ 218static Widget commandform; /* form with run, quit, clear, etc. */ 219 Widget test; /* where the test is run */ 220 Widget result; /* where the results are displayed */ 221static Widget runbutton; /* command for running */ 222static Widget clearbutton; /* command for clearing the test window */ 223 Widget recordbutton; /* start/stop recording */ 224static Widget playbackbutton; /* playback from file */ 225static Widget keyinputbutton; /* start reading from keyboard */ 226static Widget GCchoices[NUMCHOICES]; /* all the forms that contain stuff 227 for changing GC's*/ 228 ChoiceDesc *GCdescs[NUMCHOICES]; /* record of the widgets inside 229 the choice widgets */ 230 Widget planemaskchoice; /* form for choosing the plane mask */ 231 Widget dashlistchoice; /* form for choosing the dash list */ 232static Widget linewidthchoice; /* form for choosing line width */ 233 Widget linewidthtext; /* text widget within that */ 234static Widget fontchoice; /* form for choosing the font */ 235 Widget fonttext; /* text widget within that */ 236static Widget foregroundchoice; /* form for choosing foreground */ 237 Widget foregroundtext; /* text widget within that */ 238static Widget backgroundchoice; /* form for choosing background */ 239 Widget backgroundtext; /* text widget within that */ 240static Widget percentchoice; /* form for choosing percentage of test */ 241 242/* main(argc.argv) 243** --------------- 244** Initializes the toolkit, initializes data, puts up the widgets, 245** starts the event loop. 246*/ 247 248int 249main(int argc, char *argv[]) 250{ 251 static Arg shellargs[] = { 252 {XtNinput, (XtArgVal) True} 253 }; 254 255 static Arg testformargs[] = { 256 {XtNfromVert, (XtArgVal) NULL} /* put it under GCform */ 257 }; 258 259 static Arg commandformargs[] = { 260 {XtNfromVert, (XtArgVal) NULL}, /* put it under GCform */ 261 {XtNfromHoriz, (XtArgVal) NULL} /* and to the right of Testform */ 262 }; 263 264 static Arg testargs[] = { 265 {XtNheight, (XtArgVal) 400}, 266 {XtNwidth, (XtArgVal) 400}, 267 {XtNfromHoriz, (XtArgVal) NULL} /* put it to the right of GCform */ 268 }; 269 270 static Arg resultargs[] = { 271 {XtNheight, (XtArgVal) 50}, 272 {XtNwidth, (XtArgVal) 400}, 273 {XtNfromHoriz, (XtArgVal) NULL}, /* put it to the right of GCform */ 274 {XtNfromVert, (XtArgVal) NULL} /* and under test */ 275 }; 276 277 static Arg gcchoiceargs[] = { 278 {XtNfromVert, (XtArgVal) NULL}, /* put it under the one above it */ 279 {XtNfromHoriz, (XtArgVal) NULL}, /* and next to that one */ 280 {XtNborderWidth, (XtArgVal) 0} /* no ugly borders */ 281 }; 282 283 static Arg testchoiceargs[] = { 284 {XtNborderWidth, (XtArgVal) 0} 285 }; 286 287 int i; /* counter */ 288 289 /* Open the pipe */ 290 291#ifdef notdef 292 pipe(fildes); 293 outend = fdopen(fildes[0],"r"); 294#endif 295 296 /* Initialize toolkit stuff */ 297 298 XtSetLanguageProc(NULL, (XtLanguageProc) NULL, NULL); 299 300 bigdaddy = XtAppInitialize(&appcontext, "Xgc", (XrmOptionDescList) NULL, 301 (Cardinal) 0, &argc, argv, (String *) NULL, 302 shellargs, XtNumber(shellargs)); 303 X.dpy = XtDisplay(bigdaddy); 304 XtAppAddActions(appcontext, actions, XtNumber(actions)); 305 XtOverrideTranslations 306 (bigdaddy, XtParseTranslationTable("<Message>WM_PROTOCOLS: quit()")); 307 308 /* Initialize GC stuff */ 309 310 X.scr = DefaultScreenOfDisplay(X.dpy); 311 X.gc = XCreateGC(X.dpy,RootWindowOfScreen(X.scr),0,(XGCValues *) NULL); 312 X.miscgc = XCreateGC(X.dpy,RootWindowOfScreen(X.scr),0,(XGCValues *) NULL); 313 314 /* Find out what the foreground & background are, and update the GC 315 ** accordingly */ 316 317 set_foreground_and_background(); 318 319 topform = XtCreateManagedWidget("topform",formWidgetClass,bigdaddy, 320 NULL,0); 321 322 GCform = XtCreateManagedWidget("GCform",formWidgetClass,topform, 323 NULL,0); 324 325 /* create all the GCchoices forms */ 326 327 for (i=0;i<NUMCHOICES;++i) { 328 if (i==0) /* on top */ 329 gcchoiceargs[0].value = (XtArgVal) NULL; 330 else /* under the last one */ 331 gcchoiceargs[0].value = (XtArgVal) GCchoices[i-1]; 332 333 GCchoices[i] = XtCreateManagedWidget(Everything[i]->choice.text, 334 formWidgetClass,GCform, 335 gcchoiceargs,XtNumber(gcchoiceargs)); 336 337 /* now fill up that form */ 338 GCdescs[i] = create_choice(GCchoices[i],Everything[i]); 339 } 340 341 /* put the planemask choice under the bottom GC choice */ 342 gcchoiceargs[0].value = (XtArgVal) GCchoices[NUMCHOICES-1]; 343 planemaskchoice = XtCreateManagedWidget("planemask",formWidgetClass,GCform, 344 gcchoiceargs,XtNumber(gcchoiceargs)); 345 /* fill it up */ 346 create_planemask_choice(planemaskchoice); 347 348 /* put the dashlist choice under the planemask choice */ 349 gcchoiceargs[0].value = (XtArgVal) planemaskchoice; 350 dashlistchoice = XtCreateManagedWidget("dashlist",formWidgetClass,GCform, 351 gcchoiceargs,XtNumber(gcchoiceargs)); 352 /* fill it up */ 353 create_dashlist_choice(dashlistchoice); 354 355 /* put the linewidth choice under the dashlist choice */ 356 gcchoiceargs[0].value = (XtArgVal) dashlistchoice; 357 linewidthchoice = XtCreateManagedWidget("linewidth",formWidgetClass,GCform, 358 gcchoiceargs,XtNumber(gcchoiceargs)); 359 /* fill it up */ 360 linewidthtext = create_text_choice(linewidthchoice,TLineWidth,2,30); 361 362 /* put the font choice under the linewidth choice */ 363 gcchoiceargs[0].value = (XtArgVal) linewidthchoice; 364 fontchoice = XtCreateManagedWidget("font",formWidgetClass,GCform, 365 gcchoiceargs,XtNumber(gcchoiceargs)); 366 /* fill it up */ 367 fonttext = create_text_choice(fontchoice,TFont,80,300); 368 369 gcchoiceargs[0].value = (XtArgVal) fontchoice; 370 foregroundchoice = XtCreateManagedWidget("foreground",formWidgetClass,GCform, 371 gcchoiceargs,XtNumber(gcchoiceargs)); 372 foregroundtext = create_text_choice(foregroundchoice,TForeground,9,50); 373 /* FIXME 9 characters may not be the proper choice; really it 374 * should understand a more proper pixel specification... */ 375 376 gcchoiceargs[1].value = (XtArgVal) foregroundchoice; 377 backgroundchoice = XtCreateManagedWidget("background",formWidgetClass,GCform, 378 gcchoiceargs,XtNumber(gcchoiceargs)); 379 backgroundtext = create_text_choice(backgroundchoice,TBackground,9,50); 380 381 gcchoiceargs[1].value = (XtArgVal) NULL; 382 gcchoiceargs[0].value = (XtArgVal) foregroundchoice; 383 percentchoice = XtCreateManagedWidget("testpercent",formWidgetClass,GCform, 384 gcchoiceargs,XtNumber(gcchoiceargs)); 385 X.percent = 1.0; 386 create_testfrac_choice(percentchoice); 387 388 /* make all the labels inside the choices line up nicely */ 389 line_up_labels(GCdescs,(int) XtNumber(GCdescs)); 390 391 /* put the test form under the GC form */ 392 testformargs[0].value = (XtArgVal) GCform; 393 Testform = XtCreateManagedWidget("Testform",formWidgetClass,topform, 394 testformargs,XtNumber(testformargs)); 395 396 testchoiceform = XtCreateManagedWidget("testchoiceform",formWidgetClass, 397 Testform,testchoiceargs,XtNumber(testchoiceargs)); 398 testchoicedesc = create_choice(testchoiceform,Everything[CTest]); 399 400 commandformargs[0].value = (XtArgVal) GCform; 401 commandformargs[1].value = (XtArgVal) Testform; 402 commandform = XtCreateManagedWidget("commandform",formWidgetClass,topform, 403 commandformargs,XtNumber(commandformargs)); 404 405 /* Put the appropriate command buttons in the command form */ 406 407 fill_up_commandform(commandform); 408 409 testargs[2].value = (XtArgVal) GCform; /* to the right of */ 410 test = XtCreateManagedWidget("test",widgetClass,topform, 411 testargs,XtNumber(testargs)); 412 413 resultargs[2].value = (XtArgVal) GCform; /* to the right of */ 414 resultargs[3].value = (XtArgVal) test; /* under */ 415 result = XtCreateManagedWidget("result",asciiTextWidgetClass,topform, 416 resultargs,XtNumber(resultargs)); 417 418 /* Now realize all the widgets */ 419 420 XtRealizeWidget(bigdaddy); 421 422 /* Now do things we couldn't do until we had a window available */ 423 424 X.win = XtWindow(test); 425 X.tile = XCreatePixmap(X.dpy,X.win,tile_width,tile_height, 426 DefaultDepthOfScreen(X.scr)); 427 428 X.tile = XCreatePixmapFromBitmapData(X.dpy,X.win, 429 (char *)tile_bits,tile_width, 430 tile_height,Black,White, 431 DefaultDepthOfScreen(X.scr)); 432 X.stipple = XCreateBitmapFromData(X.dpy,X.win,(char *)tile_bits,tile_width, 433 tile_height); 434 435 XSetStipple(X.dpy,X.gc,X.stipple); 436 XSetStipple(X.dpy,X.miscgc,X.stipple); 437 438 GC_change_foreground(X.foreground,TRUE); 439 GC_change_background(X.background,TRUE); 440 441 wm_delete_window = XInternAtom(X.dpy, "WM_DELETE_WINDOW", False); 442 (void) XSetWMProtocols(X.dpy, XtWindow(bigdaddy), &wm_delete_window, 1); 443 444 /* Act like the user picked the first choice in each group */ 445 446 choose_defaults(GCdescs,(int)XtNumber(GCdescs)); 447 choose_defaults(&testchoicedesc,1); 448 449 /* Loop forever, dealing with events */ 450 451 XtAppMainLoop(appcontext); 452 453 return 0; 454} 455 456/* fill_up_commandform(w) 457** ---------------------- 458** Put the appropriate command buttons in the command form (w). 459*/ 460 461static void 462fill_up_commandform(Widget w) 463{ 464 static XtCallbackRec runcallbacklist[] = { 465 {(XtCallbackProc) run_test, NULL}, 466 {NULL, NULL} 467 }; 468 469 static XtCallbackRec quitcallbacklist[] = { 470 {(XtCallbackProc) quit, NULL}, 471 {NULL, NULL} 472 }; 473 474 static XtCallbackRec clearcallbacklist[] = { 475 {(XtCallbackProc) clear_test_window, NULL}, 476 {(XtCallbackProc) clear_result_window, NULL}, 477 {NULL, NULL} 478 }; 479 480 static XtCallbackRec playbackcallbacklist[] = { 481 {(XtCallbackProc) start_playback, NULL}, 482 {NULL, NULL} 483 }; 484 485 static XtCallbackRec keyinputcallbacklist[] = { 486 {(XtCallbackProc) read_from_keyboard, NULL}, 487 {NULL, NULL} 488 }; 489 490 static XtCallbackRec recordcallbacklist[] = { 491 {(XtCallbackProc) toggle_recordbutton, NULL}, 492 {NULL, NULL} 493 }; 494 495 static Arg runargs[] = { 496 {XtNcallback, (XtArgVal) NULL} 497 }; 498 499 static Arg clearargs[] = { 500 {XtNcallback, (XtArgVal) NULL}, 501 {XtNfromVert, (XtArgVal) NULL}, /* put it under runbutton */ 502 {XtNvertDistance,(XtArgVal) 10} 503 }; 504 505 static Arg recordargs[] = { 506 {XtNcallback, (XtArgVal) NULL}, 507 {XtNfromVert, (XtArgVal) NULL}, /* put it under clearbutton */ 508 {XtNvertDistance,(XtArgVal) 10}, 509 {XtNresizable, (XtArgVal) True} /* so we can change the name */ 510 }; 511 512 static Arg playbackargs[] = { 513 {XtNcallback, (XtArgVal) NULL}, 514 {XtNfromVert, (XtArgVal) NULL} /* put it under recordbutton */ 515 }; 516 517 static Arg keyinputargs[] = { 518 {XtNcallback, (XtArgVal) NULL}, 519 {XtNfromVert, (XtArgVal) NULL} /* put it under playbackbutton */ 520 }; 521 522 static Arg quitargs[] = { 523 {XtNcallback, (XtArgVal) NULL}, 524 {XtNfromVert, (XtArgVal) NULL}, /* put it under keyinputbutton */ 525 {XtNvertDistance,(XtArgVal) 10} 526 }; 527 528 runargs[0].value = (XtArgVal) runcallbacklist; 529 runbutton = XtCreateManagedWidget("Run",commandWidgetClass, 530 w,runargs,XtNumber(runargs)); 531 532 clearargs[0].value = (XtArgVal) clearcallbacklist; 533 clearargs[1].value = (XtArgVal) runbutton; /* under */ 534 clearbutton = XtCreateManagedWidget("Clear window",commandWidgetClass, 535 w,clearargs,XtNumber(clearargs)); 536 537 recordargs[0].value = (XtArgVal) recordcallbacklist; 538 recordargs[1].value = (XtArgVal) clearbutton; /* under */ 539 recordbutton = XtCreateManagedWidget("Record",commandWidgetClass, 540 w,recordargs,XtNumber(recordargs)); 541 542 playbackargs[0].value = (XtArgVal) playbackcallbacklist; 543 playbackargs[1].value = (XtArgVal) recordbutton; /* under */ 544 playbackbutton = XtCreateManagedWidget("Playback",commandWidgetClass, 545 w,playbackargs,XtNumber(playbackargs)); 546 547 keyinputargs[0].value = (XtArgVal) keyinputcallbacklist; 548 keyinputargs[1].value = (XtArgVal) playbackbutton; 549 keyinputbutton = XtCreateManagedWidget("Read Input",commandWidgetClass, 550 w,keyinputargs,XtNumber(keyinputargs)); 551 552 quitargs[0].value = (XtArgVal) quitcallbacklist; 553 quitargs[1].value = (XtArgVal) keyinputbutton; /* under */ 554 (void) XtCreateManagedWidget("Quit",commandWidgetClass, 555 w,quitargs,XtNumber(quitargs)); 556 557} 558/* quit() 559** ------ 560** Leave the program nicely. 561*/ 562 563static void 564quit(void) 565{ 566 close_file_if_recording(); 567 exit(0); 568} 569 570static void quitAction(Widget w, XEvent *e, String *p, Cardinal *n) 571{ 572 if (e->type == ClientMessage && e->xclient.data.l[0] != wm_delete_window) 573 XBell(XtDisplay(w), 0); 574 else 575 quit(); 576} 577 578/* clear_test_window() 579** ------------------- 580** Clear the test window. 581*/ 582 583static void 584clear_test_window(void) 585{ 586 XClearWindow(X.dpy,XtWindow(test)); 587} 588 589/* clear_result_window() 590** --------------------- 591** Clear the result window. 592*/ 593 594static void 595clear_result_window(void) 596{ 597 set_text(result, ""); 598} 599 600/* set_foreground_and_background() 601** ------------------------------- 602** Finds the user-specified foreground and background by querying 603** the resource manager, and sets state accordingly. Also specifies 604** the initial font for text tests. 605*/ 606 607static void 608set_foreground_and_background(void) 609{ 610 X.gcv.foreground = X.foreground = 0; 611 X.gcv.background = X.background = 0xffffffff; 612 613 X.fontname = "6x10"; 614 GC_change_font(X.fontname,FALSE); 615} 616