[PATCH 02/15] Convert Dispatcher and MainDispatcher to GObjects

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

 



From: Jonathon Jongsma <jjongsma@xxxxxxxxxx>

Allows more explicit inheritance relationship, and numerous other
advantages.
---
 server/dispatcher.c      | 233 ++++++++++++++++++++++++++++++++++++-----------
 server/dispatcher.h      |  53 ++++++-----
 server/main-dispatcher.c | 157 +++++++++++++++++++++++++------
 server/main-dispatcher.h |  25 +++++
 server/red-qxl.c         |  80 ++++++++--------
 server/red-qxl.h         |   3 +-
 6 files changed, 407 insertions(+), 144 deletions(-)

diff --git a/server/dispatcher.c b/server/dispatcher.c
index d6c03ca..cd2f2cb 100644
--- a/server/dispatcher.c
+++ b/server/dispatcher.c
@@ -1,6 +1,5 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 /*
-   Copyright (C) 2009-2012 Red Hat, Inc.
+   Copyright (C) 2009-2015 Red Hat, Inc.
 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -39,6 +38,155 @@
 #include <signal.h>
 #endif
 
+G_DEFINE_TYPE(Dispatcher, dispatcher, G_TYPE_OBJECT)
+
+#define DISPATCHER_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_DISPATCHER, DispatcherPrivate))
+
+struct DispatcherPrivate {
+    int recv_fd;
+    int send_fd;
+    pthread_t self;
+    pthread_mutex_t lock;
+    DispatcherMessage *messages;
+    int stage;  /* message parser stage - sender has no stages */
+    size_t max_message_type;
+    void *payload; /* allocated as max of message sizes */
+    size_t payload_size; /* used to track realloc calls */
+    void *opaque;
+    dispatcher_handle_async_done handle_async_done;
+    dispatcher_handle_any_message any_handler;
+};
+
+enum {
+    PROP_0,
+    PROP_MAX_MESSAGE_TYPE,
+    PROP_OPAQUE
+};
+
+static void
+dispatcher_get_property(GObject    *object,
+                        guint       property_id,
+                        GValue     *value,
+                        GParamSpec *pspec)
+{
+    Dispatcher *self = DISPATCHER(object);
+
+    switch (property_id)
+    {
+        case PROP_MAX_MESSAGE_TYPE:
+            g_value_set_uint(value, self->priv->max_message_type);
+            break;
+        case PROP_OPAQUE:
+            g_value_set_pointer(value, self->priv->opaque);
+            break;
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+    }
+}
+
+static void
+dispatcher_set_property(GObject      *object,
+                        guint         property_id,
+                        const GValue *value,
+                        GParamSpec   *pspec)
+{
+    Dispatcher *self = DISPATCHER(object);
+
+    switch (property_id)
+    {
+        case PROP_MAX_MESSAGE_TYPE:
+            self->priv->max_message_type = g_value_get_uint(value);
+            break;
+        case PROP_OPAQUE:
+            dispatcher_set_opaque(self, g_value_get_pointer(value));
+            break;
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+    }
+}
+
+static void
+dispatcher_finalize(GObject *object)
+{
+    Dispatcher *self = DISPATCHER(object);
+    g_free(self->priv->messages);
+    close(self->priv->send_fd);
+    close(self->priv->recv_fd);
+    free(self->priv->payload);
+    G_OBJECT_CLASS(dispatcher_parent_class)->finalize(object);
+}
+
+static void dispatcher_constructed(GObject *object)
+{
+    Dispatcher *self = DISPATCHER(object);
+    int channels[2];
+
+    G_OBJECT_CLASS(dispatcher_parent_class)->constructed(object);
+
+#ifdef DEBUG_DISPATCHER
+    setup_dummy_signal_handler();
+#endif
+    if (socketpair(AF_LOCAL, SOCK_STREAM, 0, channels) == -1) {
+        spice_error("socketpair failed %s", strerror(errno));
+        return;
+    }
+    pthread_mutex_init(&self->priv->lock, NULL);
+    self->priv->recv_fd = channels[0];
+    self->priv->send_fd = channels[1];
+    self->priv->self = pthread_self();
+
+    self->priv->messages = g_new0(DispatcherMessage,
+                                  self->priv->max_message_type);
+}
+
+static void
+dispatcher_class_init(DispatcherClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+    g_type_class_add_private(klass, sizeof (DispatcherPrivate));
+
+    object_class->get_property = dispatcher_get_property;
+    object_class->set_property = dispatcher_set_property;
+    object_class->constructed = dispatcher_constructed;
+    object_class->finalize = dispatcher_finalize;
+
+    g_object_class_install_property(object_class,
+                                    PROP_MAX_MESSAGE_TYPE,
+                                    g_param_spec_uint("max-message-type",
+                                                      "Maximum message type",
+                                                      "Maximum message type",
+                                                      0, G_MAXUINT, 0,
+                                                      G_PARAM_STATIC_STRINGS |
+                                                      G_PARAM_READWRITE |
+                                                      G_PARAM_CONSTRUCT_ONLY));
+    g_object_class_install_property(object_class,
+                                    PROP_OPAQUE,
+                                    g_param_spec_pointer("opaque",
+                                                      "opaque",
+                                                      "User data to pass to callbacks",
+                                                      G_PARAM_STATIC_STRINGS |
+                                                      G_PARAM_READWRITE |
+                                                      G_PARAM_CONSTRUCT));
+
+}
+
+static void
+dispatcher_init(Dispatcher *self)
+{
+    self->priv = DISPATCHER_PRIVATE(self);
+}
+
+Dispatcher *
+dispatcher_new(size_t max_message_type, void *opaque)
+{
+    return g_object_new(TYPE_DISPATCHER,
+                        "max-message-type", max_message_type,
+                        "opaque", opaque,
+                        NULL);
+}
+
+
 #define ACK 0xffffffff
 
 /*
@@ -118,10 +266,10 @@ static int dispatcher_handle_single_read(Dispatcher *dispatcher)
     int ret;
     uint32_t type;
     DispatcherMessage *msg = NULL;
-    uint8_t *payload = dispatcher->payload;
+    uint8_t *payload = dispatcher->priv->payload;
     uint32_t ack = ACK;
 
-    if ((ret = read_safe(dispatcher->recv_fd, (uint8_t*)&type, sizeof(type), 0)) == -1) {
+    if ((ret = read_safe(dispatcher->priv->recv_fd, (uint8_t*)&type, sizeof(type), 0)) == -1) {
         spice_printerr("error reading from dispatcher: %d", errno);
         return 0;
     }
@@ -129,28 +277,28 @@ static int dispatcher_handle_single_read(Dispatcher *dispatcher)
         /* no messsage */
         return 0;
     }
-    msg = &dispatcher->messages[type];
-    if (read_safe(dispatcher->recv_fd, payload, msg->size, 1) == -1) {
+    msg = &dispatcher->priv->messages[type];
+    if (read_safe(dispatcher->priv->recv_fd, payload, msg->size, 1) == -1) {
         spice_printerr("error reading from dispatcher: %d", errno);
         /* TODO: close socketpair? */
         return 0;
     }
-    if (dispatcher->any_handler) {
-        dispatcher->any_handler(dispatcher->opaque, type, payload);
+    if (dispatcher->priv->any_handler) {
+        dispatcher->priv->any_handler(dispatcher->priv->opaque, type, payload);
     }
     if (msg->handler) {
-        msg->handler(dispatcher->opaque, (void *)payload);
+        msg->handler(dispatcher->priv->opaque, payload);
     } else {
         spice_printerr("error: no handler for message type %d", type);
     }
     if (msg->ack == DISPATCHER_ACK) {
-        if (write_safe(dispatcher->recv_fd,
+        if (write_safe(dispatcher->priv->recv_fd,
                        (uint8_t*)&ack, sizeof(ack)) == -1) {
             spice_printerr("error writing ack for message %d", type);
             /* TODO: close socketpair? */
         }
-    } else if (msg->ack == DISPATCHER_ASYNC && dispatcher->handle_async_done) {
-        dispatcher->handle_async_done(dispatcher->opaque, type,
+    } else if (msg->ack == DISPATCHER_ASYNC && dispatcher->priv->handle_async_done) {
+        dispatcher->priv->handle_async_done(dispatcher->priv->opaque, type,
                                       (void *)payload);
     }
     return 1;
@@ -171,12 +319,12 @@ void dispatcher_send_message(Dispatcher *dispatcher, uint32_t message_type,
 {
     DispatcherMessage *msg;
     uint32_t ack;
-    int send_fd = dispatcher->send_fd;
+    int send_fd = dispatcher->priv->send_fd;
 
-    assert(dispatcher->max_message_type > message_type);
-    assert(dispatcher->messages[message_type].handler);
-    msg = &dispatcher->messages[message_type];
-    pthread_mutex_lock(&dispatcher->lock);
+    assert(dispatcher->priv->max_message_type > message_type);
+    assert(dispatcher->priv->messages[message_type].handler);
+    msg = &dispatcher->priv->messages[message_type];
+    pthread_mutex_lock(&dispatcher->priv->lock);
     if (write_safe(send_fd, (uint8_t*)&message_type, sizeof(message_type)) == -1) {
         spice_printerr("error: failed to send message type for message %d",
                    message_type);
@@ -197,15 +345,15 @@ void dispatcher_send_message(Dispatcher *dispatcher, uint32_t message_type,
         }
     }
 unlock:
-    pthread_mutex_unlock(&dispatcher->lock);
+    pthread_mutex_unlock(&dispatcher->priv->lock);
 }
 
 void dispatcher_register_async_done_callback(
                                         Dispatcher *dispatcher,
                                         dispatcher_handle_async_done handler)
 {
-    assert(dispatcher->handle_async_done == NULL);
-    dispatcher->handle_async_done = handler;
+    assert(dispatcher->priv->handle_async_done == NULL);
+    dispatcher->priv->handle_async_done = handler;
 }
 
 void dispatcher_register_handler(Dispatcher *dispatcher, uint32_t message_type,
@@ -214,15 +362,15 @@ void dispatcher_register_handler(Dispatcher *dispatcher, uint32_t message_type,
 {
     DispatcherMessage *msg;
 
-    assert(message_type < dispatcher->max_message_type);
-    assert(dispatcher->messages[message_type].handler == 0);
-    msg = &dispatcher->messages[message_type];
+    assert(message_type < dispatcher->priv->max_message_type);
+    assert(dispatcher->priv->messages[message_type].handler == 0);
+    msg = &dispatcher->priv->messages[message_type];
     msg->handler = handler;
     msg->size = size;
     msg->ack = ack;
-    if (msg->size > dispatcher->payload_size) {
-        dispatcher->payload = realloc(dispatcher->payload, msg->size);
-        dispatcher->payload_size = msg->size;
+    if (msg->size > dispatcher->priv->payload_size) {
+        dispatcher->priv->payload = realloc(dispatcher->priv->payload, msg->size);
+        dispatcher->priv->payload_size = msg->size;
     }
 }
 
@@ -230,7 +378,7 @@ void dispatcher_register_universal_handler(
                                Dispatcher *dispatcher,
                                dispatcher_handle_any_message any_handler)
 {
-    dispatcher->any_handler = any_handler;
+    dispatcher->priv->any_handler = any_handler;
 }
 
 #ifdef DEBUG_DISPATCHER
@@ -257,35 +405,18 @@ static void setup_dummy_signal_handler(void)
 }
 #endif
 
-void dispatcher_init(Dispatcher *dispatcher, size_t max_message_type,
-                     void *opaque)
+void dispatcher_set_opaque(Dispatcher *self, void *opaque)
 {
-    int channels[2];
-
-#ifdef DEBUG_DISPATCHER
-    setup_dummy_signal_handler();
-#endif
-    dispatcher->opaque = opaque;
-    if (socketpair(AF_LOCAL, SOCK_STREAM, 0, channels) == -1) {
-        spice_error("socketpair failed %s", strerror(errno));
-        return;
-    }
-    pthread_mutex_init(&dispatcher->lock, NULL);
-    dispatcher->recv_fd = channels[0];
-    dispatcher->send_fd = channels[1];
-    dispatcher->self = pthread_self();
-
-    dispatcher->messages = spice_malloc0_n(max_message_type,
-                                           sizeof(dispatcher->messages[0]));
-    dispatcher->max_message_type = max_message_type;
+    self->priv->opaque = opaque;
+    g_object_notify(G_OBJECT(self), "opaque");
 }
 
-void dispatcher_set_opaque(Dispatcher *dispatcher, void *opaque)
+int dispatcher_get_recv_fd(Dispatcher *dispatcher)
 {
-    dispatcher->opaque = opaque;
+    return dispatcher->priv->recv_fd;
 }
 
-int dispatcher_get_recv_fd(Dispatcher *dispatcher)
+pthread_t dispatcher_get_thread_id(Dispatcher *self)
 {
-    return dispatcher->recv_fd;
+    return self->priv->self;
 }
diff --git a/server/dispatcher.h b/server/dispatcher.h
index 78ef663..caaebc5 100644
--- a/server/dispatcher.h
+++ b/server/dispatcher.h
@@ -18,9 +18,37 @@
 #ifndef DISPATCHER_H
 #define DISPATCHER_H
 
+#include <glib-object.h>
 #include "red-common.h"
 
+#define TYPE_DISPATCHER dispatcher_get_type()
+
+#define DISPATCHER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_DISPATCHER, Dispatcher))
+#define DISPATCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_DISPATCHER, DispatcherClass))
+#define IS_DISPATCHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_DISPATCHER))
+#define IS_DISPATCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_DISPATCHER))
+#define DISPATCHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_DISPATCHER, DispatcherClass))
+
 typedef struct Dispatcher Dispatcher;
+typedef struct DispatcherClass DispatcherClass;
+typedef struct DispatcherPrivate DispatcherPrivate;
+
+struct Dispatcher
+{
+    GObject parent;
+
+    DispatcherPrivate *priv;
+};
+
+struct DispatcherClass
+{
+    GObjectClass parent_class;
+};
+
+GType dispatcher_get_type(void) G_GNUC_CONST;
+
+Dispatcher *dispatcher_new(size_t max_message_type, void *opaque);
+
 
 typedef void (*dispatcher_handle_message)(void *opaque,
                                           void *payload);
@@ -40,20 +68,6 @@ typedef struct DispatcherMessage {
     dispatcher_handle_message handler;
 } DispatcherMessage;
 
-struct Dispatcher {
-    int recv_fd;
-    int send_fd;
-    pthread_t self;
-    pthread_mutex_t lock;
-    DispatcherMessage *messages;
-    int stage;  /* message parser stage - sender has no stages */
-    size_t max_message_type;
-    void *payload; /* allocated as max of message sizes */
-    size_t payload_size; /* used to track realloc calls */
-    void *opaque;
-    dispatcher_handle_async_done handle_async_done;
-    dispatcher_handle_any_message any_handler;
-};
 
 /*
  * dispatcher_send_message
@@ -63,15 +77,6 @@ struct Dispatcher {
 void dispatcher_send_message(Dispatcher *dispatcher, uint32_t message_type,
                              void *payload);
 
-/*
- * dispatcher_init
- * @max_message_type: number of message types. Allows upfront allocation
- *  of a DispatcherMessage list.
- * up front, and registration in any order wanted.
- */
-void dispatcher_init(Dispatcher *dispatcher, size_t max_message_type,
-                     void *opaque);
-
 enum {
     DISPATCHER_NONE = 0,
     DISPATCHER_ACK,
@@ -131,4 +136,6 @@ int dispatcher_get_recv_fd(Dispatcher *);
  */
 void dispatcher_set_opaque(Dispatcher *dispatcher, void *opaque);
 
+pthread_t dispatcher_get_thread_id(Dispatcher *self);
+
 #endif //DISPATCHER_H
diff --git a/server/main-dispatcher.c b/server/main-dispatcher.c
index 298a961..bc0de24 100644
--- a/server/main-dispatcher.c
+++ b/server/main-dispatcher.c
@@ -47,12 +47,99 @@
  *   seperate from self because it may send an ack or do other work in the future.
  */
 
-struct MainDispatcher {
-    Dispatcher base;
-    SpiceCoreInterfaceInternal *core;
-    RedsState *reds;
+G_DEFINE_TYPE(MainDispatcher, main_dispatcher, TYPE_DISPATCHER)
+
+#define MAIN_DISPATCHER_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), TYPE_MAIN_DISPATCHER, MainDispatcherPrivate))
+
+struct MainDispatcherPrivate
+{
+    SpiceCoreInterfaceInternal *core; /* weak */
+    RedsState *reds; /* weak */
 };
 
+
+enum {
+    PROP0,
+    PROP_SPICE_SERVER,
+    PROP_CORE_INTERFACE
+};
+
+static void
+main_dispatcher_get_property(GObject    *object,
+                                  guint       property_id,
+                                  GValue     *value,
+                                  GParamSpec *pspec)
+{
+    MainDispatcher *self = MAIN_DISPATCHER(object);
+
+    switch (property_id) {
+        case PROP_SPICE_SERVER:
+             g_value_set_pointer(value, self->priv->reds);
+            break;
+        case PROP_CORE_INTERFACE:
+             g_value_set_pointer(value, self->priv->core);
+            break;
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+    }
+}
+
+static void
+main_dispatcher_set_property(GObject      *object,
+                                  guint         property_id,
+                                  const GValue *value,
+                                  GParamSpec   *pspec)
+{
+    MainDispatcher *self = MAIN_DISPATCHER(object);
+
+    switch (property_id) {
+        case PROP_SPICE_SERVER:
+            self->priv->reds = g_value_get_pointer(value);
+            break;
+        case PROP_CORE_INTERFACE:
+            self->priv->core = g_value_get_pointer(value);
+            break;
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+    }
+}
+
+static void main_dispatcher_constructed(GObject *object);
+
+static void
+main_dispatcher_class_init(MainDispatcherClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+    g_type_class_add_private(klass, sizeof(MainDispatcherPrivate));
+
+    object_class->constructed = main_dispatcher_constructed;
+    object_class->get_property = main_dispatcher_get_property;
+    object_class->set_property = main_dispatcher_set_property;
+
+    g_object_class_install_property(object_class,
+                                    PROP_SPICE_SERVER,
+                                    g_param_spec_pointer("spice-server",
+                                                         "spice-server",
+                                                         "The spice server associated with this dispatcher",
+                                                         G_PARAM_READWRITE |
+                                                         G_PARAM_CONSTRUCT_ONLY));
+
+    g_object_class_install_property(object_class,
+                                    PROP_CORE_INTERFACE,
+                                    g_param_spec_pointer("core-interface",
+                                                         "core-interface",
+                                                         "The SpiceCoreInterface server associated with this dispatcher",
+                                                         G_PARAM_READWRITE |
+                                                         G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+main_dispatcher_init(MainDispatcher *self)
+{
+    self->priv = MAIN_DISPATCHER_PRIVATE(self);
+}
+
 enum {
     MAIN_DISPATCHER_CHANNEL_EVENT = 0,
     MAIN_DISPATCHER_MIGRATE_SEAMLESS_DST_COMPLETE,
@@ -85,7 +172,7 @@ static void main_dispatcher_self_handle_channel_event(MainDispatcher *self,
                                                       int event,
                                                       SpiceChannelEventInfo *info)
 {
-    reds_handle_channel_event(self->reds, event, info);
+    reds_handle_channel_event(self->priv->reds, event, info);
 }
 
 static void main_dispatcher_handle_channel_event(void *opaque,
@@ -103,13 +190,13 @@ void main_dispatcher_channel_event(MainDispatcher *self, int event, SpiceChannel
 {
     MainDispatcherChannelEventMessage msg = {0,};
 
-    if (pthread_self() == self->base.self) {
+    if (pthread_self() == dispatcher_get_thread_id(DISPATCHER(self))) {
         main_dispatcher_self_handle_channel_event(self, event, info);
         return;
     }
     msg.event = event;
     msg.info = info;
-    dispatcher_send_message(&self->base, MAIN_DISPATCHER_CHANNEL_EVENT,
+    dispatcher_send_message(DISPATCHER(self), MAIN_DISPATCHER_CHANNEL_EVENT,
                             &msg);
 }
 
@@ -120,7 +207,7 @@ static void main_dispatcher_handle_migrate_complete(void *opaque,
     MainDispatcher *self = opaque;
     MainDispatcherMigrateSeamlessDstCompleteMessage *mig_complete = payload;
 
-    reds_on_client_seamless_migrate_complete(self->reds, mig_complete->client);
+    reds_on_client_seamless_migrate_complete(self->priv->reds, mig_complete->client);
     red_client_unref(mig_complete->client);
 }
 
@@ -129,7 +216,7 @@ static void main_dispatcher_handle_mm_time_latency(void *opaque,
 {
     MainDispatcher *self = opaque;
     MainDispatcherMmTimeLatencyMessage *msg = payload;
-    reds_set_client_mm_time_latency(self->reds, msg->client, msg->latency);
+    reds_set_client_mm_time_latency(self->priv->reds, msg->client, msg->latency);
     red_client_unref(msg->client);
 }
 
@@ -140,7 +227,7 @@ static void main_dispatcher_handle_client_disconnect(void *opaque,
     MainDispatcherClientDisconnectMessage *msg = payload;
 
     spice_debug("client=%p", msg->client);
-    reds_client_disconnect(self->reds, msg->client);
+    reds_client_disconnect(self->priv->reds, msg->client);
     red_client_unref(msg->client);
 }
 
@@ -149,13 +236,13 @@ void main_dispatcher_seamless_migrate_dst_complete(MainDispatcher *self,
 {
     MainDispatcherMigrateSeamlessDstCompleteMessage msg;
 
-    if (pthread_self() == self->base.self) {
-        reds_on_client_seamless_migrate_complete(self->reds, client);
+    if (pthread_self() == dispatcher_get_thread_id(DISPATCHER(self))) {
+        reds_on_client_seamless_migrate_complete(self->priv->reds, client);
         return;
     }
 
     msg.client = red_client_ref(client);
-    dispatcher_send_message(&self->base, MAIN_DISPATCHER_MIGRATE_SEAMLESS_DST_COMPLETE,
+    dispatcher_send_message(DISPATCHER(self), MAIN_DISPATCHER_MIGRATE_SEAMLESS_DST_COMPLETE,
                             &msg);
 }
 
@@ -163,14 +250,14 @@ void main_dispatcher_set_mm_time_latency(MainDispatcher *self, RedClient *client
 {
     MainDispatcherMmTimeLatencyMessage msg;
 
-    if (pthread_self() == self->base.self) {
-        reds_set_client_mm_time_latency(self->reds, client, latency);
+    if (pthread_self() == dispatcher_get_thread_id(DISPATCHER(self))) {
+        reds_set_client_mm_time_latency(self->priv->reds, client, latency);
         return;
     }
 
     msg.client = red_client_ref(client);
     msg.latency = latency;
-    dispatcher_send_message(&self->base, MAIN_DISPATCHER_SET_MM_TIME_LATENCY,
+    dispatcher_send_message(DISPATCHER(self), MAIN_DISPATCHER_SET_MM_TIME_LATENCY,
                             &msg);
 }
 
@@ -181,7 +268,7 @@ void main_dispatcher_client_disconnect(MainDispatcher *self, RedClient *client)
     if (!client->disconnecting) {
         spice_debug("client %p", client);
         msg.client = red_client_ref(client);
-        dispatcher_send_message(&self->base, MAIN_DISPATCHER_CLIENT_DISCONNECT,
+        dispatcher_send_message(DISPATCHER(self), MAIN_DISPATCHER_CLIENT_DISCONNECT,
                                 &msg);
     } else {
         spice_debug("client %p already during disconnection", client);
@@ -192,7 +279,7 @@ static void dispatcher_handle_read(int fd, int event, void *opaque)
 {
     MainDispatcher *self = opaque;
 
-    dispatcher_handle_recv_read(&self->base);
+    dispatcher_handle_recv_read(DISPATCHER(self));
 }
 
 /*
@@ -202,23 +289,35 @@ static void dispatcher_handle_read(int fd, int event, void *opaque)
  */
 MainDispatcher* main_dispatcher_new(RedsState *reds, SpiceCoreInterfaceInternal *core)
 {
-    MainDispatcher *main_dispatcher = g_new0(MainDispatcher, 1);
-    main_dispatcher->core = core;
-    main_dispatcher->reds = reds;
-    dispatcher_init(&main_dispatcher->base, MAIN_DISPATCHER_NUM_MESSAGES, main_dispatcher);
-    core->watch_add(core, main_dispatcher->base.recv_fd, SPICE_WATCH_EVENT_READ,
-                    dispatcher_handle_read, main_dispatcher);
-    dispatcher_register_handler(&main_dispatcher->base, MAIN_DISPATCHER_CHANNEL_EVENT,
+    MainDispatcher *self = g_object_new(TYPE_MAIN_DISPATCHER,
+                                        "spice-server", reds,
+                                        "core-interface", core,
+                                        "max-message-type", MAIN_DISPATCHER_NUM_MESSAGES,
+                                        NULL);
+    return self;
+}
+
+void main_dispatcher_constructed(GObject *object)
+{
+    MainDispatcher *self = MAIN_DISPATCHER(object);
+
+    G_OBJECT_CLASS(main_dispatcher_parent_class)->constructed(object);
+    dispatcher_set_opaque(DISPATCHER(self), self);
+
+    self->priv->core->watch_add(self->priv->core,
+                                dispatcher_get_recv_fd(DISPATCHER(self)),
+                                SPICE_WATCH_EVENT_READ, dispatcher_handle_read,
+                                self);
+    dispatcher_register_handler(DISPATCHER(self), MAIN_DISPATCHER_CHANNEL_EVENT,
                                 main_dispatcher_handle_channel_event,
                                 sizeof(MainDispatcherChannelEventMessage), 0 /* no ack */);
-    dispatcher_register_handler(&main_dispatcher->base, MAIN_DISPATCHER_MIGRATE_SEAMLESS_DST_COMPLETE,
+    dispatcher_register_handler(DISPATCHER(self), MAIN_DISPATCHER_MIGRATE_SEAMLESS_DST_COMPLETE,
                                 main_dispatcher_handle_migrate_complete,
                                 sizeof(MainDispatcherMigrateSeamlessDstCompleteMessage), 0 /* no ack */);
-    dispatcher_register_handler(&main_dispatcher->base, MAIN_DISPATCHER_SET_MM_TIME_LATENCY,
+    dispatcher_register_handler(DISPATCHER(self), MAIN_DISPATCHER_SET_MM_TIME_LATENCY,
                                 main_dispatcher_handle_mm_time_latency,
                                 sizeof(MainDispatcherMmTimeLatencyMessage), 0 /* no ack */);
-    dispatcher_register_handler(&main_dispatcher->base, MAIN_DISPATCHER_CLIENT_DISCONNECT,
+    dispatcher_register_handler(DISPATCHER(self), MAIN_DISPATCHER_CLIENT_DISCONNECT,
                                 main_dispatcher_handle_client_disconnect,
                                 sizeof(MainDispatcherClientDisconnectMessage), 0 /* no ack */);
-    return main_dispatcher;
 }
diff --git a/server/main-dispatcher.h b/server/main-dispatcher.h
index cbc3657..ffe82c8 100644
--- a/server/main-dispatcher.h
+++ b/server/main-dispatcher.h
@@ -19,9 +19,34 @@
 #define MAIN_DISPATCHER_H
 
 #include <spice.h>
+#include "dispatcher.h"
 #include "red-channel.h"
 
+#define TYPE_MAIN_DISPATCHER main_dispatcher_get_type()
+
+#define MAIN_DISPATCHER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_MAIN_DISPATCHER, MainDispatcher))
+#define MAIN_DISPATCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_MAIN_DISPATCHER, MainDispatcherClass))
+#define IS_MAIN_DISPATCHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_MAIN_DISPATCHER))
+#define IS_MAIN_DISPATCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_MAIN_DISPATCHER))
+#define MAIN_DISPATCHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_MAIN_DISPATCHER, MainDispatcherClass))
+
 typedef struct MainDispatcher MainDispatcher;
+typedef struct MainDispatcherClass MainDispatcherClass;
+typedef struct MainDispatcherPrivate MainDispatcherPrivate;
+
+struct MainDispatcher
+{
+    Dispatcher parent;
+
+    MainDispatcherPrivate *priv;
+};
+
+struct MainDispatcherClass
+{
+    DispatcherClass parent_class;
+};
+
+GType main_dispatcher_get_type(void) G_GNUC_CONST;
 
 void main_dispatcher_channel_event(MainDispatcher *self, int event, SpiceChannelEventInfo *info);
 void main_dispatcher_seamless_migrate_dst_complete(MainDispatcher *self, RedClient *client);
diff --git a/server/red-qxl.c b/server/red-qxl.c
index 491046f..d209de6 100644
--- a/server/red-qxl.c
+++ b/server/red-qxl.c
@@ -48,7 +48,7 @@ struct AsyncCommand {
 struct QXLState {
     QXLWorker base;
     QXLInstance *qxl;
-    Dispatcher dispatcher;
+    Dispatcher *dispatcher;
     uint32_t pending;
     int primary_active;
     int x_res;
@@ -93,7 +93,7 @@ static void red_qxl_set_display_peer(RedChannel *channel, RedClient *client,
     memcpy(payload.common_caps, common_caps, sizeof(uint32_t)*num_common_caps);
     memcpy(payload.caps, caps, sizeof(uint32_t)*num_caps);
 
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_DISPLAY_CONNECT,
                             &payload);
 }
@@ -114,7 +114,7 @@ static void red_qxl_disconnect_display_peer(RedChannelClient *rcc)
 
     // TODO: we turned it to be sync, due to client_destroy . Should we support async? - for this we will need ref count
     // for channels
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_DISPLAY_DISCONNECT,
                             &payload);
 }
@@ -129,7 +129,7 @@ static void red_qxl_display_migrate(RedChannelClient *rcc)
     qxl_state = (QXLState *)rcc->channel->data;
     spice_printerr("channel type %u id %u", rcc->channel->type, rcc->channel->id);
     payload.rcc = rcc;
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_DISPLAY_MIGRATE,
                             &payload);
 }
@@ -153,7 +153,7 @@ static void red_qxl_set_cursor_peer(RedChannel *channel, RedClient *client, Reds
     memcpy(payload.common_caps, common_caps, sizeof(uint32_t)*num_common_caps);
     memcpy(payload.caps, caps, sizeof(uint32_t)*num_caps);
 
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_CURSOR_CONNECT,
                             &payload);
 }
@@ -171,7 +171,7 @@ static void red_qxl_disconnect_cursor_peer(RedChannelClient *rcc)
     spice_printerr("");
     payload.rcc = rcc;
 
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_CURSOR_DISCONNECT,
                             &payload);
 }
@@ -187,7 +187,7 @@ static void red_qxl_cursor_migrate(RedChannelClient *rcc)
     qxl_state = (QXLState *)rcc->channel->data;
     spice_printerr("channel type %u id %u", rcc->channel->type, rcc->channel->id);
     payload.rcc = rcc;
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_CURSOR_MIGRATE,
                             &payload);
 }
@@ -203,7 +203,7 @@ static void red_qxl_update_area(QXLState *qxl_state, uint32_t surface_id,
     payload.qxl_dirty_rects = qxl_dirty_rects;
     payload.num_dirty_rects = num_dirty_rects;
     payload.clear_dirty_region = clear_dirty_region;
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_UPDATE,
                             &payload);
 }
@@ -249,7 +249,7 @@ static void red_qxl_update_area_async(QXLState *qxl_state,
     payload.surface_id = surface_id;
     payload.qxl_area = *qxl_area;
     payload.clear_dirty_region = clear_dirty_region;
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             message,
                             &payload);
 }
@@ -267,7 +267,7 @@ static void red_qxl_add_memslot(QXLState *qxl_state, QXLDevMemSlot *mem_slot)
     RedWorkerMessageAddMemslot payload;
 
     payload.mem_slot = *mem_slot;
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_ADD_MEMSLOT,
                             &payload);
 }
@@ -284,7 +284,7 @@ static void red_qxl_add_memslot_async(QXLState *qxl_state, QXLDevMemSlot *mem_sl
 
     payload.base.cmd = async_command_alloc(qxl_state, message, cookie);
     payload.mem_slot = *mem_slot;
-    dispatcher_send_message(&qxl_state->dispatcher, message, &payload);
+    dispatcher_send_message(qxl_state->dispatcher, message, &payload);
 }
 
 static void red_qxl_del_memslot(QXLState *qxl_state, uint32_t slot_group_id, uint32_t slot_id)
@@ -294,7 +294,7 @@ static void red_qxl_del_memslot(QXLState *qxl_state, uint32_t slot_group_id, uin
 
     payload.slot_group_id = slot_group_id;
     payload.slot_id = slot_id;
-    dispatcher_send_message(&qxl_state->dispatcher, message, &payload);
+    dispatcher_send_message(qxl_state->dispatcher, message, &payload);
 }
 
 static void qxl_worker_del_memslot(QXLWorker *qxl_worker, uint32_t slot_group_id, uint32_t slot_id)
@@ -306,7 +306,7 @@ static void red_qxl_destroy_surfaces(QXLState *qxl_state)
 {
     RedWorkerMessageDestroySurfaces payload;
 
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_DESTROY_SURFACES,
                             &payload);
 }
@@ -322,7 +322,7 @@ static void red_qxl_destroy_surfaces_async(QXLState *qxl_state, uint64_t cookie)
     RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC;
 
     payload.base.cmd = async_command_alloc(qxl_state, message, cookie);
-    dispatcher_send_message(&qxl_state->dispatcher, message, &payload);
+    dispatcher_send_message(qxl_state->dispatcher, message, &payload);
 }
 
 static void red_qxl_destroy_primary_surface_complete(QXLState *qxl_state)
@@ -341,7 +341,7 @@ red_qxl_destroy_primary_surface_sync(QXLState *qxl_state,
 {
     RedWorkerMessageDestroyPrimarySurface payload;
     payload.surface_id = surface_id;
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE,
                             &payload);
     red_qxl_destroy_primary_surface_complete(qxl_state);
@@ -356,7 +356,7 @@ red_qxl_destroy_primary_surface_async(QXLState *qxl_state,
 
     payload.base.cmd = async_command_alloc(qxl_state, message, cookie);
     payload.surface_id = surface_id;
-    dispatcher_send_message(&qxl_state->dispatcher, message, &payload);
+    dispatcher_send_message(qxl_state->dispatcher, message, &payload);
 }
 
 static void
@@ -399,7 +399,7 @@ red_qxl_create_primary_surface_async(QXLState *qxl_state, uint32_t surface_id,
     payload.base.cmd = async_command_alloc(qxl_state, message, cookie);
     payload.surface_id = surface_id;
     payload.surface = *surface;
-    dispatcher_send_message(&qxl_state->dispatcher, message, &payload);
+    dispatcher_send_message(qxl_state->dispatcher, message, &payload);
 }
 
 static void
@@ -411,7 +411,7 @@ red_qxl_create_primary_surface_sync(QXLState *qxl_state, uint32_t surface_id,
     qxl_state->surface_create = *surface;
     payload.surface_id = surface_id;
     payload.surface = *surface;
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE,
                             &payload);
     red_qxl_create_primary_surface_complete(qxl_state);
@@ -438,7 +438,7 @@ static void red_qxl_reset_image_cache(QXLState *qxl_state)
 {
     RedWorkerMessageResetImageCache payload;
 
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_RESET_IMAGE_CACHE,
                             &payload);
 }
@@ -452,7 +452,7 @@ static void red_qxl_reset_cursor(QXLState *qxl_state)
 {
     RedWorkerMessageResetCursor payload;
 
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_RESET_CURSOR,
                             &payload);
 }
@@ -468,7 +468,7 @@ static void red_qxl_destroy_surface_wait_sync(QXLState *qxl_state,
     RedWorkerMessageDestroySurfaceWait payload;
 
     payload.surface_id = surface_id;
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT,
                             &payload);
 }
@@ -482,7 +482,7 @@ static void red_qxl_destroy_surface_wait_async(QXLState *qxl_state,
 
     payload.base.cmd = async_command_alloc(qxl_state, message, cookie);
     payload.surface_id = surface_id;
-    dispatcher_send_message(&qxl_state->dispatcher, message, &payload);
+    dispatcher_send_message(qxl_state->dispatcher, message, &payload);
 }
 
 static void red_qxl_destroy_surface_wait(QXLState *qxl_state,
@@ -505,7 +505,7 @@ static void red_qxl_reset_memslots(QXLState *qxl_state)
 {
     RedWorkerMessageResetMemslots payload;
 
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_RESET_MEMSLOTS,
                             &payload);
 }
@@ -533,7 +533,7 @@ static void red_qxl_wakeup(QXLState *qxl_state)
     if (red_qxl_set_pending(qxl_state, RED_DISPATCHER_PENDING_WAKEUP))
         return;
 
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_WAKEUP,
                             &payload);
 }
@@ -550,7 +550,7 @@ static void red_qxl_oom(QXLState *qxl_state)
     if (red_qxl_set_pending(qxl_state, RED_DISPATCHER_PENDING_OOM))
         return;
 
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_OOM,
                             &payload);
 }
@@ -564,7 +564,7 @@ void red_qxl_start(QXLState *qxl_state)
 {
     RedWorkerMessageStart payload;
 
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_START,
                             &payload);
 }
@@ -580,7 +580,7 @@ static void red_qxl_flush_surfaces_async(QXLState *qxl_state, uint64_t cookie)
     RedWorkerMessage message = RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC;
 
     payload.base.cmd = async_command_alloc(qxl_state, message, cookie);
-    dispatcher_send_message(&qxl_state->dispatcher, message, &payload);
+    dispatcher_send_message(qxl_state->dispatcher, message, &payload);
 }
 
 static void red_qxl_monitors_config_async(QXLState *qxl_state,
@@ -596,14 +596,14 @@ static void red_qxl_monitors_config_async(QXLState *qxl_state,
     payload.group_id = group_id;
     payload.max_monitors = qxl_state->max_monitors;
 
-    dispatcher_send_message(&qxl_state->dispatcher, message, &payload);
+    dispatcher_send_message(qxl_state->dispatcher, message, &payload);
 }
 
 static void red_qxl_driver_unload(QXLState *qxl_state)
 {
     RedWorkerMessageDriverUnload payload;
 
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_DRIVER_UNLOAD,
                             &payload);
 }
@@ -612,7 +612,7 @@ void red_qxl_stop(QXLState *qxl_state)
 {
     RedWorkerMessageStop payload;
 
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_STOP,
                             &payload);
 }
@@ -631,7 +631,7 @@ static void red_qxl_loadvm_commands(QXLState *qxl_state,
     spice_printerr("");
     payload.count = count;
     payload.ext = ext;
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_LOADVM_COMMANDS,
                             &payload);
 }
@@ -871,7 +871,7 @@ void spice_qxl_gl_scanout(QXLInstance *qxl,
     pthread_mutex_unlock(&qxl_state->scanout_mutex);
 
     /* FIXME: find a way to coallesce all pending SCANOUTs */
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_GL_SCANOUT, NULL);
 }
 
@@ -896,7 +896,7 @@ void spice_qxl_gl_draw_async(QXLInstance *qxl,
     spice_return_if_fail(qxl_state->gl_draw_async == NULL);
 
     qxl_state->gl_draw_async = async_command_alloc(qxl_state, message, cookie);
-    dispatcher_send_message(&qxl_state->dispatcher, message, &draw);
+    dispatcher_send_message(qxl_state->dispatcher, message, &draw);
 }
 
 void red_qxl_async_complete(QXLState *qxl_state,
@@ -954,7 +954,7 @@ void red_qxl_init(RedsState *reds, QXLInstance *qxl)
     qxl_state->qxl = qxl;
     pthread_mutex_init(&qxl_state->scanout_mutex, NULL);
     qxl_state->scanout.drm_dma_buf_fd = -1;
-    dispatcher_init(&qxl_state->dispatcher, RED_WORKER_MESSAGE_COUNT, NULL);
+    qxl_state->dispatcher = dispatcher_new(RED_WORKER_MESSAGE_COUNT, NULL);
     qxl_state->base.major_version = SPICE_INTERFACE_QXL_MAJOR;
     qxl_state->base.minor_version = SPICE_INTERFACE_QXL_MINOR;
     qxl_state->base.wakeup = qxl_worker_wakeup;
@@ -1003,15 +1003,15 @@ void red_qxl_init(RedsState *reds, QXLInstance *qxl)
     red_worker_run(worker);
 }
 
-struct Dispatcher *red_qxl_get_dispatcher(QXLState *qxl_state)
+Dispatcher *red_qxl_get_dispatcher(QXLState *qxl_state)
 {
-    return &qxl_state->dispatcher;
+    return qxl_state->dispatcher;
 }
 
 void red_qxl_set_dispatcher_opaque(QXLState *qxl_state,
                                    void *opaque)
 {
-    dispatcher_set_opaque(&qxl_state->dispatcher, opaque);
+    dispatcher_set_opaque(qxl_state->dispatcher, opaque);
 }
 
 void red_qxl_clear_pending(QXLState *qxl_state, int pending)
@@ -1041,7 +1041,7 @@ void red_qxl_on_ic_change(QXLState *qxl_state, SpiceImageCompression ic)
 {
     RedWorkerMessageSetCompression payload;
     payload.image_compression = ic;
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_SET_COMPRESSION,
                             &payload);
 }
@@ -1050,7 +1050,7 @@ void red_qxl_on_sv_change(QXLState *qxl_state, int sv)
 {
     RedWorkerMessageSetStreamingVideo payload;
     payload.streaming_video = sv;
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_SET_STREAMING_VIDEO,
                             &payload);
 }
@@ -1059,7 +1059,7 @@ void red_qxl_set_mouse_mode(QXLState *qxl_state, uint32_t mode)
 {
     RedWorkerMessageSetMouseMode payload;
     payload.mode = mode;
-    dispatcher_send_message(&qxl_state->dispatcher,
+    dispatcher_send_message(qxl_state->dispatcher,
                             RED_WORKER_MESSAGE_SET_MOUSE_MODE,
                             &payload);
 }
diff --git a/server/red-qxl.h b/server/red-qxl.h
index f100cb4..16a348d 100644
--- a/server/red-qxl.h
+++ b/server/red-qxl.h
@@ -19,6 +19,7 @@
 #define _H_RED_DISPATCHER
 
 #include "red-channel.h"
+#include "dispatcher.h"
 
 typedef struct QXLState QXLState;
 
@@ -36,7 +37,7 @@ void red_qxl_stop(QXLState *qxl_state);
 void red_qxl_start(QXLState *qxl_state);
 uint32_t red_qxl_get_ram_size(QXLState *qxl_state);
 void red_qxl_async_complete(QXLState *qxl_state, AsyncCommand *cmd);
-struct Dispatcher *red_qxl_get_dispatcher(QXLState *qxl_state);
+Dispatcher *red_qxl_get_dispatcher(QXLState *qxl_state);
 gboolean red_qxl_use_client_monitors_config(QXLState *qxl_state);
 gboolean red_qxl_client_monitors_config(QXLState *qxl_state, VDAgentMonitorsConfig *monitors_config);
 gboolean red_qxl_get_primary_active(QXLState *qxl_state);
-- 
2.5.0

_______________________________________________
Spice-devel mailing list
Spice-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/spice-devel





[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]     [Monitors]