Re: [gdm-list] Patches for multi-seat and multi-display support




> Can you figure out X11_DIR from pkg-config?
Done, thanks for Dan's patch.

> I wouldn't get rid of the Name even if you aren't using it explicitly.
> It was already there after all and we might use it at some point in the future.
> 
> Same with Version.  I feel like it should still be there.  Given we
> weren't using this file before we can probably keep it at 1.0.
Done. 
> 
> >  Hidden=false
> > +# Indicate whether to create this seat or not. If it is set true, then CK will
> > +# not create this seat. Default value is false.
> > +
> > +DisplayType=Local
> > +# Indicate display type which defined in <etc>/ConsoleKit/displays-types.conf
> 
> Comments should appear before the lines they're commenting on, not after.
Done.

> > +DisplayNumbers=0
> > +# Display numbers list, separated by a separator character, typically ';'
> > +# or ','. If want to automatically choose next available display number,
> > +# indicate -1
> I wouldn't allow ';' and ','.  I would just pick one (and I would pick ';').
> The only reason gkeyfile let's you pick, is because when the icon theme spec
> got written no one noticed that desktop files used ; instead of , so it ended
> up getting the wrong one (and when gkeyfile got written we wanted it to work
> for the icon theme files too)
Separator ';' and ',' are from GKeyFile. I did not find any API to only
allow ';'. Can I simply change the comment that only allow ';'? That is
to say, even ',', the list can be recognized by GKeyFile.
> 
> So if I want to configure my system to start two displays at boot up, with
> any display number, I don't care, is it:
> 
> DisplayNumbers=-1;-1;
> 
> ?  That's a little clunky.
After reading the following comments, most of them is about how to
represent seat and display.

I have to say the design
http://wiki.genunix.org/wiki/index.php/design_for_newgdm_consolekit_multiseat_multidisplay is not get well reviewed before coding.
I'd suggest we make a agreement on the configuration files first, then I can go with the right way.

I'd like summarize what your said and work out the updated design for
review, does it sound reasonable?

> > +
> > +TtyDevices=
> > +# Values list to indicate the tty device number, separated by a separator
> > +# character, typically ';' or ','.
> > +# Zero or negative number or no value means choose next available vt number
> So TtyDevices and DisplayNumbers have to always be in sync?  This
> seems very fragile to changes.
Same with above.

> I think we need a separate [Display Entry] that gets tied to a
> particular seat. Then in the .seat file we'd have
> 
> Displays=localdisplay1;localdisplay2;
> 
> or some such.  The display entry file would have what display number
> to use and what tty to use
> (and the absense of those keys would mean "figure it out automatically")
> 
> DisplayType could get moved to the display entry, too.  Or maybe we
> requires all displays at one seat to have the same type, not sure.
Same with above.
> 
> > +
> > +IsConsoles=true
> > +# Values list to indicate whether the give DisplayNumbers are on console
> > +# or not , separated by a separator character, typically ';' or ','.
> That shouldn't be plural.  Maybe "RequiresConsole" would be better?
> If we end up with Displays= above, then we'll need to make sure that
> all the display types in the list
> match in the "RequiresConsole" respect.
Same with above.
> 
> > diff --git a/data/display-types.conf.in b/data/display-types.conf.in
> > new file mode 100644
> > index 0000000..4c4246d
> > --- /dev/null
> > +++ b/data/display-types.conf.in
> > @@ -0,0 +1,27 @@
> > +[Local]
> > +Command= X11_DIR@/Xorg
> > +Arguments=-br -verbose -nolisten tcp
> > +Chooser=false
> > +UseAuth=true
> > +Priority=
> Why is Command and Arguments two separate things?  I'd do this as
> 
> Command= X11_DIR@/Xorg $display -br -verbose -nolisten tcp $vt
> 
> Then $display and $vt would get substituted with whatever display is
> specified in the seat display configuration.
> 
Same with above.
> > +
> > +[RemoteMachine]
> > +Command= X11_DIR@/Xorg
> > +Arguments=-br -verbose -indirect
> > +Chooser=true
> > +UseAuth=true
> > +Priority=
> > +
> > +[LocalVNC]
> > +Command= X11_DIR@/Xvnc
> > +Arguments=-query localhost
> > +Chooser=false
> > +UseAuth=true
> > +Priority=
> > +
> > +[Headless]
> > +Command= X11_DIR@/Xvfb
> > +Chooser=false
> > +Arguments=
> > +UseAuth=true
> > +Priority=
> 
> I'm a little worried that these guys are all getting stuffed into one file.
> Who "owns" the file, the distribution or the sysadmin?  If the distro decides
> to change which command line arguments are passed to the X server is it going
> to have to tell the sysadmin to update the file?
> 
> If you did each entry as a separate file, like you did for seat configuration,
> this will be a lot more managable.  E.g.,
> 
> [Display Type]
> Name=Local
> Description=Configuration to use for local displays
> Command=Xorg $display -br -verbose -nolisten tcp $vt
> Chooser=false
> UseAuth=true
> 
Same with above.

> > --- /dev/null
> > +++ b/src/ck-display-type.c
> > @@ -0,0 +1,425 @@
> [...]
> > +#if __sun
> > +#define CK_PRIO_MIN 0
> > +#define CK_PRIO_MAX (NZERO*2)-1
> > +#define CK_PRIO_DEFAULT NZERO
> > +#else
> > +#include <sys/resource.h>
> > +#define CK_PRIO_MIN PRIO_MIN
> > +#define CK_PRIO_MAX PRIO_MAX
> > +#define CK_PRIO_DEFAULT 0
> > +#endif
> This bit is a little ugly. If priority makes sense to expose at all
> (which I'm not sure about), it should go
> over the wire to display manager in a standard range that isn't os specific.
> Maybe a double in the range 0.0 to 1.0 ?
> 
> Alternatively, maybe we should just have a flag "runs high priority" or
> whatever.  I don't understand the use case for priority, so I don't know the
> answer to this question: "Do values other than minimum, maximum, and normal
> ever make sense to use?"
As Brian said, this feature is dropped for now.

> 
> [...]
> > +static void
> > +_ck_display_type_set_priority (CkDisplayType  *display,
> > +                               int             priority)
> > +{
> > +        /* do some bounds checking */
> > +        if (priority < CK_PRIO_MIN)
> > +                display->priv->priority = CK_PRIO_MIN;
> > +        else if (priority > CK_PRIO_MAX)
> > +                display->priv->priority = CK_PRIO_MAX;
> > +        else
> > +                display->priv->priority = priority;
> > +}
> g_param_spec_int (which you used when creating the property) let's you
> enforce value ranges.
Will be removed since we decide to remove priority feature now.

> 
> [...]
> > +static void
> > +ck_display_type_init (CkDisplayType *display)
> > +{
> > +        display->priv = CK_DISPLAY_TYPE_GET_PRIVATE (display);
> > +
> > +        display->priv->name = NULL;
> > +        display->priv->command = NULL;
> > +        display->priv->arguments = NULL;
> > +        display->priv->use_auth = TRUE;
> > +        display->priv->priority = 0;
> Shouldn't this be CK_PRIO_DEFAULT ?
Will be removed since we decide to remove priority feature now.

> [...]
> > +CkDisplayType *
> > +ck_display_type_new (const char *name)
> > +{
> > +        GObject   *object;
> > +        GKeyFile  *key_file;
> > +        char     **groups;
> > +        gsize      group_len;
> > +        gsize      i;
> > +        gboolean   res;
> > +        GError    *error;
> > +
> > +        g_return_val_if_fail ((name && !g_str_equal (name, "")), NULL);
> > +
> > +        key_file = g_key_file_new ();
> > +
> > +        error = NULL;
> > +        res = g_key_file_load_from_file (key_file,
> > +                                         CK_DISPLAY_TYPES_FILE,
> > +                                         G_KEY_FILE_NONE,
> > +                                         &error);
> > +        if (! res) {
> > +                g_warning ("Unable to load static display types from file %s: %s", CK_DISPLAY_TYPES_FILE, error->message);
> > +                g_error_free (error);
> > +                return NULL;
> > +        }
> > +
> Two things that are generally considered bad practice:
> 
>     1) Doing things that can fail at object construction time.  Don't
> ever return NULL from a _new function.
>     2) Making _new() more than a 3 line wrapper around g_object_new ().
> 
> I would have a separate _load () function that returns a gerror.
Reasonable, will do.

> 
> > +        groups = g_key_file_get_groups (key_file, &group_len);
> > +        for(i=0; i<group_len; i++) {
> > +                if (g_str_equal (groups[i], name)) {
> This seems really clunky to me.  It means the file could conceivably get
> opened, read, and closed several times at startup.
> 
> I really think that each display type should be in its own file.  If you
> enforce a rule that each file be named with the same name as it's internal
> name, then you can just open "Local.display" or whatever for the local display
> type and don't have to do any searching or rereading.
Will do after the new design is ready.

> 
> [...]
> > diff --git a/src/ck-manager.c b/src/ck-manager.c
> > index bcb9350..f95c8c5 100644
> > --- a/src/ck-manager.c
> > +++ b/src/ck-manager.c
> > @@ -49,6 +49,7 @@
> >  #include "ck-manager.h"
> >  #include "ck-manager-glue.h"
> >  #include "ck-seat.h"
> > +#include "ck-display-type.h"
> >  #include "ck-session-leader.h"
> >  #include "ck-session.h"
> >  #include "ck-marshal.h"
> > @@ -97,6 +98,15 @@ static guint signals [LAST_SIGNAL] = { 0, };
> >  static void     ck_manager_class_init  (CkManagerClass *klass);
> >  static void     ck_manager_init        (CkManager      *manager);
> >  static void     ck_manager_finalize    (GObject        *object);
> > +static gboolean create_display_with_parameters (CkManager *manager,
> > +                                                gint32     display_number,
> > +                                                gint32     seat_number,
> > +                                                char      *display_type,
> > +                                                gint32     priority,
> > +                                                gboolean   is_console,
> > +                                                char      *tty_device,
> > +                                                gboolean   is_dynamic,
> > +                                                char      **id);
> This prototype declares a function that's never defined...
> [...]
Good catch, removed.

> > +static void
> > +_create_static_displays_per_seat (gpointer key,
> > +                                  gpointer value,
> > +                                  gpointer user_data)
> > +{
> > +        ck_seat_create_static_sessions (CK_SEAT (value));
> > +}
> > +
> > +/*
> > +  Example:
> > +  dbus-send --system --dest=org.freedesktop.ConsoleKit \
> > +  --type=method_call --print-reply --reply-timeout=2000 \
> > +  /org/freedesktop/ConsoleKit/Manager \
> > +  org.freedesktop.ConsoleKit.Manager.CreateStaticSessions
> > +*/
> > +gboolean
> > +ck_manager_create_static_sessions (CkManager             *manager,
> > +                                   DBusGMethodInvocation *context)
> > +{
> > +        g_hash_table_foreach (manager->priv->seats, _create_static_displays_per_seat, NULL);
> > +        return TRUE;
> > +}
> > +
> So this CreateStaticSessions function is supposed to be called by the
> display manager to make
> ConsoleKit tell the display manager what seat config to instantiate?
> I don't think the name is right.
> 
> Thinking about it, we have a bunch of seats, and each seat has a bunch
> of sessions.
> 
> Maybe the right interface is for the display manager to first
> 
> Manager.GetUnmanagedSeats
> 
> then for each seat, the display manager would "opt-in" via
> ManageSeat() function.
> 
> When that function gets called ConsoleKit would emit a signal for each session
> in the seat that needs to be started.
Good suggestion, this need time to change, will do.

> >  gboolean
> >  ck_manager_open_session (CkManager             *manager,
> >                           DBusGMethodInvocation *context)
> > @@ -2660,6 +2657,159 @@ ck_manager_get_sessions (CkManager  *manager,
> >          return TRUE;
> >  }
> >
> > +/*
> > +  Example:
> > +  dbus-send --system --dest=org.freedesktop.ConsoleKit \
> > +  --type=method_call --print-reply --reply-timeout=2000 \
> > +  /org/freedesktop/ConsoleKit/Manager \
> > +  org.freedesktop.ConsoleKit.Manager.CreateSession \
> > +  int32:101 string:"Headless" string:"/dev/local"
> > +*/
> > +gboolean
> > +ck_manager_create_session (CkManager              *manager,
> > +                           gint32                  display_number,
> > +                           char                   *display_type,
> > +                           char                   *tty_device,
> > +                           char                  **id,
> > +                           DBusGMethodInvocation  *context)
> This API doesn't link a session to a seat.  We want to be able to
> start a new session on an existing seat. So maybe there should be
> a Manager.CreateSeat call, and then a Seat.CreateSession call.
This api is supposed to used by "ck-dynamic -a -t <type> -n <disp_num>" to create a dynamic display.
Normally each call of "ck-dynamic -a" will create a new seat with a new session attached on it.

If ck-dynamic is designed as can adding a session for existing seat, then this API should be changed.

So the question is do we need that feature for ck-dynamic?

> 
> [...]
> > +static void
> > +listify_created_session_displays (char       *id,
> > +                                  CkSession  *session,
> > +                                  char      **session_list)
> > +{
> > +        gboolean is_dynamic;
> > +        char     *display;
> > +        GError  *error;
> error isn't used here.
> > +
> > +        ck_session_is_dynamic (session, &is_dynamic, NULL);
> > +
> > +        if (!is_dynamic)
> > +                return;
> > +
> > +        ck_session_get_x11_display (session, &display, NULL);
> > +        if (*session_list == NULL) {
> > +                *session_list = g_strdup (display);
> > +        } else {
> > +                *session_list = g_strdup_printf ("%s;%s", *session_list, display);
> > +        }
> > +}
> > +
> > +/*
> > +  Example:
> > +  dbus-send --system --dest=org.freedesktop.ConsoleKit \
> > +  --type=method_call --print-reply --reply-timeout=2000 \
> > +  /org/freedesktop/ConsoleKit/Manager \
> > +  org.freedesktop.ConsoleKit.Manager.ListCreatedSessions
> > +*/
> Does this API add anything over just calling GetSeats() and filtering
> out those that are dynamic?
Agree with you and Brian, will remove this API from CkManager, and let ck-dynamic do that itself.

> 
> > diff --git a/src/ck-seat.c b/src/ck-seat.c
> > index c2f70da..9dc1b9f 100644
> > --- a/src/ck-seat.c
> > +++ b/src/ck-seat.c
> [...]
> > +static void
> > +_create_display (gpointer data,
> > +                 gpointer user_data)
> > +{
> > +        CkSeat      *seat = CK_SEAT (user_data);
> > +        DisplayData *disp = (DisplayData *)data;
> > +        DBusGProxy  *proxy;
> > +        gboolean     ret = TRUE;
> > +        GError      *error = NULL;
> > +
> > +        proxy = dbus_g_proxy_new_for_name (seat->priv->connection,
> > +                                           GDM_DBUS_NAME,
> > +                                           GDM_DBUS_LOCAL_DISPLAY_FACTORY_PATH,
> > +                                           GDM_DBUS_LOCAL_DISPLAY_FACTORY_INTERFACE);
> This isn't allowed.  We can't assume ConsoleKit is running on a
> machine with GDM.  ConsoleKit should probably emit a signal here
> instead (or call the method on whatever display manager is managing
> the seat via the ManageSeat() api mentioned above.
Agree, will change.

> 
> > +        if (proxy == NULL) {
> > +                g_critical ("error getting %s proxy",
> > +                            GDM_DBUS_LOCAL_DISPLAY_FACTORY_INTERFACE);
> > +                return;
> > +        }
> > +
> > +        error = NULL;
> > +        g_free (disp->display_id);
> > +        ret = dbus_g_proxy_call (proxy,
> > +                                 "CreateDisplay",
> > +                                 &error,
> > +                                 G_TYPE_STRING, seat->priv->id,
> > +                                 G_TYPE_INT, disp->num,
> > +                                 G_TYPE_STRING, ck_display_type_get_command (seat->priv->display_type) ? ck_display_type_get_command (seat->priv->display_type) : "",
> > +                                 G_TYPE_STRING, ck_display_type_get_arguments (seat->priv->display_type) ? ck_display_type_get_arguments (seat->priv->display_type) : "",
> > +                                 G_TYPE_BOOLEAN, ck_display_type_get_chooser (seat->priv->display_type),
> > +                                 G_TYPE_BOOLEAN, ck_display_type_get_use_auth (seat->priv->display_type),
> > +                                 G_TYPE_INT, ck_display_type_get_priority (seat->priv->display_type),
> > +                                 G_TYPE_STRING, disp->tty_device ? disp->tty_device : "",
> > +                                 G_TYPE_BOOLEAN, disp->dynamic,
> > +                                 G_TYPE_INVALID,
> > +                                 DBUS_TYPE_G_OBJECT_PATH, &disp->display_id,
> > +                                 G_TYPE_INVALID);
> 
> Maybe the call should be an a{sv} isntead of a long list of args.  I
> mean if we need to send that mean arguments now, we might need to add
> more later...
can not agree more, will do.

> [...]
> > +gboolean
> > +ck_seat_add_display (CkSeat     *seat,
> > +                     int         num,
> > +                     gboolean    dynamic,
> > +                     const char *tty)
> > +{
> > +        DisplayData *disp;
> > +
> > +        disp = g_new0 (DisplayData, 1);
> > +
> > +        disp->num = num;
> > +        disp->dynamic = dynamic;
> > +        disp->tty_device = g_strdup (tty);
> > +
> > +        seat->priv->displays = g_slist_append (seat->priv->displays, disp);
> > +}
> This should have a void return type.  Also you've got some extra whitespace on
> the blank line.
To keep function same style, I'd like keep this function return gboolean, and adding following code

        g_return_val_if_fail (CK_IS_SEAT (seat), FALSE);
[...]
        return TRUE;

> > +
> > +gboolean
> > +ck_seat_set_display_type (CkSeat *seat,
> > +                          char   *type)
> > +{
> > +        g_object_unref (seat->priv->display_type);
> > +        seat->priv->display_type = ck_display_type_new (type);
> > +}
> This should have a void return type.
Same with above.
> 
> > +
> > +gboolean
> > +ck_seat_get_display_id (CkSeat  *seat,
> > +                        int      num,
> > +                        char   **id)
> > +{
> > +        int i, len;
> > +        DisplayData *disp;
> > +
> > +        len = g_slist_length (seat->priv->displays);
> > +
> > +        for (i = 0; i < len; i++) {
> > +
> > +                disp = (DisplayData *) g_slist_nth_data (seat->priv->displays, i);
> > +
> > +                if (disp->num == num) {
> > +                        g_free (*id);
> > +                        *id = g_strdup (disp->display_id);
> > +                        break;
> > +                }
> > +
> > +        }
> > +
> > +}
> This function doesn't return any value but it's return type is
> boolean.  It should probably
> return a string instead of use an out parameter, yea?
Same with above.

> >  CkSeat *
> >  ck_seat_new_from_file (const char *sid,
> >                         const char *path)
> >  {
> [...]
> > @@ -1107,6 +1299,45 @@ ck_seat_new_from_file (const char *sid,
> >                  return NULL;
> >          }
> >
> > +        error = NULL;
> > +        str = g_key_file_get_string (key_file, group, "DisplayType", &error);
> > +        if (error) {
> > +                g_warning ("Unable to load key DisplayType in seat file: %s", path, error->message);
> You're missing a %s here
Good catch, done.

> [...]
> > +        tty_device_list = g_key_file_get_integer_list (key_file, group, "TtyDevices", &ntty_device, NULL);
> > +
> >          device_list = g_key_file_get_string_list (key_file, group, "Devices", &ndevices, NULL);
> >
> >          g_debug ("Creating seat %s with %d devices", sid, ndevices);
> ndevices should be cast to int here.
Done.

Totally, I have 6 items to do together with my estimation:
1) redesign on how to represent seat and display (5h)
2) removing listify_created_session_displays (0.5h)
3) rework ck_manager_create_static_sessions (3h)
4) use a{sv} for dbus method CreateDisplay (2h)
5) rewrite ck_display_type_new (1h)
6) remove priority code (1h)

Will keep you updated.

Ray, can I commit to those two branches on changes that we agree?

My gnome account is "haltonhuo".

For freedesktop, I just followed the page http://freedesktop.org/wiki/AccountRequests 
to require an account, https://bugs.freedesktop.org/show_bug.cgi?id=21732. 
Could you or Jon help my request?

Thanks,
Halton.



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