[otaylor redhat com] Re: Multiple Displays
- From: Owen Taylor <otaylor redhat com>
- To: gtk-devel-list gnome org
- Subject: [otaylor redhat com] Re: Multiple Displays
- Date: 24 Oct 2000 19:00:28 -0400
To give some context to the email I just forwarded, here is
my original mail that gave my ideas about the situation.
--- Begin Message ---
- From: otaylor redhat com
- To: colin stephenson <colin stephenson ireland sun com>
- Cc: Havoc Pennington <hp redhat com>, Mary Dwyer <Mary Dwyer ireland sun com>
- Subject: Re: Multiple Displays
- Date: 10 Oct 2000 18:18:26 -0400
>From an API standpoint, the first thing to do is to add a GdkDisplay *
object that represents a display.
I'm not sure what the best approach is to handling multiple screens
on the same display - one approach would be to simple force
a separate display connection for each screen.
This is the simplest from the point of view of the application
programmer, though it has the disadvantage that things like
X selections and fonts that are shared across displays don't
get handled as well as they could be.
The other way to do it would be to have some call like
gdk_display_list_root_windows(), and associate things like
the default visual with the GdkWindow * for the root window.
I don't really want to have a separate GdkScreen object.
This object should be a GObject (in particular, setting user
data on this will probably be a pretty common operation as a
way of storing per-display data.)
The way it should probably work is that the object should be defined
completely in the port-specific directory and the structure should not
be public - this means that it won't be possible to derive from
GdkDisplay, but I don't think that really makes a lot of sense
Then you need to decide whether the initialization API should
gtk_init (&argc, &argv);
GdkDisplay *gdk_display_get_default ();
GdkDisplay *gdk_display_open (const char *display_name);
void gdk_display_close (GdkDisplay *display);
GdkDisplay *gtk_init_for_display (&argc, &argv, const char *display_name);
void gdk_display_close (GdkDisplay *display);
That is, whether there is a separate concept of initializating
GDK and opening a display or not. My guess would be that the
first is better, since there are some parts of GDK that are
cross display, such as:
- Debug options
- atom assignment
- Xlib error handling
At the same time, you need to decide whether you want to try
and make the GDK mutex used for threading lock all displays
or only a single one. My guess is that you need to lock all
displays, since it is also used to lock global data in GTK+.
(The amount of global data in GTK+ will decrease a lot with
GObject, but there will still be some there.)
I made a list of functions that need fixing for multiple displays
some time ago and put it into:
There are quite a few functions in there (49 of them) that need
a variant for multiple display use -
void gdk_beep (void);
Needs to have another function:
void gdk_display_beep (GdkDisplay *display);
GdkCursor* gdk_cursor_new (GdkCursorType cursor_type);
needs to have a function:
GdkCursor* gdk_cursor_new_for_display (GdkDisplay *display,
Added. Or possibly:
gdk_display_create_cursor (GdkDisplay *display,
But I think that less nice, since it breaks up the logical
organization of all the GdkCursor functions together. I think my
general strategy would be that:
* Functions like gdk_beep() that are not currently namespaced
beyond "gdk" should map to gdk_display_*
* Constructors should get a _for_display() variant.
* Namespaced functions that are not constructors such as
gdk_visual_get_best_depth() probably should get _for_display()
variant, though I'm a little less sure about this then
the previous bullet.
The list needs some updating. Scanning it over, the things I
GdkRegion* gdk_region_new (void);
Regions were never per display
GdkAtom gdk_atom_intern (const gchar *atom_name,
gchar* gdk_atom_name (GdkAtom atom);
A suggestion of Havoc's that probably is the right way to do
it here is to do atom assignment within the library, and then
itern as necessary for each display, with an internal call such
Atom gdk_atom_to_x_atom (GdkDisplay *display,
This will maintain a lot more backwards compatibility than forcing
all code to worry about the fact that atoms are per-display and
don't map 1 <=> 1 onto strings.
gint gdk_im_ready (void);
void gdk_im_end (void);
GdkIC* gdk_ic_new (GdkICAttr *attr,
All this IM support code in GDK is going away, though the replacement
IM module code will need vetting for proper multiple display
GList *gdk_input_list_devices (void);
void gdk_input_set_source (guint32 deviceid,
gint gdk_input_set_mode (guint32 deviceid,
void gdk_input_set_axes (guint32 deviceid,
void gdk_input_set_key (guint32 deviceid,
This gets much better with the new extended input device API
which uses GdkDevice * instead of device IDs - you only need
to add to:
/* Returns a list of GdkDevice * */
GList * gdk_devices_list (void);
GList * gdk_devices_list_for-display (GdkDisplay *display);
(Or, perhaps, simply have gdk_devices_list (GdkDisplay *display),
since there is no backwards compatibility concern here.)
gint gdk_text_property_to_text_list (GdkAtom encoding, gint format,
guchar *text, gint length,
void gdk_free_text_list (gchar **list);
gint gdk_string_to_compound_text (gchar *str,
GdkAtom *encoding, gint *format,
guchar **ctext, gint *length);
void gdk_free_compound_text (guchar *ctext);
I think the only dependency here is on the GdkAtom, so these
probably don't need per-display handling if GdkAtom is done
void gdk_key_repeat_disable (void);
void gdk_key_repeat_restore (void);
These functions are scheduled for death.
void gdk_error_trap_push (void);
gint gdk_error_trap_pop (void);
I'm sure there are also functions that need to be added to the
list - one that comes to mind is:
PangoContext *gdk_pango_context_get (void);
Though any additions are new API, and are thus candidates for
treating like discussed for gdk_devices_list() above.
So, that's an overview of what needs to be done at the GDK API
level. In GTK+, the API changes should be smaller:
*- You need to be able to create GtkWindow and all descendents,
such as GtkDialog for particular displays. Also GtkInvisible.
This could be done push/pop() like gtk_widget_push_colormap(),
though I think an explicit API - something like:
GtkWidget *gtk_window_new_for_root (GdkWidow *root);
may be better.
* GtkClipboard needs to become per-display.
* Selections need to be per-display. DND should be OK, since
we have GdkDragContext to hold the display pointer.
* There probably should be convenience functions in GtkWidget for
getting anything that is frequently per-display, such as:
GtkClipboard *gtk_widget_widget_get_clipboard (GtkWidget *widget,
The display for a widget needs to be formalized - the simplest
thing to say is that it is undefined/NULL until it is added into
widget heirarchy, and then it is the display for the GtkWindow
at the top of the hierarchy.
There probably is some more stuff which isn't occuring to me right
The API changes are the part that is important to get done real
soon, but there obviously is a lot of underlying implementation
work to be done as well.
- Every use of global data in GTK+ and GDK needs to be examined
to see if the data is really per-display, not global.
Per display data probably usually should be made user data
on the GdkDisplay object; by that or some other mechanism it
needs to be cleaned up when the display is closed.
- All uses of such global variables such as gdk_display/GDK_DISPLAY(),
GDK_ROOT_PARENT(), etc, needs to to be located and eliminated
in one way or another.
- All the GDK and GTK+ code needs to be examined for use of the
functions that are getting per-display variants, and the
per-display variants need to be used instead.
- The assumption that a GdkPixmap can be used with any visual
of the same depth needs to be rooted out. (It must be used
with the same display and in fact screen.)
I know that the GtkStyle code, and also (the deprecated, perhaps
going to be removed) GtkTree code have this assumption in them.
And of course, test cases need to be written that create widget on
different displays, different screens, with different depths, to find
all the assumptions that are being made that were missed on
the first pass.
OK, I know that is both a lot of stuff to take in and not nearly
enough stuff to completely describe everything that needs to
be done, but I hope it will provide a start at getting this
I think the strategy I would suggest is;
1) Write up detailed plan with a full list of planned API additions
and changes. (Feel free to steal from this message as much as you
want), send that to gtk-devel-list. I'll try to get back with
comments on that quickly.
Going over GDK for this should provide some familiarity with
Feel free to ask me (or gtk-devel-list) questions as needed;
as mentioned above, I'll be gone for the rest of this week,
but may get a chance to check email occasionally.
2) Make an initial pass at implementation, with a concentration
on the public API.
3) Finish up implementation, test.
P.S. - One thing to idly think about that for future versions of GTK+
we might eventually want to have the ability to open multiple
"displays" on different targets; e.g., Linux Framebuffer and
X. This is a very long term goal, and I wouldn't worry about it
much, but as a philosophical thing, it might be nice if the API
didn't rule it out.
--- End Message ---
] [Thread Prev