home *** CD-ROM | disk | FTP | other *** search
/ RISC DISC 1 / RISC_DISC_1.iso / pd_share / code / desklib / Docs / AuthorNote < prev    next >
Encoding:
Text File  |  1993-04-11  |  25.5 KB  |  554 lines

  1. STOP PRESS
  2.  
  3. I have realised that I don't often have time to do much work on DeskLib
  4. myself. This has resulted in suspension of my activities on a menu template
  5. system. The main problem is that many of the routines in DeskLib are just
  6. TOO generic, and can be better written for individual applications if they
  7. include nasty hacky hand-tuned things in them. However, some parts of
  8. DeskLib are useful 'little' routines, which I feel are more useful in any
  9. circumstances:
  10.  
  11.   Compact and efficient function call interfaces for SWIs (in assembler)
  12.   Small routines like Icon_Select() which make the program more readable
  13.     and/or save a lot of programming bother on "nitty gritty" stuff.
  14.  
  15. The other routines are more useful as tutorial type code for you to look at,
  16. chop bits out of, etc. when writing your own code for those operations.
  17. Thus, it would be preferable to add small, useful, timesavers rather than
  18. large, bloated "all-singing all-dancing" routines.
  19.  
  20. Thus, if you send any code, I will concentrate my available time on the
  21. simpler, more useful routines, as I feel they are generally more globally
  22. useful than bigger, more complex routines.
  23.  
  24. ---
  25.  
  26. If you write any code which you feel you may one day deign to send to the
  27. DeskLib moderator for possible inclusion in the library, then please read
  28. through the following text. It is also suggested that you familiarise
  29. yourself with the way most of the library structures have been laid out, and
  30. the naming conventions used, so that you can make your codes' external
  31. interface as consistent with the rest of DeskLib as possible
  32.  
  33. The following is not mandatory, but it will help, and it'll save me
  34. re-writing your code before it goes in!
  35.  
  36.  
  37. Programming conventions
  38. =======================
  39.  
  40.  There are various conventions which I have tried to impose upon the DeskLib
  41.  code to retain as much consistency as possible. If writing generic code
  42.  that you might add to DeskLib for all to use in the future, then please try
  43.  to write it in the same style as the current code (even if you don't
  44.  personally like this style, it is *very* bad to have inconsistencies, and I
  45.  will be forced to re-write all your code to comply, which is a lot of
  46.  wasted bother...)
  47.  
  48.  The main aims of the following conventions are:
  49.    -Naming consistency. I have chosen to echo the style used in Acorn's SWI
  50.     names (see below).
  51.    -Readability. Although "event.type" means more typing work than "e->e",
  52.     it is far better in a global library such as this for the following
  53.     reasons:
  54.       - Anyone reading some source code will be able to work out fairly
  55.         easily what is going on, even if they haven't seen the library
  56.         naming before.
  57.       - You don't need to memorise huge gobs of ASCII encodings just to
  58.         program with the library - if you want an event type, it is most
  59.         likely called an event type, not an e->e.
  60.       - Learning the ins and outs of a new library is far quicker and less
  61.         painful if things have meaningful names - especially if they tally
  62.         with similar names used in other languages people are used to.
  63.       - Debugging is easier, as remembering what an "event->type" is tends
  64.         to be easier than remembering what the "e->e" was.
  65.       - Readability is improved, so other people can more easily understand
  66.         your code, and if you leave some code alone for a few weeks and then
  67.         come back to it, you will be able to work out what you had done more
  68.         easily.
  69.       - Portability is increased, as it is easier to translate code full of
  70.         meaningful names than code full of random ASCII symbols.
  71.  
  72.  Anyone who does not like the names of types and functions in the library
  73.  can always use #defines or alter their copy of the sources to make the
  74.  names meaningless again if they so wish. (Though it is recommended that you
  75.  use #defines, so that the code remains compatible with future releases of
  76.  the Library.)
  77.  
  78.  function names:
  79.    I have opted to use the same style as Acorn standardised with their SWI
  80.    names. That is,  module-name underline function-name, where module-name
  81.    and function-name are all lowercase except for the initial letters of
  82.    words:
  83.    
  84.  i.e. Wimp_OpenWindow();
  85.       Dialog_SaveAs();
  86.       Icon_PlaceCaret();
  87.  
  88.  (Note that for the libraries I have defined SWI names as SWI_Wimp_OpenWindow
  89.  so that there is no clash between the #defined SWI name and the funcion name)
  90.  
  91.  DeskLib uses a policy of splitting code up into the smallest reasonable
  92.  segments so that a minimum of code is included if the user only calls one
  93.  function. The result of this is that it is necessary to supply some
  94.  internal-use functions (and variables) to external callers (other parts of
  95.  DeskLib).
  96.  These are to be named as above, but use a double underline to make it clear
  97.  that they are internal routines that should generally not be used unless by
  98.  a new routine for inclusion into DeskLib itself...
  99.  
  100.  
  101.  variable/type names:
  102.    The LAST thing that we want is 1-letter variable names. Undeniably they
  103.    are faster to type, but they render code far more difficult to read, even
  104.    for people who are fluent with them, and they make learning the use of a
  105.    library a long and arduous task. Also, working out what an "m" is from
  106.    its context is an undesirable thing.
  107.    (i.e. "w", "i", "m", "m", and "e" are definitely out!)
  108.  
  109.    The second to last thing that we want is a really long variable name, as
  110.    it is an annoyance to have to type exceedingly long names over and over.
  111.    Thus, some things are gong to have to be abbreviated.
  112.    (i.e. "saveas_read_leafname_during_send" is also not too good)
  113.  
  114.    Abbreviations should be 4 to 6 characters long where possible. e.g.
  115.       icon          ->  icon
  116.       window        ->  window
  117.       menu          ->  menu
  118.       button        ->  button
  119.       mouse         ->  mouse
  120.       dialogue      ->  dialog
  121.       outline       ->  outline
  122.       rectangle     ->  rect
  123.  
  124.    -most names fit nicely into 4 or 5 characters without much abbreviation,
  125.    and this seems to be a nice compromise between readability and typing
  126.    effort.
  127.  
  128.    The third important thing is that naming should be consistent: If you
  129.    look through the wimp library data structures, for example, you will find
  130.    that a window handle (type window_handle) is ALWAYS called a window in
  131.    external interfaces.
  132.    An icon_handle is always called an icon
  133.    An icon definition block (type icon_block) is always called an iconblock
  134.    A flag word is always accessed as flagword.value or flagword.data.xxx
  135.    (i.e. "value" and "data" names for flags are consistent throughout the
  136.    library, even though they might not be the "best" names under all
  137.    circumstances)
  138.    etc.
  139.  
  140.    Variables and types should be entirely lowercase to differentiate them
  141.    more easily from function names. They should contain underlines to
  142.    seperate groups from individuals (e.g. wimp_window, wimp_icon), but NO
  143.    MORE than ONE underline.
  144.    Although multiple-word variables look bad (wimp_openwindowstructure)
  145.    if things are abbreviated well and the words are carefully chosen, names
  146.    can still be quite readable all lowercased. (window_openblock)
  147.  
  148.    Where Acorn's naming fits within these guidelines, you should use
  149.    Acorn-compatible names. For example, I don't wholly like Acorns
  150.    "nameisname", but I have kept it as it is not too bad, still adequately
  151.    describes it's function, and is not a silly name like "nin" which I would
  152.    find meaningless. (Thus, Acorn's w becomes window, and i becomes icon)
  153.    This will help to ease the job of moving from use of Acorn's library to
  154.    this one, as well as making it as easy as possible to integrate parts of
  155.    the two libraries together where necessary.
  156.                                               
  157.    constants should be named with lowercased module/group name, followed by
  158.    an underline and uppercased constant name. (i.e. the same as a variable,
  159.    but with the second half uppercased). e.g.
  160.      icon_SELECTED
  161.      colour_GREEN
  162.  
  163.    Notice how I have seperated many data constants into groups like
  164.      icon, iconborder, iconbtype, etc.
  165.    rather than just the module name (Acorn use wimp_ for *everything*)
  166.    because this makes it much easier to understand what a constant is for...
  167.    e.g.
  168.         wimp_ISELECTED    ->     icon_SELECTED
  169.         wimp_MOVE_WIND    ->     drag_MOVEWINDOW
  170.         wimp_BRIGHT       ->     button_RIGHT
  171.         wimp_WMOVEABLE    ->     window_MOVEABLE
  172.  
  173.    (In fact, DeskLib goes one step further, and defines variable structures
  174.    so that you can simply use icon.data.selected to retrieve a flag etc.)
  175.  
  176.    which not only makes the function of the constant far more meaningful and
  177.    far less ambiguous, but in many cases makes the constant name shorter as
  178.    well. It also removes the possibility of using (for example) an icon flag
  179.    in a window_flagword by accident because you misread/misinterpreted one
  180.    character in its name.
  181.  
  182.    From a programming point of view, it also reduces the chance of you
  183.    defining all your icon flags as wimp_Ixxxx, and then realising that you
  184.    defined one as wimp_INDIRECT instead of wimp_IINDIRECT (as Acorn did)
  185.  
  186.    When in doubt about naming things, look at the source code in this
  187.    library for hints.
  188.  
  189.    The main thing is to get the name as readable, meaningful, consistent,
  190.    and unambiguous as possible, with a secondary consideration to length of
  191.    variable/constant name.
  192.  
  193.  
  194.    header files/function group names:
  195.    ==================================
  196.  
  197.    Try to divide any functions up into distinct groups. Acorn decided on
  198.    modules, for example "wimp", but I feel this should be further subdivided
  199.    into modules for windows, icons, drags, pointers, etc. - basically put
  200.    one "functional group" into it's own .c file (or group of files).
  201.  
  202.    My intent for a module such as "wimp" is to provide a low-level interface
  203.    to all wimp SWI calls (Wimp_OpenWindow(), Wimp_CloseWindow(), etc.), with
  204.    a higher-level (or levels) of interfacing which is named according to
  205.    WHAT the function AFFECTS, for example:
  206.      Window_Open()
  207.    might be the high-level call which does:
  208.      Wimp_GetWindowState(&windowstate);
  209.      windowstate.open.behind = -1; /* Open on top of all other windows */
  210.      Wimp_OpenWindow(&windowstate.open);
  211.  
  212.    For each .c file, there should be a .h file of the same name prototyping
  213.    all external function and variable names, plus any constants that should
  214.    be used in data passed in to those functions. This .h file will go into
  215.    the main .h directory.
  216.    An additional .h file (generally <name>defs.h or similar) can be used for
  217.    internal constant and structure definitions. This usually goes in the .h
  218.    directory local to a sublibrary directory.
  219.    e.g. "Template" has a "Template.h" file detailing the externally visible
  220.    functions, variables, and structures/types. It also has an internal header
  221.    file (Template.h.TempDefs - TempDefs.h) which defines internal-use-only
  222.    definitions.
  223.  
  224.    EVERY header file should guard against multiple-inclusion by using the
  225.    following format:
  226.  
  227.      #ifndef __dl_<filename>_h
  228.      #define __dl_<filename>_h
  229.  
  230.      ... insert your .h code in here ...
  231.  
  232.      #endif
  233.  
  234.    (I know #pragma include_only_once is better, but this will work with ANY
  235.    C compiler, rather than just Acorn's one...)
  236.  
  237.    Note that this is similar to the method used in Acorn's own libraries,
  238.    except for the addition of the dl_ portion: this is so that DeskLib
  239.    libraries can be used in conjunctipon with Acorn libraries (e.g. so there
  240.    is no clash between __dl_error_h and __error_h, for example)
  241.  
  242.    This is also useful, as other files can check #ifdef __dl_<filename>_h...
  243.  
  244.  
  245.    Generic design
  246.    ==============
  247.  
  248.    Please try to design your code in as generic a manner as possible. For
  249.    example, if you write code that automatically malloc's space for a
  250.    window's indirected data, then include a function that can be called to
  251.    free the memory when necessary. (And possibly also include a call to this
  252.    code in the Window_Delete() function). Note that this should be a seperate
  253.    function, so that programmers using the libraries can call it themselves
  254.    if they want to do things slightly differently to the way you envisaged it.
  255.  
  256.    Some code is intended as a sort of template or prototype. For example, you
  257.    might produce routines to draw a single circle, line, etc. in a given
  258.    window. Of course, this means that if two circles are to be drawn my code
  259.    will call GetWindowState twice, which is inefficient. In this case, the
  260.    user can copy the code to draw the circle into his/her own redraw loop,
  261.    and simply use the library routine as a source of useful code fragments.
  262.  
  263.    Another example is the code for SaveAs and other "standard" windows... I
  264.    have endeavoured to allow the user to do anything (e.g. 3-d icons,
  265.    pointer-shape changing) while a save-as window is up, but if necessary
  266.    they should have access to the full source code for SaveAs (so they can
  267.    alter anything), but also if possible to the dialogue-box or window data
  268.    used, so that slight alterations may be made if necessary while the code
  269.    is running. (Thus, I provide a standard functionality for a save-as
  270.    window, which provides consistency between different applications all
  271.    using the same code library, yet the programmer still has the power to
  272.    alter things if they really want to)
  273.  
  274.    
  275.    Error (and other) messages
  276.    If ALL strings in the libraries use "msgs" format, then it will be
  277.    easier to replace default messages with different languages, etc.
  278.    e.g. instead of returning an error message "not found", you should return
  279.    the message "E.CantFind:Not found", so that if the message "E.CantFind" is
  280.    defined in a "msgs" message file, the whole error message can be replaced.
  281.  
  282.    Currently, I have gone about 50% of the way to this, by defining all
  283.    output text in #defined constants at the top of .c files or in
  284.    local .h files... thus, the messages can be more easily changed to
  285.    use msgtrans tags or whatever... In the future these messages may be
  286.    collected into a central .h file to enable quick and easy conversion
  287.    of the entire library to a different language.
  288.  
  289.    This also allows selected messages to be removed from your final
  290.    application (how many times have you needed the error message "Templates
  291.    file is not loaded for use with dialog boxes" after your application is
  292.    developed: If the templates aren't loaded, another error will already
  293.    have occurred (thus the message is never seen) or you don't get the 
  294.    error (thus the message is never seen)...
  295.  
  296.    Also, I find it annoying when I know my messages file is loaded OK to
  297.    have text in my program (the default message) wasting space once again,
  298.    when it has been replaced by a message in my messages file. In these
  299.    cases I would like to replace the message with just the msgtrans tag.
  300.    So having all (most) constant strings used by a bit of code actually
  301.    defined at the top in one lump would be very useful.
  302.  
  303.  
  304.    Defaults
  305.    ========
  306.  
  307.    The last point is to always use sensible defaults: If the user doesn't
  308.    supply a non-vital piece of information, your code should handle it (even
  309.    if *you* know *you* will always supply the full information). For
  310.    example, in *ANY* situation where a function-pointer is supplied, you
  311.    should check if it is NULL, and not try to call it if it is! (Even if
  312.    this renders the effect of your routine down to nothing whatsoever)
  313.    Anywhere that you return values to a variable passed by reference
  314.      ReturnAnInteger(&integer_variable);
  315.    if the variable pointer passed in is NULL, then that return-value should
  316.    be ignored if possible. (checking if something == 0 usually takes only
  317.    one instruction, so very little efficiency is lost due to this, but it is
  318.    VERY useful if you don't want all the return values)
  319.  
  320.    At the very least, if your function DOESN'T do this, then WARN the user
  321.    of this fact in the .h and .c files with comments!
  322.  
  323.    eg In the icon-handling code, it always *checks* that icons are of the right
  324.    types for things to be done to them... For example, an attempt to set the
  325.    text in *any* icon will not fail, even if the icon was not a text icon or
  326.    an indirected text icon. An attempt to place the caret in an icon will
  327.    not always succeed, but no errors or problems should be caused by
  328.    allowing the caret to be placed in "illegal" places such as non-writeable
  329.    icons...
  330.  
  331.  
  332.  
  333. Types
  334. =====
  335.  
  336. Try to define nicely structured types. For example, in the Wimp header, I
  337. have defined a point (x, y), from which a rectangle can be formed (min, max).
  338. This leads to names in use:
  339.   screenrect.min.x
  340.   screenrect.min.y
  341.   screenrect.max.x
  342.   screenrect.max.y
  343.  
  344. which is far nicer than "screenrect.maxx" or "box.x0" etc.
  345.  
  346. It also allows the user to pull out data more easily:
  347.   int         left_x_position    = screenrect.min.x;
  348.   wimp_point  bottom_left_corner = screenrect.min;
  349.   wimp_rect   rectangle          = screenrect;
  350.  
  351. (Note that the point cannot be easily pulled out or copied in Acorn's scheme
  352. in one C instruction)
  353.  
  354. Another example is my scroll positions:
  355.   scroll.x                  (Acorn: scx or x)
  356.   scroll.y                  (       scy or y)
  357.  
  358. and caret offset:
  359.   offset.x                  (Acorn: x)
  360.   offset.y                  (       y)
  361.  
  362. -As you can see, this structure also helps to control inconsistencies - when
  363. programming, you suddenly notice that part of a structure can be replaced by
  364. a predefined substructure, and so your new structure becomes more consistent
  365. with other structure definitions.
  366.  
  367. Basically, the rule of thumb here is:
  368. If part of a data type would make a useful data type in it's own right, DO IT
  369.  
  370.  
  371. FlagWords
  372. =========
  373.  
  374. For consistency, these should be made into structures as follows:
  375.  
  376. union
  377. {
  378.   int value;        /* A straight 32-bit flag word */
  379.  
  380.   struct
  381.   {
  382.     unsigned int bit0   : 1;  /* Note: the number of bits here must be <= 32 */
  383.     unsigned int bit2   : 1;
  384.     ...
  385.     unsigned int nybble : 4;
  386.     ...
  387.     unsigned int byte   : 8;
  388.   } data;
  389. } flagword;
  390.  
  391.  
  392. This gives the programmer the choice of:
  393.  
  394.   flagword.value;
  395. (Exactly the same as current flagwords: a 32-bit integer)
  396.  
  397. or
  398.   flagword.data.nybble (etc.)
  399.  
  400. Note that the two parts "value" and "data" should ALWAYS have these names,
  401. for consistency throughout the library. These names are not always the "best"
  402. to use, but due to the fact that they are consistent, they become easy
  403. to remember.
  404.  
  405. This has the advantage of being able to replace:
  406.   buttontype = (iconflags & BUTTONTYPEMASK) >> BUTTONTYPESHIFT;
  407.   gribble    = (frobbleflags & 0x00f70000) >> 16;
  408.  
  409. with:
  410.   buttontype = iconflags.data.buttontype;
  411.   gribble    = frobbleflags.data.thingy;
  412.  
  413.   (note though, that it is *still* possible to say:
  414.     buttontype = (iconflags.value & BUTTONTYPEMASK) >> BUTTONTYPESHIFT;
  415.    if you really want to?!)
  416.  
  417.  
  418. and replace:
  419.   if (iconflags & icon_SELECTED)
  420.  
  421. with:
  422.   if (iconflags.data.selected)
  423.  
  424. -- A much more pleasant way of thinking about things.
  425.  
  426.  
  427. Misc
  428. ====
  429.  
  430. Writing of basic functions is well underway. What we really need to make
  431. DeskLib better is a lot of little, useful functions.
  432.   e.g. Fake a click on an icon
  433.        Place the caret at the end of an icon
  434.        Shade an icon (ensuring that the caret is removed from the icon)
  435.        Open a window in a portion of "free space" on the desktop
  436.        Bring a window to the front
  437.        Change the colour of an icon
  438.        Change the sprite in an icon
  439. -Most of these things are *very* simple to write, and most of us have the
  440. ability to write most of the functions for ourselves... but it is still very
  441. nice to have them *predefined*, so you can spend your time on actual editing
  442. functions or whatever...
  443.  
  444.   Also, I want a host of functions to handle writable icons: You give your
  445.   writable a validation string of "A" to allow NO characters to be entered,
  446.   and then call the Icon handlers when you get keypress events. They will
  447.   then vet entry of values properly:
  448.     Numbers where you can't type a 0 as the first digit.
  449.     Any number taking up to (e.g.) 12 digits, but not valued less than 0.1
  450.     and not more than 100.0
  451.     Any (e.g.) 3-digit number smaller than (e.g.) 73
  452.     Any number with a value between 0 and 7 (i.e. it will let you type only
  453.      a single digit, then you can only type a ".", and then you can type
  454.      up to x decimal places)
  455.     Any character entered is automatically uppercased/lowercased (good for
  456.      passwords etc.)
  457.     Any valid ADFS filename can be entered: For example, if you try to enter
  458.      a leafname only, you can't type more than 10 characters, but if you
  459.      type a "." then another 10 characters can be typed... I really hate
  460.      counting the number of characters in a save-as dialogue box to ensure I
  461.      haven't used too many characters in the leafname!
  462.  
  463.   As you can probably see by now, there are an infinitude of little functions
  464. that would come in useful to many programmers much of the time, and will be
  465. very useful time/work savers for wimp programmers (it is amazing how much
  466. you use these functions as soon as they become available)
  467.   
  468. You will notice that some of these functions are just useful or convenient
  469. (e.g. Icon_Select, etc.) and others actually save a lot of work (e.g.
  470. placing the cursor at the end of the text in a given icon takes a fair bit
  471. of work) in really quite common cases.
  472. (What annoys me with RISC OS Lib is Acorn's dbox_ obviously has code to
  473. place the caret at the end of an icon's text, but it is HIDDEN inside dbox
  474. so you can't use it generically for any icon - useful code is IN your
  475. program, but YOU can't use it... I find that very wasteful, and this kind of
  476. wanton pollution is killing our planet... ;-) ... (After having seen dbox, I
  477. was also less than pleased to see that every time a caret is placed, the code
  478. is repeated, rather than using a nice generic place_caret call...ugh)
  479.  
  480. -In fact, if you look carefully at the functionality in Acorn's dbox
  481. routines, you will see that it could be split up into a set of slightly more
  482. generic routines, and dbox will simply vanish - it isn't really needed, so
  483. long as your window, icon, and event code is well designed!
  484.  
  485. dbox_show type functions   -> Window show type functions
  486. dbox_event handling        -> default handlers used with Event()
  487. dbox button click handling -> Icon button handlers + event handlers
  488. dbox_set.../dbox_get...    -> Icon_Set/Get Integer/double/text/radios/etc
  489. dbox caret handlers        -> generic caret handlers
  490. dbox key handlers          -> generic key handlers/event handlers
  491.  
  492. Some more examples of the types of routines I intend to end up with:
  493. (well, OK, so these are now implemented in DeskLib... what do you expect? I
  494. wanted the code... it's been *days* since I thought of the idea... ;-)
  495.  
  496.   Window_Show    - Opens a window, allowing it to be opened wherever it was
  497.                    defined in the template, or centered on screen, or
  498.                    centered plus a small random displacement, or appearing
  499.                    under the pointer or over the current caret position, or
  500.                    centered over a given window or icon.
  501.                    And if the window is being opened because of a menu
  502.                    sublink warning message, it is opened instead in the
  503.                    correct position in the menu tree.
  504.                    (This replaces dbox_show, and does more on top)
  505.  
  506.   Window_Delete  - Closes and deletes a window, deallocating all it's
  507.                    handlers, memory, etc.
  508.                    (say goodbye to dbox_dispose!)
  509.  
  510.   A series of functions you can connect in that are default event handlers
  511.   for dialogue boxes. This replaces the dbox_fillin series of calls.
  512.  
  513.   Code for things like moving the caret to the next icon or the previous
  514.   icon, which can be called by the dialog handlers when up-arrow,
  515.   down-arrow, tab, and return keypresses are caught.
  516.  
  517.   And last but not least (as mentioned above), a set of icon calls that set
  518.   and get icon values, radio button selection states, etc. (Not to mention
  519.   icon-groups such as "volume sliders" that will be handled
  520.   semi-automatically. (This is not a dream... the code has *already* been
  521.   written! See Icon.h))
  522.  
  523.  
  524. I also want to devise a method by which you can open two (or more) windows
  525. and attach them to each other as panes. Then, whenever you call high-level
  526. Window_ functions, the windows will be treated as one "window" (i.e. when
  527. one window is dragged, the panes attached to it will move as if glued onto
  528. it, completely automatically, so you don't need to worry about the fact that
  529. they are seperate windows... This will probably mean indexing icons as
  530. 0..1..2 for the base window, and 512, 513, 514 for the pane, as if the whole
  531. kaboodle is really only one window...
  532. -This will probably be with Window_ calls, but the "handle" that you use
  533. is actually only the "back" window handle - you will just have to use 
  534. Window_ calls to access the pane as a "window".
  535.  
  536. (This type of thing is now likely to be conducted in conjunction with the
  537. new Glass template format and !Glazier template editor, which we hope to
  538. have supporting meta-icons (e.g. sliders) and other stuff in a more powerful
  539. manner than is currently possible under the normal WIMP icons/windows)
  540.  
  541. Hopefully these things have helped to show you what *I* intend to do for
  542. DeskLib... lots of useful "tack-on" facilities that are compatible with RISC
  543. OS Lib and DeskLib low-level functions. Any useful functions any of you have
  544. written will be gladly accepted and included into DeskLib (Even if your
  545. function only works with RISC OS Lib, I can try to add support for DeskLib
  546. as well, and the whole world can benefit from the usefulness of your
  547. function. Let's share all the useful code we have sweated over for minutes
  548. instead of hoarding it (which helps nobody)
  549.  
  550. If you think of some good things to write, it might be a good idea to
  551. contact me before you start, and I'll hopefully be able to reduce clashes
  552. where more than one person spends time writing basically the same code...
  553.  
  554.