1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987
|
@node Part V Overview of Main Functions
@chapter Overview of Main Functions
In this chapter we give a brief overview of all the main functions
that are available. For an overview of all routines related to
specific object classes see Part III.
@ifnottex
@menu
* Version Information::
* Initialization::
* Creating Forms::
* Object Attributes::
* Doing Interaction::
* Signals::
* Idle Callbacks and Timeouts::
@end menu
@end ifnottex
@node Version Information
@section Version Information
The header file @file{forms.h} defines three symbolic constants which
you can use to conditionally compile your application. They are
@table @code
@tindex FL_VERSION
@anchor{FL_VERSION}
@item FL_VERSION
The major version number.
@tindex FL_REVISION
@anchor{FL_REVISION}
@item FL_REVISION
Revision number.
@tindex FL_INCLUDE_VERSION
@anchor{FL_INCLUDE_VERSION}
@item FL_INCLUDE_VERSION
@code{1000 * FL_VERSION + FL_REVISION}
@end table
There is also a routine that can be used to obtain the library version
at run time:
@findex fl_library_version()
@anchor{fl_library_version()}
@example
int fl_library_version(int *version, int *revision)
@end example
@noindent
The function returns a consolidated version information, computed as
@code{1000 * version + revision}. For example, for library version 1
revision 21 (1.21), the function returns a value of 1021 with
@code{version} and @code{revision} (if not @code{NULL}) set to 1 and
21, respectively.
It is always a good idea to check if the header and the run time
library are of the same version and take appropriate actions when they
are not. This is especially important for versions less than 1.
To obtain the version number of the library used in an executable, run
the command with @code{-flversion} option, which will print the
complete version information.
@node Initialization
@section Initialization
The routine
@findex fl_initialize()
@anchor{fl_initialize()}
@example
Display *fl_initialize(int *argc, char *argv[], const char *appclass,
XrmOptionDescList app_opt, int n_app_opt);
@end example
@noindent
initializes the Forms Library and returns a pointer to the
@code{Display} structure if a connection could be made, otherwise
@code{NULL}. This function must be called before any other calls
to the Forms Library (except @code{@ref{fl_set_defaults()}} and a few
other functions that alter some of the defaults of the library).
The meaning of the arguments is as follows
@table @code
@item argc, argv
Number and array of the command line arguments the application was
started with. The application name is derived from @code{argv[0]} by
stripping leading path names and trailing period and extension, if
any. Due to the way the X resources (and command line argument
parsing) work, the executable name should not contain a dot @code{.}
or a star @code{*}.
@item appclass
The application class name, which typically is the generic name for
all instances of this application. If no meaningful class name exists,
it is typically given (or converted to if non given) as the
application name with the first letter capitalized (second if the
first letter is an X).
@item app_opt
Specifies how to parse the application-specific resources.
@item n_app_opt
Number of entries in the option list.
@end table
The @code{@ref{fl_initialize()}} function builds the resource
database, calls the Xlib @code{XrmParseCommand()} function to parse
the command line arguments, and performs other per display
initialization. After the creation of the database, it is associated
with the display via @code{XrmSetDatabase()}, so the application can
get at it if necessary.
All recognized options are removed from the argument list and their
corresponding values set. Forms Library provides appropriate defaults
for all options. The following are the defaults:
@multitable @columnfractions 0.25 0.1 0.45 0.2
@item @strong{Option}
@tab @strong{Type}
@tab @strong{Meaning}
@tab @strong{Default}
@item @code{-fldebug} @i{level}
@tab int
@tab prints debug information
@tab 0
@item @code{-name} @i{appname}
@tab string
@tab changes application name
@tab none
@item @code{-flversion}
@tab
@tab prints the version of the library
@tab
@item @code{-sync}
@tab
@tab requests synchronous mode(debug)
@tab false
@item @code{-display} @i{host:dpy}
@tab string
@tab specifies remote host
@tab @code{$DISPLAY}
@item @code{-visual} @i{class}
@tab string
@tab TrueColor, PseudoColor...
@tab best
@item @code{-depth} @i{depth}
@tab int
@tab specifies prefered visual depth
@tab best
@item @code{-vid} @i{id}
@tab long
@tab specifies prefered visual ID
@tab
@item @code{-private}
@tab
@tab forces private colormap
@tab false
@item @code{-shared}
@tab
@tab forces shared colormap
@tab false
@item @code{-stdcmap}
@tab
@tab forces standard colormap
@tab false
@item @code{-double}
@tab
@tab enables double buffering
@tab false
@item -bw @i{width}
@tab int
@tab changes border width
@tab 1
@item -rgamma @i{gamma}
@tab float
@tab specifies red gamma
@tab 1.0
@item -ggamma @i{gamma}
@tab float
@tab specifies green gamma
@tab 1.0
@item -bgamma @i{gamma}
@tab float
@tab specifies blue gamma
@tab 1.0
@end multitable
In the above table "best" means the visual that has the most colors,
which may or may not be the server's default. There is a special
command option @code{-visual Default} that sets both the visual and
depth to the X servers default. If a visual ID is requested, it
overrides depth or visual if specified. The visual ID can also be
requested programmatically (before @code{@ref{fl_initialize()}} is
called) via the function
@findex fl_set_visualID()
@anchor{fl_set_visualID()}
@example
void fl_set_visualID(long id);
@end example
Note that all command line options can be abbreviated, thus if the
application program uses single character options, they might clash
with the built-ins. For example, if you use @code{-g} as a command
line option to indicate geometry, it might not work as @code{-g}
matches @code{-ggamma} in the absence of @code{-ggamma}. Thus you
should avoid using single character command line options.
If the border width is set to a negative number, all objects appear to
have a softer appearance. Some people might prefer @code{-bw -2}.
Depending on your application, XForms defaults may or may not be
appropriate. E.g., on machines capable of @w{24 bits} visuals, Forms
Library always selects the deeper @w{24 bits} visual. If your
application only uses a limited number of colors, it might
be faster if a visual other than @w{24 bits} is selected.
There are a couple of ways to override the default settings. You can
provide an application specific resource database distributed with
your program. The easiest way, however, is to set up your own program
defaults programmatically without affecting the users' ability to
override them with command line options. For this, you can use the
following routine before calling @code{@ref{fl_initialize()}}:
@findex fl_set_defaults()
@anchor{fl_set_defaults()}
@tindex FL_IOPT
@anchor{FL_IOPT}
@example
void fl_set_defaults(unsigned long mask, FL_IOPT *flopt);
@end example
@noindent
In addition to setting a preferred visual, this function can also be
used to set other program defaults, such as label font size, unit of
measure for form sizes etc.
The following table lists the fields, masks and their meanings of
@code{FL_IOPT}:
@multitable @columnfractions 0.25 0.3 0.45
@headitem Structure
@tab Mask Name
@tab Meaning
@item @code{typedef struct @{}
@tab
@tab
@item @code{int debug;}
@tab @code{FL_PDDebug}
@tab Debug level (0-5)
@item @code{int depth;}
@tab @code{FL_PDDepth}
@tab Preferred visual depth
@item @code{int vclass;}
@tab @code{FL_PDVisual}
@tab Prefered visual, @code{TrueColor} etc.
@item @code{int doubleBffer;}
@tab @code{FL_PDDouble}
@tab Simulate double buffering
@item @code{int buttonFontSize;}
@tab @code{FL_PDButtonFontSize}
@tab Default button label font size
@item @code{int menuFontSize;}
@tab @code{FL_PDMenuFontSize}
@tab Menu label font size
@item @code{int choiceFontSize;}
@tab @code{FL_PDChoiceFontSize}
@tab Choice label and choice text font size
@item @code{int browserFontSize;}
@tab @code{FL_PDBrowserFontSize}
@tab Browser label and text font size
@item @code{int inputFontSize;}
@tab @code{FL_PDInputFontSize}
@tab Input label and text font size
@item @code{int labelFontSize;}
@tab @code{FL_PDLabelFontSize}
@tab Label font size for all other objects (box, pixmap etc.)
@item @code{int pupFontSize;}
@tab @code{FL_PDPupFontSize}
@tab Font size for pop-ups
@item @code{int privateColormap;}
@tab @code{FL_PDPrivateMap}
@tab Select private colormap if appropriate
@item @code{int sharedColormap;}
@tab @code{FL_PDSharedMap}
@tab Force use of shared colormap
@item @code{int standardColormap;}
@tab @code{FL_PDStandardMap}
@tab Force use of standard colormap
@item @code{int scrollbarType;}
@tab @code{FL_PDScrollbarType}
@tab Scrollbar type to use for browser and input
@item @code{int ulThickness;}
@tab @code{FL_PDULThickness}
@tab Underline thickness
@item @code{int ulPropWidth;}
@tab @code{FL_PDULPropWidth}
@tab Underline width, 0 for const. width fonts
@item @code{int backingStore;}
@tab @code{FL_PDBS}
@tab Turn BackingStore on or off
@item @code{int coordUnit;}
@tab @code{FL_PDCoordUnit}
@tab Unit of measure: pixel, mm, point
@item @code{int borderWidth;}
@tab @code{FL_PDBorderWidth}
@tab Default border width
@item @code{@} FL IOPT;}
@tab
@tab
@end multitable
A special visual designation, @code{FL_DefaultVisual} and a command
line option equivalent, @code{-visual Default} are provided to set the
program default to the server's default visual class and depth.
If you set up your resource specifications to use class names instead
of instance names, users can then list instance resources under
an arbitrary name that is specified with the @code{-name} option.
Coordinate units can be in pixels, points (1/72 inch), mm
(millimeters), cp (centi-point, i.e., 1/100 of a point) or cmm
(centi-millimeter). The the type of unit in use can be queried or
set via the functions
@findex fl_get_coordunit()
@anchor{fl_get_coordunit()}
@findex fl_set_coordunit()
@anchor{fl_set_coordunit()}
@example
int fl_get_coordunit(void);
void fl_set_coordunit(int coordUnit);
@end example
@noindent
@code{coordUnit} can have the following values:
@tindex FL_COORD_PIXEL
@tindex FL_COORD_POINT
@tindex FL_COORD_MM
@tindex FL_COORD_centiPOINT
@tindex FL_COORD_centiMM
@code{FL_COORD_PIXEL}, @code{FL_COORD_POINT}, @code{FL_COORD_MM},
@code{FL_COORD_centiPOINT} and @code{FL_COORD_centiMM}.
The unit in use can be changed anytime, but typically you would do
this prior to creating a form, presumably to make the size of the form
screen resolution independent. The basic steps in doing this may look
something like the following:
@example
int oldcoordUnit = fl_get_coordunit();
fl_set_coordunit(FL_COORD_POINT);
fl_bgn_form(...); /* add more objects */
fl_end_form();
fl_set_coordunit(oldcoordunit);
@end example
Some of the defaults are "magic" in that their exact values depend on
the context or platform. For example, the underline thickness by
default is 1 for normal fonts and 2 for bold fonts.
There exists a convenience function to set the application default
border width
@findex fl_set_border_width()
@anchor{fl_set_border_width()}
@example
void fl_set_border_width(int border_width)
@end example
@noindent
which is equivalent to
@example
FL_IOPT fl_cntl;
fl_cntl.borderWidth = border_width;
fl_set_defaults(FL_PDBorderWidth, &fl_cntl);
@end example
Typically this function, if used, should appear before
@code{@ref{fl_initialize()}} is called so the user has the option to
override the default via resource or command line options.
To change the default scrollbar type (which is @code{THIN_SCROLLBAR})
used in browser and input object, the following convenience function
can be used:
@findex fl_set_scrollbar_type()
@anchor{fl_set_scrollbar_type()}
@example
void fl_set_scrollbar_type(int type);
@end example
where @code{type} can be one of the following
@table @code
@item FL_NORMAL_SCROLLBAR
Basic scrollbar
@item FL_THIN_SCROLLBAR
Thin scrollbar
@item FL_NICE_SCROLLBAR
Nice scrollbar
@item FL_PLAIN_SCROLLBAR
Similar to thin scrollbar, but not as fancy
@end table
Setting the scrollbar type before calling @code{@ref{fl_initialize()}}
is equivalent to
@example
FL_IOPT fl_cntl;
fl_cntl.scrollbarType = type;
fl_set_defaults(FL_PDScrollbarType, &fl_cntl);
@end example
It is recommended that this function be used before
@code{@ref{fl_initialize()}} so the user has the option to override
the default through application resources.
Prior to version 0.80, the origin of XForms' coordinate system was at
the lower-left corner of the form. The new Form Designer will convert
the form definition file to the new coordinate system, i.e., with the
origin at the upper-left hand corner, so no manual intervention is
required. To help those who lost the @code{.fd} files or otherwise
can't use a newer version of @code{fdesign}, a compatibility function
is provided
@findex fl_flip_yorigin()
@anchor{fl_flip_yorigin()}
@example
void fl_flip_yorigin(void);
@end example
@noindent
Note however that this function must be called prior to
@code{@ref{fl_initialize()}} and is a no-op after that.
For proportional font, substituting tabs with spaces is not always
appropriate because this most likely will fail to align text properly.
Instead, a tab is treated as an absolute measure of distance, in
pixels, and a tab stop will always end at multiples of this distance.
Application program can adjust this distance by setting the tab stops
using the following routine
@findex fl_set_tabstop()
@anchor{fl_set_tabstop()}
@example
void fl_set_tabstop(const char *s);
@end example
@noindent
where @code{s} is a string whose width in pixels is to be used as the
tab length. The font used to calculate the width is the same font that
is used to render the string in which the tab is embedded. The default
@code{"aaaaaaaa"}, i.e.@: eight @code{'a'}s.
Before we proceed further, some comments about double buffering are in
order. Since Xlib does not support double buffering, Forms Library
simulates this functionality with pixmap bit-bliting. In practice, the
effect is hardly distinguishable from double buffering and performance
is on par with multi-buffering extensions (It is slower than drawing
into a window directly on most workstations however). Bear in mind
that a pixmap can be resource hungry, so use this option with
discretion.
In addition to using double buffering throughout an application, it is
also possible to use double buffering on a per-form or per-object
basis by using the following routines:
@findex fl_set_form_dblbuffer()
@anchor{fl_set_form_dblbuffer()}
@findex fl_set_object_dblbuffer()
@anchor{fl_set_object_dblbuffer()}
@example
void fl_set_form_dblbuffer(FL_FORM *form, int yes);
void fl_set_object_dblbuffer(FL_OBJECT *obj, int yes);
@end example
@noindent
Currently double buffering for objects having a non-rectangular box
might not work well. A nonrectangular box means that there are regions
within the bounding box that should not be painted, which is not
easily done without complex and expensive clipping and unacceptable
inefficiency. XForms gets around this by painting these regions with
the form's backface color. In most cases, this should prove to be
adequate. If needed, you can modify the background of the pixamp by
changing @code{obj->dbl_background} after switching to double buffer.
Normally the Forms Library reports errors to @code{stderr}. This can
be avoided or modified by registering an error handling function
@findex fl_set_error_handler()
@anchor{fl_set_error_handler()}
@example
void fl_set_error_handler(void (*user_handler)(const char *where,
const char *fmt,...));
@end example
@noindent
The library will call the @code{user_handler} function with a string
indicating in which function an error occured and a formatting string
(see @code{sprintf()}) followed by zero or more arguments. To restore
the default handler, call the function again with @code{user_handler}
set to @code{NULL}. You can call this function anytime and as many
times as you wish.
You can also instruct the default message handler to log the error to
a file instead of printing to @code{stderr}
@findex fl_set_error_logfp()
@anchor{fl_set_error_logfp()}
@example
void fl_set_error_logfp(FILE *fp);
@end example
@noindent
For example
@example
fl_set_error_logfp(fopen("/dev/null","w"));
@end example
redirects all error messages to @file{/dev/null}, effectively turning
off the default error reporting to @code{stderr}.
In XForms versions older than 1.0.01 for some error messages, in
addition to being printed to stderr, a dialog box were shown that
requires actions from the user. This could be turned off and on
with the function
@findex fl_show_errors()
@anchor{fl_show_errors()}
@example
void fl_show_errors(int show);
@end example
@noindent
where @code{show} indicates whether to show (1) or not show (0) the
errors. With newer versions of the Forms Library this function has
no effect.
The fonts used in all forms can be changed using the routine
@findex fl_set_font_name()
@anchor{fl_set_font_name()}
@example
int fl_set_font_name(int n, const char *name);
@end example
@noindent
where @code{n} is a number between 0 and @code{FL_MAXFONTS -1}. The
function returns @code{0} on success, @code{1} if called before proper
initialization of the library and @code{-1} for either invalid
arguments (@code{name} isn't set or isn't a name of a font that could
be found, @code{n} negative or larger or equal to @code{FL_MAXFONTS}).
@xref{Label Attributes and Fonts}, for details. A redraw of all forms
is required to actually see the change for visible forms.
Since the dimension of an object is typically given in pixels,
depending on the server resolution and the font used, this can lead to
unsatisfactory user interfaces. For example, a button designed to
(just) contain a label in a @w{10 pt} font on a @w{75 DPI} monitor
will have the label overflow the button on a @w{100 DPI} monitor. This
comes about because a character of a @w{10 pt} font when rendered with
@code{75 DPI} resolution may have 10 pixels while the same character
in the same @w{10 pt} font with @w{100 DPI} resolution may have 14
pixels. Thus, when designing the interfaces, leave a few extra pixels
for the object. Or use a resolution independent unit, such as point,
or centi-point etc.
Using a resolution independent unit for the object size should solve
the font problems, theoretically. In practice, this approach may still
prove to be vulnerable. The reason is the discreteness of both the
font resolution and the monitor/server resolutions. The standard X
fonts only come in two discrete resolutions, @w{75 DPI} and @w{100
DPI}. Due to the variations in monitor resolutions, the theoretically
identical sized font, say a @w{10 pt} font, can vary in sizes (pixels)
by up to 30%, depending on the server (rendering a font on a @w{80
DPI} monitor will cause errors in sizes regardless if a @w{75 DPI} or
@w{100 DPI} font is used.) This has not even taken into account the
fact that a surprising number of systems have wrong font paths (e.g.,
a @w{90 DPI} monitor using @w{75 DPI} fonts etc.).
With the theoretical and practical problems associated with X fonts,
it is not practical for XForms to hard-code default font resolution
and it is not practical to use the resolution information obtained
from the server either as information obtained from the server
regarding monitor resolution is highly unreliable. Thus, XForms does
not insist on using fonts with specific resolutions and instead it
leaves the freedom to select the default fonts of appropriate
resolutions to the system administrators.
Given all these uncertainties regarding fonts, as a workaround, XForms
provides a function that can be used to adjust the object size
dynamically according to the actual fonts loaded:
@findex fl_adjust_form_size()
@anchor{fl_adjust_form_size()}
@example
double fl_adjust_form_size(FL_FORM *form);
@end example
This function works by computing the size (in pixels) of every object
on the form that has an inside label and compares it to the size of
the object. Scaling factors are computed if any object labels don't
fit. The maximum scaling factor found is then used to scale the form
so every object label fits inside the object. It will never shrink a
form. The function returns the resulting scaling factor. In scaling
the form the aspect ratio of the form is left unmodified and all
object gravity specifications are ignored. Since this function is
meant to compensate for font size and server display resolution
variations, scaling is limited to 125% per invocation. The best place
to use this function is right after the creation of the forms. If the
forms are properly designed, this function should be a no-op on the
machine the forms were designed on. Form Designer has a special option
@code{-compensate} and resource @code{compensate} to request the
emission of this function automatically for every form created. It is
likely that this will become the default once the usefulness of it is
established.
There is a similar function that works the same way, but on an
object-by-object basis and further allows explicit margin
specifications:
@findex fl_fit_object_label()
@anchor{fl_fit_object_label()}
@example
void fl_fit_object_label(FL_OBJECT *obj, FL_Coord hm, FL_Coord vm);
@end example
@noindent
where @code{hm} and @code{vm} are the horizontal and vertical margins
to leave on each side of the object, respectively. This function works
by computing the object labels size and comparing it to the object
size. If the label does not fit inside the object with the given
margin, the entire form the object is on is scaled so the object label
fits. In scaling the form, all gravity specification is ignored but
the aspect ratio of the form (and thus of all objects) is kept. This
function will not shrink a form. You can use this function on as many
objects as you choose. Of course the object has to have a label inside
the object for this function to work.
All colors with indices smaller than @code{FL_FREE_COL1} are used (or
can potentially be used) by the Forms Library. If you wish they can be
changed using the function prior to @code{@ref{fl_initialize()}}:
@findex fl_set_icm_color()
@anchor{fl_set_icm_color()}
@example
void fl_set_icm_color(FL_COLOR index, int r, int g, int b);
@end example
@noindent
Using this function you can actually change all entries in the
internal colormap (with @code{index} going up to
@code{FL_MAX_COLORS-1}). You may also inspect the internal colormap
using
@findex fl_get_icm_color()
@anchor{fl_get_icm_color()}
@example
void fl_get_icm_color(FL_COLOR index, int *r, int *g, int *b);
@end example
In some situations Forms Library may modify some of the server
defaults. All modified defaults are restored as early as possible by
the main loop and in general, when the application exits, all server
defaults are restored. The only exception is when exiting from a
callback that is activated by shortcuts. Thus it is recommended that
the cleanup routine @code{@ref{fl_finish()}} is called prior to
exiting an application or register it via @code{atexit()}.
@findex fl_finish()
@anchor{fl_finish()}
@example
void fl_finish(void);
@end example
In addition to restoring all server defaults, @code{@ref{fl_finish()}}
also shuts down the connection and frees dynamically allocated memory.
@node Creating Forms
@section Creating Forms
To start the definition of a form call
@findex fl_bgn_form()
@anchor{fl_bgn_form()}
@example
FL_FORM *fl_bgn_form(int type, FL_Coord w, FL_Coord h);
@end example
@noindent
@code{type} is the type of the box that is used as a background.
@code{w} and @code{h} give the width and height of the new form. The
function returns a pointer to the form created.
Once all objects required have been added to a form call
@findex fl_end_form();
@anchor{fl_end_form()}
@example
void fl_end_form(void);
@end example
Between these two calls objects and groups of objects are added to the
form. To start a new group of objects use
@findex fl_bgn_group()
@anchor{fl_bgn_group()}
@example
FL_OBJECT *fl_bgn_group(void);
@end example
@noindent
The function returns a pointer to the group (actually to an invisible
object of class
@tindex FL_BEGIN_GROUP
@code{FL_BEGIN_GROUP}). Groups can't be nested.
When all objects that are supposed to belong to the group are added
call
@tindex FL_END_GROUP
@findex fl_end_group()
@anchor{fl_end_group()}
@example
void fl_end_group(void);
@end example
@noindent
Also this function creates an (invisible) object, belonging to class
@code{FL_END_GROUP}, but since it can't be used its address isn ot
returned.
Groups are useful for two reasons. First of all, it is possible to
hide or deactivate groups of objects with a single function call. This
is often very handy to dynamically change the appearance of a form
depending on the context or selected options. In addition it can also
be used as a shortcut to set some particular attributes of several
objects. It is not uncommon that you want several objects to maintain
their relative positioning upon form resizing. This requires to set
the gravity for each object. If these objects are placed inside a
group, setting the gravity attributes of the group will suffice.
The second reason for use of groups is radio buttons. Radio buttons
are considered related only if they belong to the same group. Using
groups is the only way to place unrelated groups of radio buttons on a
single form without interference from each other.
Both forms and groups that have been ended by
@code{@ref{fl_end_form()}} or @code{@ref{fl_end_group()}} can be
"reopened" by using
@findex fl_addto_form()
@anchor{fl_addto_form()}
@findex fl_addto_group()
@anchor{fl_addto_group()}
@example
FL_FORM *fl_addto_form(FL_FORM *form)
FL_OBJECT *fl_addto_group(FL_OBJECT *group);
@end example
@noindent
Both functions return their argument on success and @code{NULL} on
failure (e.g. because a different group or form is still open).
On success further objects can be appended to the form or group.
To remove an object from a form use
@findex fl_delete_object()
@anchor{fl_delete_object()}
@example
void fl_delete_object(FL_OBJECT *obj);
@end example
@noindent
This does not yet destroy the object, it just breaks its connection to
the form it did belong to, so it can still be referenced.
To finally destroy an object use
@findex fl_free_object()
@anchor{fl_free_object()}
@example
void fl_free_object(FL_OBJECT *obj);
@end example
@noindent
If @code{@ref{fl_delete_object()}} hadn't been called for the object
this will happen now. The object receives a final event of type
@code{FL_FREEMEM} to allow it to free memory it did allocate and do
whatever other clean-up required. Finally all memory allocated for the
object is freed. After being freed an object should not be referenced.
A form as a whole, together with all the objects it contains can be
deleted by calling
@findex fl_free_form()
@anchor{fl_free_form()}
@example
void fl_free_form(FL_FORM *form);
@end example
@noindent
This will first hide the form (emitting warning if this is necessary),
then free all of its objects and finally release memory allocated for
the form.
@node Object Attributes
@section Object Attributes
A number of general routines are available for setting and querying
attributes. Unless stated otherwise, all attributes altering routines
affect the appearance or geometry of the object immediately if the
object is visible.
Since the object class and type of an object can't be changed anymore
once an object has been created there are only functions for querying
these attributes:
@findex fl_get_object_objclass()
@anchor{fl_get_object_objclass()}
@findex fl_get_object_type()
@anchor{fl_get_object_type()}
@example
int fl_get_object_objclass(FL_OBJECT *obj);
int fl_get_object_type(FL_OBJECT *obj);
@end example
@noindent
Receiving a negative value indicates that a @code{NULL} pointer
was passed to the functions.
To set the two colors that influence the appearance of the object use
@findex fl_set_object_color()
@anchor{fl_set_object_color()}
@example
void fl_set_object_color(FL_OBJECT *obj, FL_COLOR col1, FL_COLOR col2);
@end example
@noindent
and to find out about the colors of an object use
@findex fl_get_object_color()
@anchor{fl_get_object_color()}
@example
void fl_get_object_color(FL_OBJECT *obj,
FL_COLOR *col1, FL_COLOR *col2);
@end example
@findex fl_set_object_boxtype()
@anchor{fl_set_object_boxtype()}
@example
void fl_set_object_boxtype(FL_OBJECT *obj, int boxtype);
@end example
@noindent
Changes the shape of the box of the object. Please note that not all
possible boxtypes are suitable for all types of objects, see the
documentation for the different objects for limitations.
To find out the current boxtype of an object use
@findex fl_get_object_boxtype()
@anchor{fl_get_object_boxtype()}
@example
int fl_get_object_boxtype(FL_OBJECT *obj);
@end example
@noindent
Receiving a negative value indicates that a @code{NULL} pointer
was passed to the function.
There are also functions to change or query the border width of an object:
@findex fl_set_object_bw()
@anchor{fl_set_object_bw()}
@findex fl_get_object_bw()
@anchor{fl_get_object_bw()}
@example
void fl_set_object_bw(FL_OBJECT *obj, int bw);
void fl_get_object_bw(FL_OBJECT *obj, int *bw);
@end example
@noindent
If the requested border width is 0, -1 is used.
To change or inquire the objects position (relative to the form it
belongs to) the functions
@findex fl_set_object_position()
@anchor{fl_set_object_position()}
@findex fl_get_object_position()
@anchor{fl_get_object_position()}
@example
void fl_set_object_position(FL_OBJECT *obj, FL_Coord x, FL_Coord y);
void fl_get_object_position(FL_OBJECT *obj, FL_Coord *x, FL_Coord *y);
@end example
@noindent
exist. If the object is visible it's redrawn at the new position.
To change or inquire the size of an object use
@findex fl_set_object_size()
@anchor{fl_set_object_size()}
@findex fl_get_object_size()
@anchor{fl_get_object_size()}
@example
void fl_set_object_size(FL_OBJECT *obj, FL_Coord w, FL_Coord h);
void fl_get_object_size(FL_OBJECT *obj, FL_Coord *w, FL_Coord *h);
@end example
@noindent
When changing th size the position of the upper left hand corner of
the object remains unchanged.
To set or query both the position and size of an object the
functions
@findex fl_set_object_geometry()
@anchor{fl_set_object_geometry()}
@findex fl_get_object_geometry()
@anchor{fl_get_object_geometry()}
@example
void fl_set_object_geometry(FL_OBJECT *obj, FL_Coord x, FL_Coord y,
FL_Coord w, FL_Coord h);
void fl_get_object_geometry(FL_OBJECT *obj, FL_Coord *x, FL_Coord *y,
FL_Coord (*w, FL_Coord *h);
@end example
@noindent
can be used.
Please note: always use one of the above functions to change the
position and/or size of an object and don't try to change the
information stored in the object directly. There's some double
bookkeeping going on under the hood that makes sure that the objects
position and size won't change due to rounding errors when the
whole form gets resized and changing the internal information kept in
the objects structure would interfer with this.
There's a second function for calculation an objects geometry:
@findex fl_get_object_bbox()
@anchor{fl_get_object_bbox()}
@example
void fl_get_object_bbox(FL_OBJECT *obj, FL_Coord *x, FL_Coord *y,
FL_Coord *w, FL_Coord *h);
@end example
@noindent
The difference between this functions and
@code{@ref{fl_get_object_geometry()}} is that
@code{@ref{fl_get_object_bbox()}} returns the bounding box size that
has the label, which could be drawn outside of the object figured in.
Some objects in the library are composite objects that consist of
other objects. For example, the scrollbar object is made of a slider
and two scroll buttons. To get a handle to one of the components of
the composite object, the following routine is available:
@findex fl_get_object_component()
@anchor{fl_get_object_component()}
@example
FL_OBJECT *fl_get_object_component(FL_OBJECT *obj, int objclass,
int type, int number);
@end example
@noindent
where @code{obj} is the composite object, @code{objclass} and
@code{type} are the component object's class ID and type; and
@code{number} is the sequence number of the desired object in case the
composite has more than one object of the same class and type. You can
use a constant -1 for @code{type} to indicate any type of class
@code{objclass}. The function returns the object handle if the
requested object is found, otherwise @code{NULL}. For example to
obtain the object handle to the horizontal scrollbar in a browser,
code similiar to the following can be used
@example
hscrollbar = fl_get_object_component(browser, FL_SCROLLBAR,
FL_HOR_THIN_SCROLLBAR, 0)
@end example
To influence change the color, font size, font style, alignment and
text of the label of an object use
@findex fl_set_object_lcol()
@anchor{fl_set_object_lcol()}
@findex fl_set_object_lsize()
@anchor{fl_set_object_lsize()}
@findex fl_set_object_lstyle()
@anchor{fl_set_object_lstyle()}
@findex fl_set_object_lalign()
@anchor{fl_set_object_lalign()}
@findex fl_set_object_label()
@anchor{fl_set_object_label()}
@example
void fl_set_object_lcol(FL_OBJECT *obj, FL_COLOR lcol);
void fl_set_object_lsize(FL_OBJECT *obj, int lsize);
void fl_set_object_lstyle(FL_OBJECT *obj, int lstyle);
void fl_set_object_lalign(FL_OBJECT *obj, int align);
void fl_set_object_label(FL_OBJECT *obj, const char *label);
@end example
To find out about the object labels color, font size, style, alignment
and the string itself use
@findex fl_get_object_lcol()
@anchor{fl_get_object_lcol()}
@findex fl_get_object_lsize()
@anchor{fl_get_object_lsize()}
@findex fl_get_object_lstyle()
@anchor{fl_get_object_lstyle()}
@findex fl_get_object_lalign()
@anchor{fl_get_object_lalign()}
@findex fl_get_object_label()
@anchor{fl_get_object_label()}
@example
FL_COLOR fl_get_object_lcol(FL_OBJECT *obj);
int fl_get_object_lsize(FL_OBJECT *obj);
int fl_get_object_lstyle(FL_OBJECT *obj);
int fl_get_object_lalign(FL_OBJECT *obj);
const char * fl_get_object_label(FL_OBJECT *obj);
@end example
To set a tool-tip text for an object use the following routine
@findex fl_set_object_helper()
@anchor{fl_set_object_helper()}
@example
void fl_set_object_helper(FL_OBJECT *obj, const char *helpmsg);
@end example
@noindent
where @code{helpmsg} is a text string (with possible embedded newlines
in it) that will be shown when the mouse hovers over the object for
nore than about @w{600 msec}. A copy of the string is made internally.
The boxtype, color and font for the tool-tip message displayed can be
customized further using the following routines:
@findex fl_set_tooltip_boxtype()
@anchor{fl_set_tooltip_boxtype()}
@findex fl_set_tooltip_color()
@anchor{fl_set_tooltip_color()}
@findex fl_set_tooltip_font()
@anchor{fl_set_tooltip_font()}
@example
void fl_set_tooltip_boxtype(int boxtype);
void fl_set_tooltip_color(FL_COLOR textcolor, FL_COLOR background);
void fl_set_tooltip_font(int style, int size);
@end example
@noindent
where @code{boxtype} is the backface of the form that displays the
text. The default is @code{FL_BORDER_BOX}. @code{textcolor} and
@code{background} specify the color of the text and the color of the
backface. The defaults for these are @code{FL_BLACK} and
@code{FL_YELLOW}. @code{style} and @code{size} are the font style and
size of the text.
There are four function for controlling how an object reacts to
resizing the form it belongs to or to find out what its current
settings are:
@findex fl_set_object_resize()
@anchor{fl_set_object_resize()}
@findex fl_get_object_resize()
@anchor{fl_get_object_resize()}
@findex fl_set_object_gravity()
@anchor{fl_set_object_gravity()}
@findex fl_get_object_gravity()
@anchor{fl_get_object_gravity()}
@example
void fl_set_object_resize(FL_OBJECT *obj, unsigned int howresize);
void fl_get_object_resize(FL_OBJECT *obj, unsigned int *howresize);
void fl_set_object_gravity(FL_OBJECT *obj, unsigned int NWgravity,
unsigned int SEgravity);
void fl_get_object_gravity(FL_OBJECT *obj, unsigned int *NWgravity,
unsigned int *SEgravity);
@end example
@noindent
@xref{Part I Doing Interaction, , Doing Interaction}, for more details
on the resizing behaviour of objects.
If you change many attributes of a single object or many objects in a
visible form, the changed object is redrawn after each change. To
avoid this, put the changes between calls of the two functions
@findex fl_freeze_form()
@anchor{fl_freeze_form()}
@findex fl_unfreeze_form()
@anchor{fl_unfreeze_form()}
@example
void fl_freeze_form(FL_FORM *form);
void fl_unfreeze_form(FL_FORM *form);
@end example
There are also routines that influence the way events are dispatched.
These routines are provided mainly to facilitate the development of
(unusual) new objects where attributes need to be changed on the fly.
These routines should not be used on the built-in ones.
To enable or disable an object to receive the @code{FL_STEP} event,
use the following routine
@findex fl_set_object_automatic()
@anchor{fl_set_object_automatic()}
@example
void fl_set_object_automatic(FL_OBJECT *obj, int yes);
@end example
To determine if an object receives @code{FL_STEP} events use
@findex fl_object_is_automatic()
@anchor{fl_object_is_automatic()}
@example
int fl_object_is_automatic(FL_OBJECT *obj);
@end example
To enable or disable an object to receive the FL_DBLCLICK event use
the following routine
@findex fl_set_object_dblclick()
@anchor{fl_set_object_dblclick()}
@example
void fl_set_object_dblclick(FL_OBJECT *obj, unsigned long timeout);
@end example
@noindent
where @code{timeout} specifies the maximum time interval (in msec)
between two clicks for them to be considered a double-click (using 0
disables double-click detection). To determine the current setting
of the timeout use
@findex fl_get_object_dblclick()
@anchor{fl_get_object_dblclick()}
@example
unsigned fl_get_object_dblclick(FL_OBJECT *obj);
@end example
To make an object or a group invisible or visible use the following
two functions
@findex fl_hide_object()
@anchor{fl_hide_object()}
@findex fl_show_object()
@anchor{fl_show_object()}
@example
void fl_hide_object(FL_OBJECT *obj);
void fl_show_object(FL_OBJECT *obj);
@end example
@noindent
@code{obj} can be the pseudo-object returned by
@code{@ref{fl_bgn_group()}} and then allows to hide or show whole
groups of objects.
To determine if an object is visible (given that the form it belongs
to is also visible) use
@findex fl_object_is_visible()
@anchor{fl_object_is_visible()}
@example
int fl_object_is_visible(FL_OBJECT *obj);
@end example
@findex fl_trigger_object()
@anchor{fl_trigger_object()}
@example
void fl_trigger_object(FL_OBJECT *obj);
@end example
@noindent
returns @code{obj} to the application program after calling its
callback if one exists.
@findex fl_set_focus_object()
@anchor{fl_set_focus_object()}
@example
void fl_set_focus_object(FL_FORM *form, FL_OBJECT *obj);
@end example
@noindent
sets the input focus in form @code{form} to object @code{obj}. Note
however, if this routine is used as a response to an @code{FL_UNFOCUS}
event, i.e., as an attempt to override the focus assignment by the
main loop from within an objects event handler, this routine will not
work as the main loop assigns a new focus object upon return from the
object event handler, which undoes the focus change inside the event
handler. To override the @code{FL_UNFOCUS} event the following routine
should be used:
@findex fl_reset_focus_object()
@anchor{fl_reset_focus_object()}
@example
void fl_reset_focus_object(FL_OBJECT *obj);
@end example
Use the following routine to obtain the object that has the focus on a
form
@findex fl_get_focus_object()
@anchor{fl_get_focus_object()}
@example
FL_OBJECT *fl_get_focus_object(FL_FORM *form);
@end example
The routine
@findex fl_set_object_callback()
@anchor{fl_set_object_callback()}
@example
void fl_set_object_callback(FL_OBJECT *obj,
void (*callback)(FL_OBJECT *, long),
long argument);
@end example
@noindent
binds a callback routine to an object.
To invoke the callback manually (as opposed to invocation by the main
loop), use the following function
@findex fl_call_object_callback()
@anchor{fl_call_object_callback()}
@example
void fl_call_object_callback(FL_OBJECT *obj);
@end example
@noindent
If the object @code{obj} does not have a callback associated with it,
this call has not effect.
@findex fl_set_form_callback()
@anchor{fl_set_form_callback()}
@example
void fl_set_form_callback(FL_FORM *form,
void (*callback)(FL_OBJECT *, void *),
void *data);
@end example
@noindent
binds a callback routine to an entire form.
It is sometimes useful to obtain the last event from within a callback
function, e.g., to implement different functionalities depending on
which button triggers the callback. For this, the following routine
can be used from within a callback function.
@findex fl_last_event()
@anchor{fl_last_event()}
@example
const XEvent *fl_last_event(void);
@end example
@noindent
Sometimes, it may be desirable to obtain hardcopies of some objects
in a what-you-see-is-what-you-get (WYSISYG) way, especially those that
are dynamic and of vector-graphics in nature. To this end, the
following routine exists:
@findex fl_object_ps_dump()
@anchor{fl_object_ps_dump()}
@example
int fl_object_ps_dump(FL_OBJECT *obj, const char *fname);
@end example
@noindent
The function will output the specified object in PostScript. If
@code{fname} is @code{NULL}, a fselector will be shown to ask the user
for a file name. The function returns a negative number if no output
is generated due to errors. At the moment, only the @code{FL_XYPLOT}
object is supported.
The object must be visible at the time of the function call. The
hardcopy should mostly be WYSIWYG and centered on the printed page.
The orientation is determined such that a balanced margin results,
i.e., if the width of the object is larger than the height, landscape
mode will be used. Further, if the object is too big to fit on the
printed page, a scale factor will be applied so the object fits. The
box underneath the object is by default not drawn and in the default
black&white mode, all curves are drawn in black. See demo program
@file{xyplotover.c} for an example output.
It is possible to customize the output by changing the PostScript
output control parameters via the function
@findex flps_init()
@anchor{flps_init()}
@tindex FLPS_CONTROL
@example
FLPS_CONTROL *flps_init(void);
@end example
@noindent
A typical use is to call this routine to obtain a handle to the
PostScript output control structure and change the control structure
members to suit your needs before calling
@code{@ref{fl_object_ps_dump()}}. You should not free the returned
buffer.
The control structure has the following members
@table @code
@item int ps_color
The choices are full color (@code{FLPS_COLOR}), grayscale
(@code{FLPS_GRAYSCALE}) and black&white (@code{FLPS_BW}). The default
for xyplot is black and white. In this mode, all drawings are black,
on a white background. If @code{drawbox} (see below) is true, the
drawing color can be either white or black depending on the specified
color.
@item int orientation
Valid choices are @code{FLPS_AUTO}, @code{FLPS_PORTRAIT} and
@code{FLPS_LANDSCAPE}. The default is @code{FLPS_AUTO}.
@item auto_fit
By default, this is true so the object always fits the printed page.
Set it to false (0) to turn off auto-scaling.
@item int eps
Set this to 1 if output in EPS format is required.
@item int drawbox
Set this to 1 if the box of the object is to be drawn.
@item float xdpi, ydpi
These two are the screen resolution. The default is to use the actual
resolution of the display. Note by setting a dpi number smaller or
larger than the actual resolution, the output object is in effect
being enlarged or shrunken.
@item float paper_w
The paper width in inches. The default is @w{8.5 in}.
@item float paper_h
The paper height in inches. The default is @w{11 in}.
@end table
To generate a PostScript output of a form or forms, use the
@code{fd2ps} program documented in @ref{Part II Generating Hardcopies}.
@node Doing Interaction
@section Doing Interaction
To display the form @code{form} on the screen use
@findex fl_show_form()
@anchor{fl_show_form()}
@example
Window fl_show_form(FL_FORM *form, int place, int border,
const char *title);
@end example
@noindent
@code{place} controls the position and size of the form. @code{border}
indicates whether a border (window manager's decoration) should be
drawn around the form. If a border is to be drawn @code{title} is the
name of the window (and its associated icon). The routine returns the
window identifier of the form. For resource and identification
purposes, the form name is taken to be the title with spaces removed
and the first character lower-cased. E.g., if a form has a title
@w{@code{"Foo Bar}} the forms name is derived as @code{"fooBar"}.
For the the location and size of the window controlled by @code{place}
the following possibilities exist:
@table @code
@tindex FL_PLACE_SIZE
@item FL_PLACE_SIZE
The user can control the position but the size is fixed. Interactive
resizing is not allowed once the form becomes visible.
@tindex FL_PLACE_POSITION
@item FL_PLACE_POSITION
Initial position used will be the one set via
@code{@ref{fl_set_form_position()}}. Interactive resizing is allowed.
@tindex FL_PLACE GEOMETRY
@item FL_PLACE GEOMETRY
Place at the latest position and size (see also below) or the geometry
set via @code{@ref{fl_set_form_geometry()}} etc. A form so shown will
have a fixed size and interactive resizing is not allowed.
@tindex FL_PLACE_ASPECT
@item FL_PLACE_ASPECT
Allows interactive resizing but any new size will have the aspect ratio
as that of the initial size.
@tindex FL_PLACE_MOUSE
@item FL_PLACE_MOUSE
The form is placed centered below the mouse. Interactive resizing will
not be allowed unless this option is accompanied by
@code{@ref{FL_FREE_SIZE}} as in
@code{@ref{FL_PLACE_MOUSE}|@ref{FL_FREE_SIZE}}.
@tindex FL_PLACE_CENTER
@item FL_PLACE_CENTER
The form is placed in the center of the screen. If
@code{@ref{FL_FREE_SIZE}} is also specified, interactive resizing will
be allowed.
@tindex FL_PLACE_FULLSCREEN
@item FL_PLACE_FULLSCREEN
The form is scaled to cover the full screen. If
@code{@ref{FL_FREE_SIZE}} is also specified, interative resizing will
be allowed.
@tindex FL_PLACE_FREE
@item FL_PLACE_FREE
Both the position and size are completely free. The initial size used
is the designed size. Initial position, if set via
@code{@ref{fl_set_form_position()}}, will be used, otherwise
interactive positioning may be possible if the window manager allows
it.
@tindex FL_PLACE_HOTSPOT
@item FL_PLACE_HOTSPOT
The form is so placed that mouse is on the "hotspot". If
@code{@ref{FL_FREE_SIZE}} is also specified, interactive resizing will
be allowed.
@tindex FL_PLACE_CENTERFREE
@item FL_PLACE_CENTERFREE
Same as @code{@ref{FL_PLACE_CENTER}|@ref{FL_FREE_SIZE}}, i.e., place
the form at the center of the screen and allow resizing.
@tindex FL_PLACE ICONIC
@item FL_PLACE ICONIC
The form is shown initially iconified. The size and location used are
the window manager's default.
@end table
If no size is specified, the designed (or later scaled) size will be
used. Note that the initial position is dependent upon the window
manager used. Some window managers will allow interactive placement of
the windows and some will not.
There are three values that can be passed for @code{border}:
@table @code
@tindex FL_FULLBORDER
@item FL_FULLBORDER
Draw full border with title
@tindex FL_TRANSIENT
@item FL_TRANSIENT
Draw borders with possibly less decoration (depends on the window
managers behaviour)
@tindex FL_NOBORDER
@item FL_NOBORDER
Draw no border at all
@end table
Since multiple forms can be displayed at the same time note that using
@code{FL_NOBORDER} might have adverse effect on keyboard focus and is
not very friendly to other applications (it is close to impossible to
move a form that has no border). Thus use this feature with
discretion. The only situation where @code{FL_NOBORDER} is appropriate
is for automated demonstration suites or when the application program
must obtain an input or a mouse click from the user, and even then all
other forms should be deactivated while a borderless form is active.
For almost all situations where the application must demand an action
from the user @code{FL_TRANSIENT} is preferable. Also note that you
can't iconify a form that has no borders and under most window
managers forms displayed with @code{FL_TRANSIENT} can't be iconified
either.
One additional property (under almost all window managers) of a
transient window is that it will stay on top of the main form, which
the application program can designate using
@findex fl_set_app_mainform()
@anchor{fl_set_app_mainform()}
@example
void fl_set_app_mainform(FL_FORM *form);
@end example
@noindent
By default, the main form is set automatically by the library to the
first full-bordered form shown.
To obtain the current main form, use the following routine
@findex fl_get_app_mainform()
@anchor{fl_get_app_mainform()}
@example
FL_FORM *fl_get_app_mainform(void);
@end example
In some situations, either because the concept of an application main
form does not apply (for example, an application might have multiple
full-bordered windows), or under some (buggy) window managers, the
designation of a main form may cause stacking order problems. To
workaround these, the following routine can be used to disable the
designation of a main form (must be called before any full-bordered
form is shown):
@findex fl_set_app_nomainform()
@anchor{fl_set_app_nomainform()}
@example
void fl_set_app_nomainform(int yes);
@end example
@noindent
with a true flag.
All visible forms will have the properties @code{WM_CLASS},
@code{WM_CLIENT_MACHINE} and @code{WM_NAME} set. In addition, the
first full-bordered form will have the @code{WM_COMMAND} property set
and is by default the applications main form.
Sometimes it is necessary to have access to the window resource ID
before the window is mapped (shown). For this, the following routine
can be used
@findex fl_prepare_form_window()
@anchor{fl_prepare_form_window()}
@example
Window fl_prepare_form_window(FL_FORM *form, int place, int border,
const char *name);
@end example
@noindent
This routine creates a window that obeys any and all constraints just
as @code{@ref{fl_show_form()}} does but remains unmapped. To map such
a window, the following must be used
@findex fl_show_form_window()
@anchor{fl_show_form_window()}
@example
Window fl_show_form_window(FL_FORM *form);
@end example
@noindent
Between these two calls, the application program has full access to
the window and can set all attributes, such as icon pixmaps etc., that
are not set by @code{@ref{fl_show_form()}}.
The application program can raise a form to the top of the screen so
no other forms obscures it by calling
@findex fl_raise_form()
@anchor{fl_raise_form()}
@example
void fl_raise_form(FL_FORM *form);
@end example
To instead lower a form to the bottom of the stack use
@findex fl_lower_form()
@anchor{fl_lower_form()}
@example
void fl_lower_form(FL_FORM *form);
@end example
When placing a form on the screen using @code{FL_PLACE_GEOMETRY} for
the @code{place} argument to @code{@ref{fl_show_form()}} the position
and size can be set before by using the routines
@findex fl_set_form_position()
@anchor{fl_set_form_position()}
@findex fl_set_form_size()
@anchor{fl_set_form_size()}
@findex fl_set_form_geometry()
@anchor{fl_set_form_geometry()}
@findex fl_scale_form()
@anchor{fl_scale_form()}
@example
void fl_set_form_position(FL_FORM *form, FL_Coord x, FL_Coord y);
void fl_set_form_size(FL_FORM *form, FL_Coord w, FL_Coord h);
void fl_set_form_geometry(FL_FORM form*, FL_Coord x, FL_Coord y,
FL_Coord w, FL_Coord h);
void fl_scale_form(FL_FORM *form, double xsc, double ysc);
@end example
@noindent
where @code{@ref{fl_set_form_geometry()}} combines the functionality
of @code{@ref{fl_set_form_position()}} and
@code{@ref{fl_set_form_size()}} and the last routine,
@code{@ref{fl_scale_form()}}, scales the form in horizontal and
vertical direction by the factors passed to the function. These
routines can also be used when the form is visible.
Sometimes it is desirable to know how large the decoration are the
window manager puts around a forms window. They can be obtained by a
call of
@findex fl_get_decoration_sizes()
@anchor{fl_get_decoration_sizes()}
@example
void fl_get_decoration_sizes(FL_FORM *form, int *top, int *right,
int *bottom, int *left);
@end example
@noindent
This is especially useful if it is necessary to open a window at some
previously stored position since in that case one needs the position
of of the window, which deviates from the position reported for the
form by the window manager's decorations. Obviously, the above
function can't be used for forms that are embedded into another form.
The function
@findex fl_form_is_isconified()
@anchor{fl_form_is_isconified()}
@example
int fl_form_is_isconified(FL_FORM *form);
@end example
@noindent
allows to test if the (visible) window of a form is in iconified
state.
If interactive resizing is allowed (e.g., by showing the form with
@code{@ref{FL_PLACE_POSITION}}) it can be useful to limit the range of
the size of a form can take. To this end, the following functions are
available
@findex fl_set_form_minsize()
@anchor{fl_set_form_minsize()}
@findex fl_set_form_maxsize()
@anchor{fl_set_form_maxsize()}
@example
void fl_set_form_minsize(FL_FORM *form, FL_Coord minw, FL_Coord minh);
void fl_set_form_maxsize(FL_FORM *form, FL_Coord maxw, FL_Coord maxh);
@end example
Although these two routines can be used before or after a form becomes
visible, not all window managers honor such requests once the window
is visible. Also note that the constraints only apply to the next call
of @code{@ref{fl_show_form()}} for the form.
To set or change the icon shown when a form is iconified use the
following routine
@findex fl_set_form_icon()
@anchor{fl_set_form_icon()}
@example
void fl_set_form_icon(FL_FORM *form, Pixmap icon, Pixmap mask);
@end example
@noindent
where @code{icon} can be any valid pixmap ID. (@xref{Pixmap Object},
for some of the routines that can be used to create pixmaps.) Note
that a previously set icon if not freed or modified in anyway.
If, for any reason, you would like to change the form title after the
form has been made visible, the following call can be used (this will
also change the icon title)
@findex fl_set_form_title()
@anchor{fl_set_form_title()}
@example
void fl_set_form_title(FL_FORM *form, const char *name);
@end example
The routine
@findex fl_hide_form()
@anchor{fl_hide_form()}
@example
void fl_hide_form(FL_FORM *form);
@end example
@noindent
hides the particular form, i.e., closes its window and all subwindows.
To check if a form is visible or not, the following function can be used
@findex fl_form_is_visible()
@anchor{fl_form_is_visible()}
@example
int fl_form_is_visible(FL_FORM *form)'
@end example
@noindent
The function can return that the form is visible
(@code{@ref{FL_VISIBLE}}), is invisible (@code{@code{FL_INSIBILE}}) or
in the processing of becoming invisible
(@code{@ref{FL_BEING_HIDDEN}}).
The most important function for doing the actual interaction with forms
is
@anchor{fl_do_forms()}
@findex fl_do_forms()
@example
FL_OBJECT *fl_do_forms(void);
@end example
@noindent
It starts the main loop of the program and returns only when the state
of an object changes that has no callback bound to it. A pointer to
this object is then returned.
A second way of doing interaction with the currently displayed forms
is using
@anchor{fl_check_forms()}
@findex fl_check_forms()
@example
FL_OBJECT *fl_check_forms(void);
@end example
@noindent
This routine returns @code{NULL} immediately unless the state of one
of the object (without a callback bound to it) changed. In that case a
pointer to this object gets returned.
Then there are two more functions:
@anchor{fl_do_only_forms()}
@findex fl_do_only_forms()
@anchor{fl_check_only_forms()}
@findex fl_check_only_forms()
@example
FL_OBJECT *fl_do_only_forms(void);
FL_OBJECT *fl_check_only_forms(void);
@end example
@noindent
Both functions do the same as @code{@ref{fl_do_forms()}} and
@code{@ref{fl_check_forms()}} except that they do not handle user
events generated by application windows opened via
@code{@ref{fl_winopen()}} or similar routines.
To activate or deactivate a form for user interaction you can use
@findex fl_activate_form()
@anchor{fl_activate_form()}
@findex fl_deactivate_form()
@anchor{fl_deactivate_form()}
@example
void fl_activate_form(FL_FORM *form);
void fl_deactivate_form(FL_FORM *form);
@end example
The same can also be done for all forms at once using
@findex fl_deactivate_all_forms()
@anchor{fl_deactivate_all_forms()}
@findex fl_activate_all_forms()
@anchor{fl_activate_all_forms()}
@example
void fl_deactivate_all_forms(void)
void fl_activate_all_forms(void)
@end example
You can also register callbacks for a form that are invoked whenever
the activation status of the form is changed:
@tindex FL_FORM_ATACTIVATE
@tindex FL_FORM_ATDEACTIVATE
@findex fl_set_form_atactivate()
@anchor{fl_set_form_atactivate()}
@findex fl_set_form_atdeactivate()
@anchor{fl_set_form_atdeactivate()}
@example
typedef void (*FL_FORM_ATACTIVATE)(FL_FORM *, void *);
FL_FORM_ACTIVATE fl_set_form_atactivate(FL_FORM *form,
FL_FORM_ATACTIVATE callback,
void *data);
typedef void (*FL_FORM_ATDEACTIVATE)(FL_FORM *, void *);
FL_FORM_ACTIVATE fl_set_form_atdeactivate(FL_FORM *form,
FL_FORM_ATACTIVATE callback,
void *data);
@end example
Also individual objects (or groups of objects if the argument of the
function is an object returned by @code{@ref{fl_bgn_group()}}) can be
activated and deactivated to enable or disable user interaction:
@findex fl_activate_object()
@anchor{fl_activate_object()}
@findex fl_deactivate_object()
@anchor{fl_deactivate_object()}
@example
void fl_activate_object(FL_OBJECT *obj);
void fl_deactivate_object(FL_OBJECT *obj);
@end example
@noindent
It is normally useful to give the user a visual clue when an object
gets deactivated, e.g., by graying out its label etc.
To find out if an object is active use
@findex fl_object_is_active()
@anchor{fl_object_is_active()}
@example
int fl_object_is_active(FL_OBJECT *obj);
@end example
@findex fl_redraw_object()
@anchor{fl_redraw_object()}
@example
void fl_redraw_object(FL_OBJECT *obj);
@end example
@noindent
This routine redraws the particular object. If @code{obj} is a group
it redraws the complete group. Normally you should never need this
routine because all library routines take care of redrawing objects
when necessary, but there might be situations in which an explicit
redraw is required.
To redraw an entire form use
@findex fl_redraw_form()
@anchor{fl_redraw_form()}
@example
void fl_redraw_form(FL_FORM *form);
@end example
For non-form windows, i.e., those created with
@code{@ref{fl_winopen()}} or similar routines by the application
program, the following means of interaction are provided (note that
these do not work on form windows, for which a different set of
functions exist. @xref{Windowing Support}, for details.)
You may set up a callback routine for all user events using
@findex fl_set_event_callback()
@anchor{fl_set_event_callback()}
@example
FL_APPEVENT_CB fl_set_event_callback(int (*callback)(XEvent *ev, void *data),
void *data);
@end example
It is also possible to set up callback functions on a per window/event
basis using the following routines:
@tindex FL_APPEVENT_CB
@findex fl_add_event_callback()
@anchor{fl_add_event_callback()}
@findex fl_remove_event_callback()
@anchor{fl_remove_event_callback()}
@example
typedef int (*FL_APPEVENT_CB)(XEvent *xev, void *user_data);
FL_APPEVENT_CB fl_add_event_callback(Window win, int xevent_type,
FL_APPEVENT_CB callback,
void *user_data);
void fl_remove_event_callback(Window win, int xevent_type);
@end example
@noindent
These functions manipulate the event callback functions for the window
specified, which will be called when an event of type
@code{xevent_type} is pending for the window. If @code{xevent_type} is
0 it signifies a callback for all event for window @code{win}. Note
that the Forms Library does not solicit any event for the caller,
i.e.@: the Forms Library assumes the caller opens the window and
solicits all events before calling these routines.
To let the Forms Library handle event solicitation, the following
function may be used
@findex fl_activate_event_callbacks()
@anchor{fl_activate_event_callbacks()}
@example
void fl_activate_event_callbacks(Window win);
@end example
@node Signals
@section Signals
Typically, when a signal is delivered, the application does not know
what state the application is in, thus limiting the tasks a signal
handler can do. In a GUI system and with a main loop inside the
library, it's even harder to know what's safe or unsafe to do in a
signal handler. Given all these difficulties, the Forms Library's main
loop is made to be aware of signal activities and invoke signal
handlers only when it's appropriate to do so, thus removing most
limitations on what a signal handler can do.
The application program can elect to handle the receipt of a signal by
registering a callback function that gets called when a signal is
caught
@tindex FL_SIGNAL_HANDLER
@findex fl_add_signal_callback()
@anchor{fl_add_signal_callback()}
@example
typedef void (*FL_SIGNAL_HANDLER)(int, void *);
void fl_add_signal_callback(int signal, FL_SIGNAL_HANDLER sh,
void *data);
@end example
Only one callback per signal is permitted. By default,
@code{@ref{fl_add_signal_callback()}} will store the callback function
and initiate a mechanism for the OS to deliver the signal when it
occurs. When the signal is received by the library, the main loop will
invoke the registered callback function when it is appropriate to do
so. The callback function can make use of all of XForms's functions as
well as Xlib functions as if they were reentrant. Further, a signal
callback registered his way is persistent and will cease to function
only when explicitly removed.
It is very simple to use this routine. For example, to prevent a
program from exiting prematurely due to signals, a code fragment
similar to the following can be used:
@example
void clean_up(int signum, void *data) @{
/* clean up, of course */
@}
/* call this somewhere after fl_initialize() */
fl_add_signal_callback(SIGINT, clean_up, &mydata);
@end example
@noindent
After this, whenever a @code{SIGINT} signal is received,
@code{clean_up()} is called.
To remove a signal callback, the following routine should be used
@findex fl_remove_signal_callback()
@anchor{fl_remove_signal_callback()}
@example
void fl_remove_signal_callback(int signal);
@end example
Although very easy to use, there are limitations with the default
behavior outlined above. For example on some platforms there is no
blocking of signals of any kind while handling a signal. In addition,
use of @code{@ref{fl_add_signal_callback()}} prevents the application
program from using any, potentially more flexible, system signal
handling routines on some platforms. Also there might be perceptible
delays from the time a signal is delivered by the OS and the time its
callback is invoked by XForms' main loop. This delay can be particular
troublesome for timing sensitive tasks (playing music for example).
In light of these limitations, provisions are made so an application
program may choose to take over the initial signal handling setup and
receipt via various system dependent methods (@code{sigaction()} for
example).
To change the default behavior of the built-in signal facilities, the
following routine should be called prior to any use of
@code{fl_add_signal_callback(}) with a true value for @code{flag}:
@findex fl_app_signal_direct()
@anchor{fl_app_signal_direct()}
@example
void fl_app_signal_direct(int flag);
@end example
@noindent
After this call @code{@ref{fl_add_signal_callback()}} will not
initiate any actions to receive a signal. The application program
should handle the receipt and blocking of signals (via e.g.,
@code{signal(2)}, @code{sigaction(2)}, @code{sigprocmask(2}) etc.) When
the signal is received by the application program, it should call the
following routine to inform the main loop of the delivery of the
signal @code{signum}, possibly after performing some timing sensitive
tasks:
@findex fl_signal_caught()
@anchor{fl_signal_caught()}
@example
void fl_signal_caught(int signum);
@end example
@noindent
This routine is the only one in the library that can be safely called
from within a direct application signal handler. If multiple
invocations of @code{@ref{fl_signal_caught()}} occur before the main
loop is able to call the registered callback, the callback is called
only once.
The following example illustrates how to handle a timing critical
situation (for most application, idle callback, timeouts or
@code{FL_TIMER} object should be sufficient).
First, you need to define the function that will handle the timing
critical tasks. The function will be registered with the OS to be
invoked directly by it. There are limitations on what you can do
within a (OS) signal handler, in particular, GUI activity is not safe.
@example
void timing_critical_task(int sig) @{
/* handle timing critical tasks that does not involve GUI */
...
/* Now tell the library the signal has been delivered by the OS.
* The library will invoke the xforms signal handler when it's
* appropriate to do so */
fl_signal_caught(sig);
@}
@end example
@noindent
Now define a (XForms) signal handler that will be responsible for
handling the response of the GUI upon receipt of the signal
@example
void gui_signal_handler(int sig, void *data) @{
/* within an XForms signal handler, there is no limitation
* on GUI activitity */
fl_set_object_color(....);
...
@}
@end example
To make all this work, a set-up similar to the following can be used
@example
/* setup the signal */
fl_app_signal_direct(1);
setitimer(ITIMER_REAL, interval);
/* setup the OS signal handler */
signal(SIGALRM, timing_critical_tasks);
/* setup the XForms signal handler */
fl_add_signal_callback(SIGALRM, gui_signal_handler, &myData);
@end example
@node Idle Callbacks and Timeouts
@section Idle Callbacks and Timeouts
For application programs that need to perform some light, but
semi-continuous or periodic tasks, idle callback and timeouts (also
@code{FL_TIMER} objects) can be utilized.
To register an idle callback with the system, use the following routine
@tindex FL_APPEVENT_CB
@findex fl_set_idle_callback()
@anchor{fl_set_idle_callback()}
@example
typedef int (*FL_APPEVENT_CB)(XEvent *, void *);
FL_APPEVENT_CB fl_set_idle_callback(FL_APPEVENT_CB callback,
void *user_data);
@end example
@noindent
where @code{callback} is the function that will get called whenever
the main loop is idle. The time interval between invocations of the
idle callback can vary considerably depending on interface activity
and other factors. A range between 50 and @w{300 msec} should be
expected.
It is possible to change what the library considers to be "idle" with
the following function:
@findex fl_set_idle_delta()
@anchor{fl_set_idle_delta()}
@example
void fl_set_idle_delta(long msec);
@end example
@noindent
Here @code{msec} is the minimum time interval of inactivity after
which the main loop is considered to be in an idle state. However it
should be noted that under some conditions an idle callback can be
called sooner than the minimum interval.
If the timing of the idle callback is of concern, timeouts should be
used. Timeouts are similar to idle callbacks but with the property
that the user can specify a minimum time interval that must elapse
before the callback is called. The precision of timeouts tends to be
quite a bit better than that of idle callbacks since they internally
get prefered treatent. To register a timeout callback, the following
routine can be used
@tindex FL_TIMEOUT_CALLBACK
@findex fl_add_timeout()
@anchor{fl_add_timeout()}
@example
typedef void (*FL_TIMEOUT_CALLBACK)(int, void *);
int fl_add_timeout(long msec, FL_TIMEOUT_CALLBACK callback,
void *data);
@end example
@noindent
The function returns the timeout ID (note: the function will not
return 0 and -1, so the application can use these values to mark
invalid or expired timeouts). When the time interval specified by the
@code{msec} argument (in milli-second) is elapsed, the timeout is
removed and the callback function is called with the timeout ID as the
first argument. Although a timeout offers some control over the
timing, due to performance and CPU load compromises, while the
resolution can be better than @w{10 ms} under favourable conditions,
it can also be much worse, occasionally up to @w{150 ms}.
To remove a timeout before it triggers, use the following routine
@findex fl_remove_timeout()
@anchor{fl_remove_timeout()}
@example
void fl_remove_timeout(int id);
@end example
@noindent
where @code{id} is the timeout ID returned by
@code{@ref{fl_add_timeout()}}. @xref{Timer Object}, for the usage of
@code{FL_TIMER} object. For tasks that need more accurate timing the
use of signal should be considered.
|