File: part5_overview.texi

package info (click to toggle)
libforms 1.0.93sp1-2
  • links: PTS
  • area: main
  • in suites: wheezy
  • size: 11,548 kB
  • sloc: ansic: 97,227; sh: 9,236; makefile: 858
file content (1987 lines) | stat: -rw-r--r-- 70,482 bytes parent folder | download | duplicates (2)
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.