Common Graphics and the IDE on GTK

Release Notes

Welcome to this preliminary release of Common Graphics and the
IDE on GTK. Note that some features are not yet implemented, and known
bugs remain with what has been implemented. These matters
are described here, along with incompatibilities with the
Microsoft Windows version, plus some general issues to keep in mind.

Links in this document will take you to pages on the Franz
web site for the 8.0 release, assuming you are connected to the
Internet. Most of these links
were generated from exported symbol names in the text, so
some links are not relevant to their context.

The existing documentation for CG and the IDE (see
doc/cgide.htm) was written for the existing Windows platform.
The release notes below describe cases where the behavior on the new
GTK platform differs, so refer to these notes when CG behavior
does not match the CG documenation or the behavior on Windows.

Please send bug reports and other feedback to
support@franz.com.
(Please put `Linux IDE' in the email subject line so we will know
you are referring to this product.)

To start the IDE, first do a (require :ide), unless you are using
an image that already contains the IDE. Then evaluate (ide:start-ide).
Then investigate the Help menu at the rightmost end of the menu bar,
and experiment with commands on other menus.

There is no rich-text (formatted text) capability yet in the
multi-line text control. We have not yet delved into GTK's text
formatting functionality.

This means no colorization in the IDE editor yet (see
colorize-source-code). We can probably
implement the functions for modifying the text color, fonts, and
paragraph styles as on Windows, but will not be able to support
reading the widget contents as a rich text string or placing a rich
text string into the control.

1.4 A standalone app may not yet have a splash pixmap or application icon.

We have not yet come across the way to establish an icon for a
standalone app that would be shown in places like the alt-tab window
and the file manager. Splash pixmaps may need to be implemented in
the base lisp similar to the way they are on Windows. See
splash-file and icon-file.

Drag-and-drop appears to basically work, but there is a problem
with changing the mouse cursor image as the user drags to places
where a drop is either allowed or not. We are currently stumped
by this one.

The icon at the left end of a child window's title-bar is just an icon
currently and doesn't show a menu when you click on it. This is
somewhat low priority due to those menu commands being redundant with
the frame buttons.

These are streams that map arbitrary user drawing coordinates
to pixels. We aren't aware of people using this feature,
except for printer streams, where they are built in (though
we haven't implemented printing on gtk).

There is no undo in a text-edit-pane, including the IDE editor. The
Windows control supports this internally but the GTK control presently
does not. It's probably not feasible to implement this in CG because
CG isn't aware of everything that happens inside the control.

You can use the File | Revert to Saved command in the IDE Editor
to back up to the point where you most recently saved a file.

We document that user-scroll is called for application side effects
whenever the user makes an interactive scrolling gesture, but on GTK
it is not possible to find the user-scroll arguments to pass, so it is
not called at all on GTK.

If you supplied a user-scroll method to override the default scroll
increments and call either scroll-to or scroll directly, then instead
of doing that you could supply methods for the new generic function
scroll-increment, which will be called on all platforms whenever
the user interactively does a page scroll (scrollbar body) or line
scroll (scrollbar arrow) on a non-widget window.

Here are some issues that you may generally need to keep in mind when
writing CG code for GTK. These are mainly things that cannot work
quite as they do on Microsoft Windows or as currently documented.

If you load the CG fasl files and it does not find loadgtk20.cl and
the rest of the GTK foreign function interface in a "gtk" subdirectory
of the directory that contains the lisp executable, then a break will
happen that tells you to set excl:*gtk-root* to the GTK FFI directory.

If you are using existing CG code from the Windows platform on CG,
then CG will map some common Windows font face names to GTK font face
names automatically. The mapping may not produce a desirable font,
though, so you may need to conditionalize your font face names using
#+mswindows and #+gtk.

Note that GTK appears to use its own fonts rather then the X server's
fonts, and many of them do not look very good at some sizes,
especially smaller sizes. (The non-bold fonts are too thin, while the
bold fonts have uneven stroke width.) It may take a fair amount of
trial-and-error to find pleasing fonts.

You can't count on all GTK installations having any particular
font. For example, we have one machine that does not have
"Adobe Courier" while another does not have "Courier". So an
application that you distribute should probably search the
list returned by (font-faces (screen*system*)) for the first
suitable font face that's found on that machine.

Font sizes may now be non-integers. This was done mostly to allow
non-integer CG font pixel sizes to map to integral point sizes, where
the fonts seem to look nicer on GTK.

This next problem applies only to GTK 2.4; this should no longer
be a concern in CG under GTK 2.6 and later:
In order for fonts to draw at the requested pixel size on GTK, you
must go to the window manager's Control Center (or equivalent) and
change "Fonts | Details | Resolution / dots per inch" to the proper
magic value. (In Gnome 2.0 this is instead under Start Menu |
Preferences.) The GTK docs say only that 96 is typically the
appropriate value for a display (monitor). Our experimentation
indicates that a font resolution of 96 is appropriate when the screen
resolution is 1280 by 1024, and 75 is good when the screen resolution
is 1024 by 768. But keep in mind that your end users may use
different settings, so it's best to call font-line-height to see how
big the fonts will really be drawn.

Some widgets that are children of GTK dialogs (such as the File
dialog) or of children of complex GTK widgets will use default GTK
fonts rather than CG defaults. The size of these fonts can depend on
your Control Center font choices or on your ~/.gtkrc file.

If an application uses many different fonts, the redisplay of windows
can slow down greatly. From the behavior that we see, our impression
is that the X server is caching all of the pixel data of the fonts
that have most recently been used, and if all of the fonts that
an application frequently uses do not fit into the X server's
cache, then a lot of time is spent reloading font data that has
been replaced by more recently used fonts.

On the developer's
machine, for example, about 16 fonts will typically fit (though it
depends on the particular fonts being used), and so if a window
uses 16 fonts then there is no problem, but if it uses 17 fonts,
then every time it draws the next font it must load it again due
it having been displaced by the previously drawn font, and this
can cause the redisplay to take a few seconds.

So an application should minimize the variety of fonts that it
uses simultaneously. Note that a different size or boldness of
the same font face, for example, is still a different font.

On Windows, events arrive in the process that created the window for
the event, and so events generally are handled in the creation-process
of a Window. This does not work on virtual threads platforms, which
includes our Linux/Unix lisps currently, because there is a single
event queue for the single real OS thread, which leads to confusion if
multiple lisp processes read from the single queue. So on virtual threads
platforms CG uses a single process (called "CG Event Handler") to
handle all events. This should not be a porting issue for most
applications, but would be if you depend on code to run in particular
CG processes.

If you are calling process-pending-events in processes other than the
CG event handler and confusion results due to multiple processes
alternately handling events from the single queue, then you might try
calling process-pending-events-if-event-handler instead, which does
nothing unless the calling process is the single event handler
process.

On virtual threads it is not feasible for event-handling to continue
being done inside a process-wait, and so all event handling will hang
if the event-handling process calls process-wait. This is an
important issue because most application code generally runs in this
process, because application code is generally triggered by mouse
clicks and keystrokes that are handled as events.

We have exported the function cg-process-wait that you could call in a
CG application in place of calling process-wait. (It is not clear if this
is the final solution that we will offer.) In most cases this
function simply calls process-wait, but when called in the single CG
event-handling process on a virtual threads platform it will instead
enter its own loop where it calls process-pending-events, then the
wait function, and then (sleep 0.1) repeatedly until the wait function
returns true. It also handles any tasks that were queued by calls to
post-funcall-in-cg-process.

You might alternately want to pass tasks that might call process-wait
to another process by calling post-funcall-in-cg-process. The IDE
uses that function to pass tasks between the CG event handler process
and the IDE listener processes, for example.

If you create a non-child window that has an owner window, GTK will
keep the owned window in front of the owner and will shrink the owned
window with the owner, as it should. But it will allow windows of other
applications to come between the owned window and its owner in the
occlusion stack, and the window manager will have a separate taskbar
button for each top-level owned window.

Therefore, we recommend converting the non-child owned windows (other
than modal dialogs) in your applications into child windows. We have
done this to the IDE by turning its owner window into a parent window.
(You could turn it back into an owner window by setting the
use-ide-parent-windowconfiguration option to nil before starting up
the IDE, but it may not work well on GTK.)

Another reason not to use separate top-level windows is that there
seems to be no way to programmatically move the keyboard focus to a
different top-level window, unless the all-knowing window manager is
in the mood to move it there.

3.9 Top-level windows are bigger than requested due to the window manager
frame.

In X the window manager officially gets to control where it puts a new
top-level window. It will generally put them where you ask, but will
wrap a border of unknown size around the window. In CG, the window
will generally appear with the top left corner of the window manager
frame at the requested top left position, but the window will be
larger than the requested exterior by the size of the window manager
frame.

Thereafter, retrieving or changing the exterior or interior of a
top-level window may work according to the CG design, though it is
very tricky to make this work accurately due to the X philosophy where
an application is not supposed to care where the exteriors of its
top-level windows are. Child windows, on the other hand, are
completely under CG's control.

A top-level window may not have the set of frame buttons (for
maximizing, minimizing, and closing) that you requested if the
window manager does not obey CG's request to add or remove
particular buttons.

A top-level window will never have the
"question mark" help button. CG implements this button for child
windows (to emulate this Microsoft Windows feature), but cannot
do so in window manager frames for top-level windows.

Calling select-window on a window in an application that is not
the currently selected application may produce different results
with different window managers. On the developer's machine, it
brings the application to the front, but does not move the
keyboard focus to it, and so the user must still use either a
mouse click or an alt-tab gesture to give the application the
keyboard focus.

It was intended that an application could set
*use-window-manager-frames* to nil to cause top-level windows
to use Common Graphics title bars and borders rather than
window manager title bars and borders, perhaps to avoid
the unpredictability of arbitrary window managers. But this
option leads to focusing problems that do not appear to be
resolvable, so we expect to unexport this variable in the next
release.

Most of the keystrokes that combine a function key with the alt key
(plus perhaps other shift keys) are grabbed either by Linux or by
Gnome's default shortcuts, and CG cannot intercept them. For
compatibility with existing CG code, CG will automatically map these
keystrokes to other ones whenever they are specified as keyboard
shortcuts.

The general rule is that if a menu-bar shortcut includes both a
function key and the alt key, then the corresponding numeral key is
used on GTK instead of the function key. So alt-F1 will be converted
automatically to alt-1, for example. As special cases, F10 maps to
the zero key, F11 to the minus key, and F12 to the equals key.

This affects the IDE menu-bar, where for example the Run | Trace
Dialog command becomes alt-8, while the Run | Trace command is still
F8. Check the shortcuts printed in the menu-bar menus as needed.

If you happen to suspend the X server accidentally with a keystroke
like control-alt-F8, you can get it back with control-alt-F7.

Also, Gnome uses control-alt-D by default to iconize all applications,
so Build Project Distribution is control-alt-Q on GTK.

GTK appears to grab the F10 key as a special case to show the
leftmost menu on the title-bar of the top-level window, if any.
To handle the F10 key (with no shift keys), you must add a method
to the generic function handle-f10.

Only the :text format of the function clipboard-object
is supported for passing information
on the system clipboard between lisp and other applications.
The :pixmap format may be supportable in the future, but the
:rich-text format (or formatted text in general) does not
appear to be supportable.

The main IDE area is scrollable when the IDE parent window is used.
There are keyboard shortcuts on the View | Manage Windows menu to
scroll it quickly with the keyboard.

The Background Window does not appear on the View menu when using a
single IDE parent window, and in its place is a Maximize IDE command
to make the IDE fill the screen. The maximization state will be
saved in your prefs file so that the IDE starts up maximized if it
was maximized when you last exited.

Due to the way event-handling must be done on GTK, there is a tradeoff
between how quicky CG timers can be handled and how much time is
consumed by switching to the CG event-handling process to check
for timer events. The variable *cg-timer-resolution*
can be adjusted to adjust this tradeoff. The default value is 0.1.
This means that CG will check for timer events every tenth of a second,
and otherwise sit in a call to mp:wait-for-input-available to wait
for GTK events as other processes run. The variable could be set
to a smaller value if you need CG timer events to be handled more
frequently than that, though this makes other processes less responsive.
Or it could be set to a larger value if you aren't using timers
to perhaps make other processes more efficient.

In keeping with unix style, save-options-to-user-specific-file
defaults to true on Linux/Unix, and so IDE preferences will normally
be saved in the file ~/allegro-prefs-foo.cl, where foo is
the name of the machine on which lisp is running. Including the
machine name allows a different options file to be saved for each
machine on which you run lisp, where things such as pathnames and
screen resolution may be different.

3.20 A standalone app that's run from the IDE takes over the emacs listener.

When you generate a standalone app from a project in the IDE (see build-project),
and run the new standalone app directly from the IDE when the modal dialog
offers to do so, then the standalone app is a subprocess of the IDE
and inherits its standard i/o streams from the IDE. This means that
when a break occurs in the standalone app, it will print to the same
emacs buffer that the IDE's Initial Lisp Listener process uses. Both
processes would normally then be reading from this single emacs
buffer, though the IDE would probably take precedence and prevent you
from debugging the standalone app.

To avoid that scenario, the IDE makes the Initial Lisp Listener
process go into a wait state until the standalone app exits, so that
all interaction in its emacs listener buffer will be with the
standalone app. When the standalone app exits, the emacs buffer will
revert to being a listener in the development lisp.

This does NOT apply to running the standalone app from outside the
IDE, such as from a unix terminal.

3.21 You must use pixmap objects rather than their lower-level components.

The separate texture, texture-info, and pixmap-handle objects have
been deprecated for several releases in favor of the newer single
pixmap object. On GTK it was not feasible to make the older separate
objects work completely, so you should convert any remaining textures
in your apps into pixmaps.

If a pixmap has a mask and you draw it at a size other than the size
at which it is defined, then the masking will not be done. We don't
see a feasible way to implement this on GTK.

For picture-buttons we internally create and cache a stretched mask to
make this work, so perhaps we could work out a way to do this when
drawing pixmaps so that the slowness of creating the mask at the
stretched size would happen only the first time a pixmap is drawn at a
particular size.

When you invoke a modal dialog, CG is currently avoiding disabling
event-handling on other windows because it was quite slow. The
slowness seems to be when GTK redraws all of its widgets in a
grayed-out style.

To tell a menu-item to draw a check mark at the left of its label by
calling (setf selected) or passing :selected t when creating it, you
must first declare the menu-item to be checkable by passing
:checkable t when creating it.

The reason is that GTK will draw a box for the check mark at all
times, and leave room for it, so it must know at creation time if you
might check it. Passing :checkable t will have no effect on the
Windows platform, where all menu-items are checkable.

3.28 The list-view control has only "report" view, and will not display
images.

We are using the list-view control provided by GTK, and it does not
support the small images at the left of each item as the Windows
control does, or the views that show icons only. We could support
those features on GTK only by writing the control from scratch, if
there were sufficient demand.

As of GTK 2.4, a button widget (that is, an instance of the CG
"button" class in particular) appears to have a hardcoded margin of 8
pixels on each side between the edge of the button and where the label
is drawn. If the label text overlaps this margin, it gets clipped
there.

To prevent existing CG code from the Windows platform from clipping
most or all of the text of button widgets, CG on GTK currently makes a
button widget 4 pixels larger in each direction than requested. In
most cases this is hopefully OK since the usual custom is not to place
button widgets directly against other widgets or the edge of the
parent.

You may still need to tweak the positioning and size of button widgets
due to this curious design of the GTK button widget. Eventually we
could implement a button completely in CG to avoid this problem.

A quick test on GTK 2.6 appeared to show that GTK buttons no longer
have this large clipping margin, so we may contionalize this hack
to gtk 2.4.

You can scroll a tab-control quickly by holding the mouse button down
on the scroll arrow, but only if the widget's focus-on-click property
is true, since otherwise CG will move the keyboard focus to a widget
on a tab.

If you draw on the screen (over all windows) when calling functions
such as get-line, then garbage may be left on the screen due to GTK
widgets redrawing themselves as the mouse passes over them.

We don't see a good solution for this, other than doing rubber-banding
only in a window rather than on the screen, though that alternative
does not allow drawing the rubber banding line over child windows of
the specified window.

3.34 The wrapping property doesn't work in check-boxes and radio-buttons.

If the wrapping property is turned on for a check-box or radio-button,
the text will not wrap at spaces where needed to prevent the text from
being clipped at the right edge of the widget.

You can, however, add explicit newline characters into the title string,
and the text will always wrap there.

We could internally use a separate gtk label widget for the title, since
a label widget does support the wrapping property. But then they would
no longer act as a single widget, where you can for example click on the
label area to toggle the value, and the background of the whole widget
changes color when you move over the check box or the label.

To fix this definitively we would need to implement a check-box widget
from scratch, unless GTK adds support for this feature.

If you turn on the click-off property of a radio-button, you still
can't turn off a radio-button by clicking on it when it is turned on.
This is partly due to the general rule where you can't turn off all
of the radio-buttons in a cluster in any way. This is how GTK designed
the widget apparently.

3.37 The HTML widget needs to know where the Mozilla GTK libraries are.

If you use the IDE's help facility or create an html-widget and the variable
excl:*mozilla-library-path* is not set to the directory containing the
libraries for the Mozilla GTK widget, then a break will occur telling
you to set that variable.

In a SuSE installation, for example, the libraries are typically at a path
such as /opt/mozilla/lib/. The SuSE "mozilla-dev" rpm package must be
installed for these libraries to exist.

(These appear to be limitation's of Mozilla's HTML GTK widget.
Perhaps they will improve on this situation in later releases,
though the web page for this control shows no recent activity.)

You can't bring the parent of the HTML widget to the front
by clicking on the HTML widget itself, because CG's callbacks
for that event do not get called. You need to click on
the parent directly (such as the title-bar of the IDE's help
window).

The HTML browser will not put the keyboard focus into the HTML
widget when the browser is first created, for scrolling with
the keyboard. It will do so thereafter whenever the browser
is selected, including when it is reshown after being hidden,
or when clicking it. (Closing the IDE's help dialog
really just hides it.)

The default fixed-width font comes out very small on the developer's
machine, and there is no way to set preferences for this as you can in a
full HTML browser application. You may want to specify explicit
font sizes when using this control in an application.

There is apparently no way to search for a string in the
displayed HTML page.

The bypass-cache and bypass-proxy arguments to html-widget-reload
do not do anything. They were originally provided for the
built-in reload function of the GtkMozEmbed control, but that
function does not appear to do anything, and so html-widget-reload
simply visits the current uri again the usual way.

We have not found a way to ask whether a key is really down now,
and so key-is-down-p behaves just like key-was-down-p when called
on GTK. And neither of these functions return the second value,
which indicates whether the key has been pressed since the previous
call.

The box that is returned by the functions clipping-box and
nclipping-box will exclude any part of the window that is covered by
other windows on the Windows platform, but will not exclude these
areas on GTK.

3.44 Some GTK widgets can't have an arbitrary background or foreground color.

This includes the multi-line-editable-text, which the IDE sometimes
uses as a faux static-text with a scrollbar, and so the background
color is not appropriate, such as in the IDE Intro guide dialog.
Perhaps there is a way to control this by formatting the text, but we
have not yet delved into text formatting.

On GTK, ask-user-for-font and pop-up-font-dialog ignore the following
arguments: stream-for-font, fixed-width-only-p, minimum-size,
maximum-size, and initial-point-size. The dialog provided by GTK
has no options for these.

The variable *gtk-compatibility-warning-action* is provided to tell CG
what to do when your CG code calls something that can't be done on the
GTK platform. The default value is :warn, which simply prints a
warning. Changing the value to :error would cause a break to occur so
that you can look at the stack backtrace and see which function of
yours is calling the incompatible CG function. Setting the variable
to nil would suppress the compatibility warnings.

[We have seen (or heard of) this problem only on a single machine,
so please tell us if you see it.]

Sometimes many button widgets will begin drawing themselves entirely
black in their upper-left halves, along a diagonal, plus in their
label area. The symptom can happen even on buttons inside GTK dialogs,
such as the standard file dialog, which CG does not access at all. So it's
unclear how CG could be causing this problem, or how to debug it.

If anyone can find a way to reliably reproduce this one, then please
tell us.

[We haven't seen this recently, but here's how to recover
if it does happen.]

If CG windows stop redrawing their interiors and there is no response
to mouse clicks or keypresses, then the CG Event Handler process is
hung. If it happens, you can usually free things up by going into the emacs
listener, focusing on the "CG Event Handler" process, and resetting it
with these commands:

If the default font is larger on GTK than it was on Windows, this is
causing some pieces of text in IDE widgets to be chopped off. This
probably happens only prior to Pango 1.8 (typically included with
GTK 2.6), when CG could not determine the real pixel size of a font.

If you request a vertical or horizontal scrollbar for an OS widget
(one provided by GTK) such as an item-list or a
multi-line-editable-text, then the scrollbar(s) will be visible all of
the time, even when there is nothing scrolled out of view. You may
need to make item-lists, for example, in your application somewhat
wider to allow for this.

These GTK widgets do provide an option for the scrollbars to turn off
automatically when not needed, but when we enable this option a crash
occurs when the scrollbar turns itself off. This happens
asynchronously later, when some event comes in that we have failed to
track down, but we hope to find it eventually.

When you click on a static-text, the parent (only) gets the events.
When you click on a static-picture, both it and the parent get the
events.

4.7 Dismissing the inspector's "Invalid Value" dialog can wipe out the value.

If you type an invalid value and a dialog appears to tell you that
the value is invalid and you press the space bar to dismiss the
dialog, the space also gets typed into the inspector and wipes out
the current value on the selected row.

If you specify the simple-click-toggle option of a multi-item-list
widget, then doing a simple left click on an item that is already
selected will deselect all other items rather than deselecting only
the clicked item as CG specifies.

This affects some IDE dialogs such as the list of included modules in
the Project Manager.

The functions down-keys, down-key-names, and key-is-down-p will always
claim that the alt key is not down. CG is currently doing this on
purpose to avoid a problem where an alt-tab gesture sends us the event
for pressing the key but not for releasing it, leaving CG believing
that the key is still down.

The ask-user-for-new-or-existing-directory dialog can access non-local
directories via links, but will not show all networked machines under
the /net item. The non-unix-expert implementor isn't sure whether
that's important or feasible.

This is judging from the Navigator example. In general timers
are working fine though. We haven't looked into the drawable
at all yet; it just happens to be mostly working.

4.13 The Return key in the listener history drop-down pastes the wrong item.

If you drop the listener history list and use the down arrow key to
move to a different item and press the Enter key, it pastes the
originally selected item rather than the focused item. For now, use
the spacebar instead to correctly pick the focused item.

4.14 Sometimes an IDE listener ends up with the prompt scrolled out of view.

This can happen for example when resizing the Debug Window, for
example. Sometimes if something is printed to the listener and you
use the keyboard to scroll to the bottom of the text, it still will
not scroll to the bottom if the text cursor was already at the end.

The functions fontmetrics and nfontmetrics, as well as accessors of
them such as font-height, do not seem to correspond to reality. These
values are coming directly from GTK, and we don't know how to convert
them to meaningful values. Call line-height on a stream to find out
how tall it is really drawing its current font, or call
font-line-height directly on the font.

If you click on the inspector's history list and then click again in
the same place to undrop the outline without selecting an item, then
the outline drops down again. Other dropping outlines do not have
this problem.

There are now so many child packages in CG and the IDE that the
cumbersome scrolling technique of GTK menus takes way too long.
Perhaps we should not list all of those child packages, and
make the parent package work for symbols in them.

Lots of warnings are still being printed by GTK to the Emacs Listener.
We will be pursuing all of these eventually, though they take a while
to track down, and at least some of them can occur with the GTK
utility dialogs, for example, where it does not appear that CG
can be at fault.