Re: GTK+ Accessibility Proposed API
- From: Havoc Pennington <hp redhat com>
- To: Bill Haneman <Bill Haneman Sun COM>
- Cc: gtk-devel-list gnome org
- Subject: Re: GTK+ Accessibility Proposed API
- Date: 09 Mar 2001 23:34:45 -0500
Hi,
I've gone through the headers and the gtkwidget diffs, I haven't gone
through the .c files yet. So here are a bunch of comments, some
nitpicky, some obvious, etc. These are only my opinions, revising
things before Owen and Tim comment could be dangerous. ;-)
Directory layout: I think "gtk/a11y" isn't a good name for the directory
holding the include files, gtk/ is bad because this is a GTK
dependency not part of GTK, "a11y" is bad because it isn't the name of
the library. Suggest just gaccessible/.
Gaccessible: while I understand the pedantic reasoning that leads to the
lowercase 'a', I think it's ugly, confusing, hard to type, etc., and
also I think there's no way we would introduce a GAccessible if a
Gaccessible was widely used. For GConf I just capitalized the 'c',
which I know annoys Tim, but I like more.
However, I don't think 'Gaccessible' is a good name for the namespace
- it sounds like an interface. Suggest 'Gaccessibility,' or make up a
name in the tradition of Pango. Somewhat prefer the latter, if we can
think of something nice. Or just "accessibility" - no rule that stuff
has to start with G.
You also use 'Gaccessible' as the name of an object - that doesn't
work. It's as if GTK had an object called simply "Gtk". i.e. basically
the name of the object is an empty string. ;-) It should be
GaccessibleAccessible. But that's pretty lame, which is why renaming
the namespace might be good.
gaccessible.h:
For copyright notices, you should use the LGPL notice, but put the
actual copyright holder, in this case I assume that's Sun
Microsystems, instead of Peter/Spencer/Josh. This is a bug in many
current GTK copyright notices.
If the lib is Gaccessible, the include guards shouldn't have the
underscore in __G_ACCESSIBLE
You include gobject/* directly, supposed to include glib-gobject.h or
something like that, I don't remember the exact header.
The GaccessibleRole enum should have its members namespaced.
So GACCESSIBLE_ROLE_ALERT, etc.
Do we need this enum to be extensible? What about widgets added in
other libraries or in enums? You might look at PangoAttributeType
or the recent patch I posted for GtkIconSize to see how to do
an "extensible enum" (GType is also such an enum).
GaccessibleStateEnum should not have "Enum" in its name, and the
members should be namespaced GACCESSIBLE_STATE_ACTIVE
The states that correspond to widget states should probably be named
the same as we name them in GTK+; for example, "sensitive" rather
than "enabled", be sure "active" means GTK_STATE_ACTIVE, and so on.
For both these enums, I think a one-line comment above each member
explaining its meaning would not be out of line. Then it would be
easier for us to know if they correspond to some existing GTK term.
As with the Role enum - does this one need to be extensible to handle
add-on widget collections such as libgnomeui?
The type macros are not quite right in gaccessible.h, which I think
is because the object name is an empty string. However the same
mistake was then cut-and-pasted. So e.g. we should have
GACCESSIBLE_TYPE_HYPERTEXT, not TYPE_GACCESSIBLE_HYPERTEXT. Basic
rule is that all names start with the namespace.
I don't see any real need to forward declare the interfaces in this
file, why not just put those in the appropriate interface-specific
headers?
NUM_POSSIBLE_STATES is not namespaced.
Instead of GaccessibleStateMask, just use GaccessibleStateEnum,
renamed to GaccessibleState. (I personally agree that bitmasks
should be done this way, with a typedef to guint, but it's
inconsistent with all of GTK; we just use the enum type for
the bitmasks).
The _parent member in both instance and class struct need not have an
underscore prefix.
I could use some explanation of what Gaccessible is/does, and why it
contains a bunch of child Gaccessible. It seems you basically
have a tree of these things? My feeling is that the object should
have a more descriptive name, but I can't suggest that name since
I'm not sure what the object does.
We would conventionally say get_n_children() rather than
get_child_count(), I think. The _count() convention is sort of
a Java-ism.
ref_child should IMO be get_child and not increment the reference
count.
I would make the "guint i" into "gint i", on the "unsigned ints are
Evil" principle, Owen will probably agree and Tim will probably
disagree.
Perhaps avoid that issue though; I don't see why the interface
exposes indices. It's not inherently done as an array.
Why not just:
GList* get_children (); /* returns a list of Gaccessible */
Gaccessible* get_parent ();
What is the meaning of the "children_changed" signal?
changed_type passed to that signal should be an enum I'm guessing,
or there should be a comment explaining what sort of value it holds.
Even if we keep the index-based API, suggest removing child_index
from the signal, people can call get_index_in_parent.
GaccessibleInterface: You're missing the "dummy typedef"
passed to methods on this interface (see GtkTreeModel
vs. GtkTreeModelIface). Of course the dummy typedef would be called
Gaccessible which is a different object, so that's a problem. ;-)
This interface to me is "any instance which has_a accessibility
object." I would actually call that GaccessibleAccessible, i.e. a
thing that's accessible. Then perhaps rename current Gaccessible to
GaccessibleInfo, GaccessibleHandle, or something. No good ideas at
the moment. Of course the struct containing the vtable is
GaccessibleAccessibleIface, and GaccessibleAccessible would just be
a dummy typedef.
Note that non-GObject can implement interfaces, so the ref_accessible
method should take a GaccessibleAccessible, not a GObject.
Again I'd make it get_accessible() and not ref the return.
gaccessible_ref_accessible_child(): the "accessible" there seems
redundant, the name of the object (if it existed) would indicate
what kind of child it has.
gaccessible_get_index_in_parent(): the function pointer in the vtable
takes a guint argument, this function does not.
gaccessible_set_parent(): I think gaccessible_add() would be better,
i.e. make the method on the parent, as with gtk_container_add().
But again I'm unclear on why accessibles are in a tree structure,
so I may be wrong on this.
Can children be removed? What's the rationale for why or why not?
The GaccessiblePropertyChangeHandler typedef should be to a function
pointer not a GClosure; if using GClosure, don't use a typedef.
But in general GClosure is only used for language bindings, so if
connect/remove property change handler are C convenience functions,
using GClosure simply makes them less convenient.
That said I tend to doubt that we need convenience functions, people
can just connect to notify on the properties.
For the properties, they should not be namespaced. That is, they
should not begin with accessible_. Properties are just member
variables, right, you wouldn't namespace those with the class name
(because it's done automatically, as with properties).
The comment here talks about Gaccessible*Interface - for some
reason we have the convention to abbreviate these virtual
tables as "Iface", maybe since app programmers aren't supposed
to ever type the name, but anyway should be consistent.
Again see GtkTreeModel/GtkTreeModelIface for example.
The comment describes using interfaces directly by poking around in
the vtable, generally that's not done, since wrapper functions are
provided for each method (which you've done here of course).
The RELATION_CONTROLLED_BY etc. enum should be named and typedef'd,
rather than anonymous, and should have its members in the Gaccessible
namespace.
gaccessible_relation_new() should then take a GaccessibleRelationship
as an arg, not guint.
It isn't obvious to me what state_mask_get/set_name() are used for.
gaccessibleaction.h:
Copyright to Sun
s/__G_ACCESSIBLE/__GACCESSIBLE/
TYPE_GACCESSIBLE_ACTION -> GACCESSIBLE_TYPE_ACTION
I don't see the purpose of the #ifdef _TYPEDEF_GACCESSIBLE_ACTION
guard, but if it's there it should be namespaced.
I'd expect get_count() to be called get_n_actions() instead, in
GTK's own special world.
get_description() should likely return a string by reference,
which means "G_CONST_RETURN gchar*" as the return type.
accessible_action: the comment makes it sounds like this is purely
for notification. Properties shouldn't be used for notification,
only for conceptual "member variables." So you might just want a
signal, unless you can set the actions via this property.
As mentioned above, should be called just "action" not
"accessible_action".
Well, for that matter if it refers to the whole list of actions,
it should be plural, "actions"
gaccessibleeditabletext.h:
Repeat first few comments for gaccessibleaction.h (copyright,
include guards, type macros, _TYPEDEF_ thing, Iface convention)
The methods on this object don't take an instance as one of the
arguments, so they will be tricky to implement. ;-) This is true
of the vtable and also the wrapper functions.
startIndex, etc. are named in javaCaps, should be start_index
suggest that insert_text_at_index simply be insert_text for
consistency with GtkEntry, GtkTextBuffer.
insert_text args should be "gint index, const gchar *text, gint len"
where len can be -1 to insert a nul-terminated string.
You have cut/delete/paste, shouldn't you also have copy?
You can't call a method "delete" because it's a C++ keyword; suggest
delete_text to parallel insert_text, also consistent with
GtkTextBuffer.
gaccessibletext.h:
Repeat first few comments as before.
Potentially big issue here: I think GaccessibleTextDelimiter, and
getting words/sentences/etc. using delimiters, is fundamentally
broken for i18n purposes. The algorithm we use for word/sentence/etc.
boundaries is in pango/pango/break.c,
http://cvs.gnome.org/lxr/source/pango/pango/break.c, delimiters have
no hope of getting this right. Unless a TextDelimiter is a more
sophisticated object than I'm thinking, such as a semantic object
rather than e.g. a list of delimiter chars.
For all methods: we're trying to use the convention that "index"
means "bytes" and "offset"/"position" means "chars". I'm guessing
that chars is most appropriate here (and GtkTextView can't implement
this interface really unless it's chars, though I could fix that
fairly easily at some cost in memory usage). If it's chars,
should probably use "offset"
get_character_after_index: should just be get_character(), and return
the character at that index, i.e. first character for index 0.
Should return a gunichar, not a UTF-8 encoded string.
get_caret_index: we never call it a caret, though we aren't
especially consistent about it. GtkTextView variously says
"insert" or "cursor", GtkEntry uses "position", GtkText just
"point". We probably should call it a caret I guess ;-)
get_text_range(): I'd just call it get_text()
get_row_col_at_index: this seems a bit clunky to me, GtkTextBuffer
uses "line" and "line_offset", I guess "column" is a bit nicer than
"line_offset"
get_character_bounds should perhaps fill in a GdkRectangle, and we'd
usually call it get_character_extents() I think.
You have a comment "why not use accessible_selection" for
get_selected_text, I think the reason is that GaccessibleSelection
is for a list of items, and is probably really inefficient for
characters.
However, I would suggest replacing this function with:
get_selection_bounds (GaccessibleText *text, gint *start, gint *end);
then people can get the selection by getting its bounds, then
calling get_text(). Also, I'd replace
get_selection_end()/get_selection_start() with the single
get_selection_bounds() method.
Aren't you missing a function to get the current number of characters
in the buffer?
For all these methods, -1 should be allowed to indicate "last
character in the buffer", e.g. get_text (text, 0, -1) returns all
text in the buffer.
Same comments as before on the accessible_text and accessible_caret
properties; remove accessible_, and they should only be properties if
you can set them. (Setting these two seems reasonable, though.)
gaccessiblehypertext.h:
Same first few comments as with the other headers.
Whatever GaccessibleHyperLink turns out to be, it'll probably be
a struct or object, so passed around as a pointer.
I'm assuming GaccessibleHyperLink will have a way to get the name,
target, and other info about the link.
Conceivably in C it's easier to have methods on GaccessibleHypertext
that get that info, instead of fooling with a tiny
GaccessibleHyperLink object that will get memory-leaked all the time.
Should probably be Hypertext and Hyperlink or HyperText and
HyperLink, rather than a mixture.
gaccessibleicon.h:
Same first few comments, blah blah.
G_CONST_RETURN on get_icon_description I think, if you are reasonably
sure there will be a description stored somewhere to return a
reference to; else the string would be copied so not const.
Most of the other interfaces seem to lack "setters", such as
set_icon_description(); why does this one have a setter while there's
e.g. no set_hyperlinks(), set_actions(), and that kind of stuff?
set_icon_description(): the gchar* should be const.
get_icon_width(), get_icon_height(): our usual convention would be:
get_icon_size (GaccessibleIcon *icon, gint *width, gint *height);
gaccessibleselection.h:
Same first few comments.
The methods are named incorrectly I think, add_selection() sounds
like it adds a selection, but you are adding _to_ the selection.
It seems odd to me to write selection->add_selection().
Maybe selection->add_item(), selection->clear(),
selection->get_item(), selection->get_n_selected(),
selection->item_is_selected(), selection->remove_item(),
selection->select_all().
As you note in a comment, convenience wrappers missing.
gaccessibletable.h:
(Same first few comments, I'll stop saying this now I guess ;-)
I believe this class is to access what we'd call a "sheet", that is,
a spreadsheet-like widget, while GtkTable is a container widget used
to line up widgets in dialogs and such. So conceivably it should be
renamed to GaccessibleSheet, though I'm not sure it's a big deal. If
it's also used for say GtkTreeView then I could very well be on
crack.
For all methods, "r" and "c" should be spelled out "row" and "column"
I'd change ref_at() to get_item() or get_cell() and use the same name
(item, cell) for the other methods also when appropriate.
I don't understand the get_index_at, get_row_at_index methods. Why
have flat index space in addition to the grid indices? Do these map
to Gaccessible indices? (It's dawning on me that maybe the purpose of
Gaccessible having children is to do these "compound" accessible
objects, such as a table with cells - is that right? If so and we
revise Gaccessible as I suggested to not use indices, these methods
would become I guess get_position (table, Gaccessible *child, gint
*row, gint *column)
get_column_count should maybe be get_n_columns()
ditto for get_row_count
What does get_row_extent_at() do?
I don't understand the get_column_header() method, why does
it return another table?
For get_selected_rows() (and get_selected_columns()) we might
consider:
void get_selected_rows (GAccessibleTable *table,
gint **rows,
gint *n_rows);
The methods starting with is_ should probably have the is_ moved
just before the participle, that is, column_is_selected().
The wrapper functions are missing the "g" at the front, they are just
"accessible_table_ref_at()" etc.
This interface again has "setters", what are those used for? (I can
imagine an accessibility app setting the text in a cell I guess, but
why would a user change say a column title? Or, even if there are
cases where they would, don't we need a mechanism to indicate
whether or not they can? Since most column titles won't be
modifiable by the user.)
gaccessiblevalue.h:
"Value" seems a bit vague, maybe "GaccessibleNumber"?
s/accessible_value/value/
gtkaccessiblefactory.h:
My only question here is what the factory is for - it doesn't look
like it does anything. ;-)
gtkaccessible.h:
Doesn't this need get_widget() and set_widget() methods? (they don't
need to be in the vtable, just "final" methods that can't be
overridden).
GtkWidget changes:
Suggest storing the GtkAccessible in object data instead of
in an instance member, so no space is used unless you're using
the accessibility feature.
There's no reason to put GtkAccessibleFactory in the class struct;
for what Java/C++ would call a class/static variable, we just use
static globals in the .c file.
Since you make GtkWidget implement the GaccessibleInterface which has
the get_accessible() method, I don't think it's right to introduce
another get_accessible() method in GtkWidget, or the wrapper
function gtk_widget_get_accessible().
gtk_widget_class_set_accessible_factory() could just be
gtk_widget_set_accessible_factory (GtkAccessibleFactory *factory),
which sets the global variable. This is the same as a static C++
function, i.e. I'd call it as Gtk::Widget::set_accessible_factory
(factory), with no instance (the class is just a namespace here).
gtkaccessiblecomponent.h:
I could use some docs on what this object represents and when/how
it's used.
Remember to remove inclusion of gtk/gtkdata.h, GtkData is a useless
object I've been meaning to delete.
'typedef gint GaccessibleCursorType' isn't something we'd normally
use - it should be an enum or an int, not an enum-looking int. ;-)
contains() is just syntactic sugar for getting the extents and seeing
if the point is in the extents, so there's no reason to virtualize
it; just write a wrapper function that calls get_extents()
then checks if it's in the extents.
get_bounds() would be get_extents() using our conventions.
get_accessible_at() dangles an ambiguous preposition, suggest
get_accessible_at_point().
get_location() is get_position() with our conventions.
get_location_on_screen() would return the position in root window
coordinates. Suggest maybe calling the parameters root_x root_y to
clarify that.
If set_cursor_type() changes the mouse pointer, it's not
implementable without some larger GTK changes that I can describe if
you want, I was trying to implement gtk_widget_set_cursor() the other
day. If it does something else, probably you should explain it so
we can figure out how to implement.
set_enabled() would be set_sensitive() in GTK terms, and has the
prototype for get_enabled(). Maybe you mean get_enabled()?
If not then get_enabled() seems to be missing.
set_location() should be set_position(), but can't be implemented for
most GtkWidgets, since they are inside containers that determine
their position. So at least there needs to be a way to query whether
this operation is possible?
For set_visible(), the arg should be named "setting" or "visibility"
instead of "b"; also, again not sure this makes sense to implement.
Why would users hide a widget? Probably yet another case of me not
knowing what the method is intended to do. ;-)
We'd call it grab_focus() not request_focus() in GTK
add_focus_listener() is a Java-ism, we'd just have a signal to
connect to.
component_contains() should take x, y, not a GdkPoint.
ditto for component_get_accessible_at()
You seem to have a set_bounds() wrapper but no set_bounds() in the
vtable.
We'd call it set_extents() not set bounds.
As with set_position(), not sure how we'd implement this for widgets
in containers.
OK, I'm tired of typing, you're tired of reading. ;-) Hopefully the
above is constructive. When I'm not understanding how the API is used,
please point that out.
Thanks for working on this stuff, should be a nice addition to GTK.
Havoc
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]