                         LibGGI Hackers' Guide
                         =====================

$Id: libggi-hackers.txt,v 1.1 1998/08/26 22:09:35 steve Exp $

(C) 1998 Steve Cheng <steve@ggi-project.org> and others.

Pieces of documentation (basically a bunch of notes, hackers tend to
tolerate bad documentation :-) on various LibGGI internals.  Useful if you
wanted to improve/debug LibGGI or satisfy your curiosity.  Some of it may
apply to other parts of the GGI Project <http://www.ggi-project.org> as
well.

This document isn't in Linuxdoc format since it is a pain in the @$$ to
write in (IMO), and you're expected to get dirty with the source anyway :-)




First, a message from our friend Marcus Sundberg:

> > As I wrote in another post:
> > Requesting auxiliary buffers (offscreen pixmapstorage, z-buffers,
> > sprite buffers or whatever) should be in an (or more than one probably,
> > given the number of different buffertypes) extension, and these
> > extensions would naturally have functions to do every possible
> > operation on these buffers, such as blitting them to the screen.

Allocating DirectBuffers is currently not possible (mentioned extension is
not written yet), but there is a simple API to get them.

This is now becoming an Official Frequently Answered Question :-)




8.  Overview of how to write a LibGGI display target (and other
    sub-libraries)

  [This article is NOT a substitute for not looking at the existing
  display target code. This section does not explain every detail.]

  Actually, most of the work of displaying and servicing an application
  has been done for the display target writer. For example, there is
  reasonably optimized code for linear framebuffers of most bit-types,
  and stubs exist to do a few non-speed-critical operations such as 
  ggiPutc() by calling ggiSetPixel() individually.  "Convenient"
  functions such as ggi{Set/Check}{Text/Graph}Mode() simply call the
  "master" function, ggi{Set/Check}Mode(), with different arguments,
  and the display target writer only needs to supply "master" functions
  for these to work.

  However, (and this is the important part) targets may also choose to
  override standard drawing functions. E.g. because they have no
  framebuffer, or for speed (e.g. they have hardware accel).

  When the application requests a visual (by name), LibGGI looks it up
  in its configuration file, and loads and initializes the appropriate
  library. On initialization, the display target's GGIdlinit() is
  called. This function should do whatever set up is necessary to begin
  using the target, e.g.  initializing Xlib in the display-X target. 
  This is basically the result of ggiOpen().  But do NOT set the mode
  here yet.

  GGIdlinit() should also indicate which functions it implements by
  assigning the various function pointers of the operation structs to its
  own functions.  (Which are prototyped as GGIgetmode, GGIsetmode, GGIflush,
  etc. in ggi/ggi-dl.h.) It does not have to implement all of the possible
  functions; if it doesn't then stubs are used or the function fails.)

  The user-visible functions in libGGI are simply stubs which call your
  target's functions.  So you can know the expected behavior of the
  functions by looking at the User's docs.  All functions are passed a
  ggi_visual* argument so you can have more than one instance of a target
  open and know which one you're dealing with.

  Now, the LibGGI headers have a lot of macros n' stuff for internal library
  use.  So, instead of messing with the ggi_visual structure itself (in case
  the structure changes, etc.), you use macros such as LIBGGI_MODE(vis) for
  vis->mode, and LIBGGI_PIXFMT(vis) for vis->pixfmt.  See internal.h for
  these.  Other structures are in structs.h.  However, all of this is
  included in ggi-dl.h so don't bother including the other headers in the
  target.

  GGIgetmode() is used to check the mode. Usually the display target can
  simply grab the mode stored in the given ggi_visual.

  GGIsetflags() sets the flags.  If setting a flag triggers an action, then
  you should do that here instead of just doing a LIBGGI_FLAGS(vis)=flags.

  GGIcheckmode() is used to check if the mode in question can be set. If
  not, the mode passed to it should be changed to the suggested mode.
  GGIsetmode() is used to set the mode. If it fails, GGIsetmode() should
  suggest a mode, although this change may not be propagated back to
  ggiSet{Text/Graph}Mode because they don't take a ggi_mode pointer.

  GGIsetmode() implementations must also load "suggestions". Suggestions
  are additional libraries used by the target, such as the linear
  framebuffer libraries, and stubs.  The GGIgetapi() function is usually
  used to return the names of these suggestions to LibGGI "extensions"
  -- libraries that extend libGGI and its API -- for optimization for
  each target/library.

  The "suggestions" that a target will most likely use are generic-linear-*
  or generic-text-* for linear framebuffers, generic-stubs for miscellaneous
  drawing functions (it has stubs for everything using ggiPutPixel()) and
  generic-color for mapping ggi_colors to the palette and vice versa.
  Use _ggiOpenDL() to load suggestions.

  GGIsetmode() should also override any additional operations that the
  target performs, such as GGIfillscreen() for a accelerated fill screen,
  for example.  There are some weird functions like _ggiZapMode() to clear
  the settings of a previous GGIsetmode().

  Any target-specific data (e.g. information about the X display) is
  'hooked' onto the visual structure itself using a pointer.  ggi_visual
  has members such as void *targetpriv, void *helperpriv, void *colorpriv,
  etc. for exactly this purpose.

  GGIdlcleanup() should free() all the memory that the target has opened
  for the visual, return consoles to text mode, shutdown X connection, etc.
  This is the result of calling ggiClose().


Writing other LibGGI sub-libraries (i.e. "suggestions") are similar, but
they override some other structure (not opdisplay), and may be portable
between targets.

Now, if you're seriously going to start a new target, the easiest way is to
copy another target that acts similar or has similar structure and replace
each part of that one-by-one.  However, if you see any brain-damages in
coding style (there used to be meaningless "We are guaranteed to have been
checked already..." comment in every visual.c of the tree) or resulting from
old LibGGI-isms (there have been major overhauls since its inception),
please do not hesitate to change that.




Targets' common code:

It's common for us to move anything that is duplicated between LibGGI
targets.  For example, X and Xlib targets have a lot of common code since
they both deal with X-Windows, and we want to make life easier for anyone
improving the X code.  The code is included by #include (not *.c because
the data structures are different between targets).

We put the documentation for these things in the source code if we feel
like it.  But often they do little things so they're easy to understand even
without comments.




The Evils of helper-mansync:

This is a library loaded by targets which want or need to emulate a hardware
framebuffer.  It's not enough for the target to allocate some memory for
the emulated fb because anything written to it is not instantly displayed.
So what this does is to repeatedly call ggiFlush() 20 times per second to
get it to display.  As you can see, this is a hack (was even worse when the
code was all macros instead of a proper library), but our Master Andy Beck
wants sync mode implemented for all targets.




A warning from the LibGGI Code Police:

> _DO NOT_ use static or global variables in _any_ code in
> lib/libggi/display/* or lib/libggi/default/*, unless they are
> strictly read-only or absolutely neccessary - even if you think
> that there can only be one visual open at a time.
> And they are _rarely_ "absolutely neccessary".

IOW, use LIBGGI_PRIVATE(vis) to store your target's stuff.  We want robust
code, e.g. nested multiple targets.

> 
> And in case of global variables, _always_ prefix them with _ggi
> or _GGI.
> 
> I've done some cleaning up of such variables, but there's still
> a lot of them. I'm not sure about about display/fbdev/vtswitch.c,
> could you check it to see if anything there really needs to be
> static Andrew?
> 
> Also I've removed _ALL_ warnings when compiling libggi and the
> demos (except an inline warning in demos/showaccel.c), PLEASE
> keep it this way now!

Be sure to read namespace.txt for other things you should avoid in LibGGI.
There used to be a doc on what the bosses' coding style is but I can't find
it anymore.  Just try not to make it worse, okay? :-)




Debugging macros:

DPRINT - Print message to stderr if GGI_DEBUG=255 is set.  Works like
         printf(3).

LIBGGI_ASSERT(expr, msg) - If DEBUG is defined at compile time, check if
         expression is true[*]; if so, aborts program with some source
         file information and specified string. 

         [*] Note that currently the meaning is the inverse of assert(3),
         which aborts program if expression is false.  Here's what Neal
         Tucker says about it:

  Andrew Apted says:
  > Marcus writes:
  >
  > >  Hmm, you might be right about that. Should I change them to
  > >  LIBGGI_IFERR and LIBGGI_APPIFERR ? Or does anyone have a better
  > >  name?
  >
  > Stick with ASSERT imho.
  
  Yes, I vote for ASSERT, but changing the meaning to be consistent
  with assert(3).  The reason the assert(3) logic seems odd to you
  is that you've probably started to equate the word "assert" with
  "halt because something bad happened".  This isn't what it means.
  It means "I assert (claim) the following:".  If the assertion is
  false, that's a catastrophic error.
  
  "I assert that 1 equals 2" causes an abort because the condition
  is false.

  (I don't think I'm the only one who thinks this way, though I do
   understand what assert means.)

LIBGGI_APPASSERT(expr, msg) - Same as above except that we check if
         the application programmer screwed up instead of an internal
         error.




More DirectBuffer stuff: (don't you love BiCapitalized buzz words?)

The ggi_visual struct carries two lists of DirectBuffers.  DirectBuffers in
this list are usually creating by targets at mode setting.  They are used
by generic-linear-* to do drawing.

One list is the public or application list (LIBGGI_APPLIST) which is
available to LibGGI applications.  A private list (LIBGGI_PRIVLIST) is for
DirectBuffers that are not available to LibGGI applications (e.g. internal
buffers, backing store), but still used by generic-linear-*.

Each DirectBuffer, in addition to the fields visible to the user, has a tag
associated with it (not implemented yet) which says which target/library it
belongs to.  (When target is cleaning up, it frees the DBs which it owns.)

See db.c for what functions a target can use to manipulate DirectBuffers.




What are LibGGI extensions?

> But you seem to be under the common but wrong impression that
> an extension is something that sits on top of libggi and add
> higher level functions - it's not.

> An extension is something that uses the extension mechanism
> of libggi (ggiExtension* family functions), and it'll probably
> also include ggi/internal/internal.h instead of ggi/ggi.h

> An extension rather sits _beside_ libggi and adds functionality
> to the core libggi. An extension has access to all internal data-
> structures of libggi, may load target-specific libraries for
> that particular extension, may override existing functions
> to extend their functionality, and certainly may interface the
> hardware directly.

> Please have a look at the misc extension in lib/libggi/extensions/misc
> to see how to write an extension that provides an API to lowlevel
> hardware functions.




EXPSYMS files:

I think these are used to accomodate static libs.  LibGGI is heavily
dependent on a DL system.  So if you write a new library then don't forget
it.




LibGGI thread-safety:

The current (depressing) situation is that even with multi-threading support
compiled LibGGI is not thread-safe.  But it shouldn't be that hard to fix it
write:

> In the targets, driver libraries, etc., do _ggiLock() and _ggiUnlock().
> 
> We don't do it in stubs because e.g. in ggiEventPoll() you might want to
> release the lock for periods of time.  It might also depend on the target:
> e.g. Xlib must lock, but simultaneous drawing on framebuffer should be ok.
> 
> ggiFlush should do a _ggiTryLock(), since that is the current behaviour
> (albeit X locks on ints!), but the real problem is that pthread_mutex_t
> isn't async signal safe, so if we do a _ggiLock() from mansync, we get
> a deadlock.

The goal is (pending no objections):

[be threadsafe for]
> At least the case where two threads open two separate visuals and use
> them independently.
> 
> It would also be nice if events could be gathered in one thread while
> drawing was performed by another thread (e.g. a multithreaded game
> engine).  Putting some locking in common/evqueue.inc would be the easy
> part, but how much of a PITA would this be for the X targets ?
> 
> [Should be no problem for the fbdev target AFAICT].





generic-color:

> Here's the plan:  The ggi_visual structure has a "ggi_color *palette"
> field which is non-NULL for GT_PALETTE modes, and contains the current
> palette.
> 
> Then, we have a "generic-color" sub-library which implements
> ggiMapColor() and ggiUnmapPixel() for GT_PALETTE modes (using
> vis->palette) and GT_TRUECOLOR modes (using vis->pixelformat) and
> GT_GREYSCALE modes (using a simple formula).  It also implements
> ggiPackColors() and ggiUnpackPixels().
> 
> Although this could be done in generic-stubs, separating the color
> mapping stuff from the drawing stuff is cleaner IMHO,  We could even
> rename "generic-stubs" to "generic-draw" ... that would be nice.

Also, if a target loads this, you are required to setup the pixel format
(LIBGGI_PIXFMT) and vis->palette (if in GT_PALETTE mode) *BEFORE* loading
the generic-color sub-library, or it will not work.

Another thing, Marcus doesn't like targets setting a default BGR233 (or
whatever) palette, so don't do it. :-)




Clipping functions:

> While we're busily upgrading libggi's gizzards, I'd like to rework the
> way non-clipping functions work, as follows :
> 
>   a) Instead of just the "_" prefix (which is rather meaningless), have
>      a suffix of "_nc" (nc == non clipping).  Thus _drawpixel becomes
>      drawpixel_nc.
> 
>   b) Add a putpixel_nc function to opdraw.
> 
>   c) Update generic-stubs such that the only drawing functions that a
>      target HAS to implement is: putpixel_nc & getpixel.  This is handy
>      when prototyping a new target.  (Of course the other stuff SHOULD
>      be implemented to get half-decent performance).




ggi_key_events:

>  Currently ggi_key_event has these three entries:
>          uint32  sym;            /* meaning of key (action)      */
>          uint32  code;           /* keyboard's code for key      */
>          uint32  label;          /* label on key                 */

label describes which physical key was pressed.

sym describes the meaning of that key, with regard taken to modifiers and
such.

code is the key's "scancode", but it is hardware-/target-/keyboard-
dependent.

> For ordinary keys (letters, digits and such), the label and sym values
> are just Unicode.  Thus values <= 0xff are just ISO-8859-1 (hence the
> GGI_KT_LATIN1 keytype).  For example, pressing SHIFT+A gives a label of
> 0x61 ('a') and a sym of 0x41 ('A').
> 
> [With a few exceptions, label is just the sym value you get with no
> modifiers pressed].

And if you press just a shift key, then you get a label with a non-character
sym (K_VOID ?).




Option parsing:

> I've added some code to lib/libggi/display/common/parsing.inc for option
> parsing by display targets.  All you need to do is setup an array of
> ggi_option with each option name and default value, and call
> _GGIparseoptions(), then use the results.  The fbdev target already does
> this (check out display/fbdev/visual.c), and I will soon update trueemu,
> palemu & monotext similiarly.
> 
> Part of the idea is to be able to specify options for each target in an
> environmental variable, such as GGI_FBDEV_OPTIONS for the fbdev target,
> and GGI_TRUEEMU_OPTIONS for the trueemu target.  These options are
> overridable by options in the argument string itself, as in :
> 
>       export GGI_FBDEV_OPTIONS='-mouse=microsoft -joystick=ibm'
>       export GGI_DISPLAY='fbdev:-mouse=logitech:/dev/fb1'
> 
> (the -mouse in GGI_DISPLAY overrides the one in GGI_FBDEV_OPTIONS).




