[Erwann Chenede <Erwann Chenede ireland sun com>] Multihead support for GTK



--- Begin Message ---
Hi Owen, Havoc,

Matt Keenan and myself (Erwann Chenede) are looking into multihead support for 
gtk. We are not gtk/gdk expert but we have a good amount of experience in 
Motif and XView toolkits.

-------

Sorry for the response delay, I didn't manage to reply earlier as I was at a 
conference all last week.

Below, you'll find a quick description of how the multihead handling was 
implemented in XView  & Motif and after my general idea on howto implement it
in gdk.

Our intent, here, is to start the discussion (as we are not gdk/gtk expert) and 
try to reach a consensus on what could be a good design for multihead handling.

If you feel that this discussion belongs more to gtk-devel-list feel free to 
forward it to the list.

Thanks.

--------

So we've looked at these 2 toolkit to see how they implemented multihead 
support.

Here is a small sum-up :

- In OpenWindows/XView the multiple screen handling works like this :

  XView uses its own Xv_Screen object. This includes information such as screen 
  no. of the root window, server, colormap, etc, and is separate from the X11 
  screen data type.

  In XView first need to get a handle for the server object (Xv_Server) by 
  initializing the toolkit (using xv_init function).
  The server object handle is used to retrieve a handle to a Xv_Screen object - 
  the screen required is specified using the SERVER_NTH_SCREEN attribute

  eg Xv_Screen screen_0=(Xv_Screen)xv_get(server, SERVER_NTH_SCREEN, 0);
  will return a handle to screen 0.

  Once you have a screen, you can xv_get its root window, and once you have the 
  root window you can start creating frames etc.

  There is no XView display object.  To obtain a reference to the X11 Display 
  object you get the value of the XV_DISPLAY attribute (available from most 
  vXView objects) eg Display *dpy=(Display *)xv_get(frame, XV_DISPLAY);

- Here is how Motif/Xt handles the multiple screens and multiple display :

  One connection is opened per display (XOpenDisplay) then initialized (by
  XtDisplayInitialize).
  
  To run an app on more than one screen within a display, each widget got a
  a "screen" resource (as each widget is using the same display connection).
  So display a widget to a specific screen we just need to set the 
  XmNScreen resource to the desired screen number and realize it.
  

Here is my idea on how multihead support could be design.
Yeap, there's not much details in it as I wanted to know if it made sense for 
you
or if I've lost it completely...


For the "Multiheadization" of gdk, each GdkWindow we'll need to know 
which display and which screen the gdkDrawable is referring to.

We'll need to keep track of all the display opened (with associated 
data, visual, num of screen, etc) and each gdk "object" (from beep to
windows) while need info about both display and screen number to be displayed
on. 

One approached could be to create a GdkConnection to abstract the concept of
Display and screen (and other info I guess). All screen-dependent gdk object 
would inherit that GdkConnection.
All the multihead support could be grouped around the GdkConnection object.
All multihead interaction would go through this object.

e.g to set the desired screen :

gdk_screen_set(GDK_WINDOW(window)->connection,0).

If not specified explicitly GdkConnection would default the current screen.
This approach could minimize the API change needed.
The API change would be concentrated at the gdk level and at the Gtk 
level would not have to change much.

For the initialization, It could be good to have a list of X display open 
to minimize redundancy within the GdkConnection objects.



------


Following are some comments and questions about the email you sent to 
Colin Stephenson.
   

[...]
   
> 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.

I don't if it is a good idea as a display (according to the Xlib docs)
is an abstraction representing the input (keyboard and pointing device)
and output (one or more screen). 

So if multihead display is supported an app should be able to display
widgets not only on multiple screens but also on multiple machine 
as an Xserver usually only as one display...

[...]

> 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.)

I guess whatever the name of the object that will provide the Display/Screen,
it will have to be a GObject.

> 
> 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
> anyways.
> 

I agree with you but, should we try to support that for windows also 
or will it need a specific design and implem. for each port ?
Anyway I guess our main concern is to make it work on X...


> Then you need to decide whether the initialization API should
> be:
> 
>  gtk_init (&argc, &argv);
> 
>  GdkDisplay *gdk_display_get_default ();
>  GdkDisplay *gdk_display_open        (const char *display_name);
>  void        gdk_display_close       (GdkDisplay *display);
> 
> Or, alternatively:
> 
>  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
> 

Yes, the display opening has to be separated from the GDK initialization
as a developer might went to open an extra display at anytime while the
app is running.

> 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+.

I don't really understand the problem here, could you give me 
some background on threading in GDK.

> 
> (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:
> 
>  gtk+/gdk/TODO
> 
> There are quite a few functions in there (49 of them) that need
> a variant for multiple display use -
> 
> For instance:
> 
>   void gdk_beep (void);
> 
> Needs to have another function:
> 
>   void gdk_display_beep (GdkDisplay *display);
> 
> Added. And:
> 
>   GdkCursor* gdk_cursor_new              (GdkCursorType   cursor_type);
> 
> needs to have a function:
> 
>   GdkCursor* gdk_cursor_new_for_display (GdkDisplay    *display,
>                                          GdkCursorType  cursor_type);
> Added. Or possibly:
> 
>   gdk_display_create_cursor (GdkDisplay    *display,
>                              GdkCursorType *cursor_type);
> 
> 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.
> 

I think we'll need to add a _for_display() Constructor and convienance 
functions, the original function could default to the current Display/Screen.

[...]

> 
>  GdkAtom gdk_atom_intern            (const gchar *atom_name,
>                                      gint         only_if_exists);
>  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
> as:
> 
>  Atom gdk_atom_to_x_atom (GdkDisplay *display,
>                           GdkAtom    *atom);
> 
> 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.
>

 I don't get it. Are you saying that we have to have only one set of 
 atom for every screen of every display ? Why ? What are the problems 
 with backward compatibility ? 

[...]

> 
> 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.

What do you really mean by user data ?

> 
>  - 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.)
> 

Yes, this might be tricky 

>    I know that the GtkStyle code, and also (the deprecated, perhaps
>    going to be removed) GtkTree code have this assumption in them.

Yes, GtkStyle could create interesting problems as the Style is not stored
in the X Server as for example X Resources are !

> 
> 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.
> 

I guess our Test Team will come up with some good testcase 

> 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
> going.
> 
> 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
>     the code.
> 
>     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.


Thank you in advance for your responses.

    Erwann

- I speak for myself, not for my employer. -
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  Erwann Chénedé, Sun Microsystems Ireland
  Desktop Applications & Middleware Group
  Phone  : +353 1 8199031        xt: 19031
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~







--- End Message ---


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]