add stamp to vblank objects
[platform/core/uifw/libtdm.git] / client / tdm_client.c
index 858e4f5..cd74513 100644 (file)
@@ -76,6 +76,7 @@ typedef struct _tdm_private_client_output {
        struct list_head change_handler_list;
 
        unsigned int req_id;
+       unsigned int watch_output_changes;
 
        struct list_head link;
 } tdm_private_client_output;
@@ -93,6 +94,7 @@ struct _tdm_private_client_vblank {
        unsigned int enable_fake;
 
        unsigned int started;
+       unsigned int stamp;
 
        double last_time;
 
@@ -122,6 +124,16 @@ typedef struct _tdm_client_wait_info {
 } tdm_client_wait_info;
 
 static void
+_tdm_client_vblank_cb_stamp(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t stamp)
+{
+       tdm_private_client_vblank *private_vblank = data;
+
+       TDM_RETURN_IF_FAIL(private_vblank != NULL);
+
+       private_vblank->stamp = stamp;
+}
+
+static void
 _tdm_client_vblank_cb_done(void *data, struct wl_tdm_vblank *wl_tdm_vblank,
                                                   uint32_t req_id, uint32_t sequence, uint32_t tv_sec,
                                                   uint32_t tv_usec, uint32_t error)
@@ -158,6 +170,7 @@ _tdm_client_vblank_cb_done(void *data, struct wl_tdm_vblank *wl_tdm_vblank,
 }
 
 static const struct wl_tdm_vblank_listener tdm_client_vblank_listener = {
+       _tdm_client_vblank_cb_stamp,
        _tdm_client_vblank_cb_done,
 };
 
@@ -187,7 +200,7 @@ _tdm_client_output_destroy(tdm_private_client_output *private_output)
 
 static void
 _tdm_client_output_cb_mode(void *data, struct wl_tdm_output *wl_tdm_output,
-                                                  uint32_t width, uint32_t height, uint32_t refresh)
+                                                  uint32_t width, uint32_t height, uint32_t refresh, uint32_t error)
 {
        tdm_private_client_output *private_output = (tdm_private_client_output*)data;
 
@@ -197,13 +210,16 @@ _tdm_client_output_cb_mode(void *data, struct wl_tdm_output *wl_tdm_output,
        private_output->height = height;
        private_output->refresh = refresh;
 
+       if (error != TDM_ERROR_NONE)
+               TDM_INFO("mode event error: %d", error);
+
        TDM_DBG("private_output(%p) wl_tbm_output@%d width(%d) height(%d) refresh(%d)",
                        private_output, wl_proxy_get_id((struct wl_proxy*)private_output->output),
                        width, height, refresh);
 }
 
 static void
-_tdm_client_output_cb_connection(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value)
+_tdm_client_output_cb_connection(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error)
 {
        tdm_private_client_output *private_output = (tdm_private_client_output*)data;
        tdm_client_output_handler_info *h = NULL;
@@ -216,6 +232,9 @@ _tdm_client_output_cb_connection(void *data, struct wl_tdm_output *wl_tdm_output
 
        private_output->connection = value;
 
+       if (error != TDM_ERROR_NONE)
+               TDM_INFO("connection event error: %d", error);
+
        TDM_DBG("private_output(%p) wl_tbm_output@%d connection(%d)",
                        private_output,
                        wl_proxy_get_id((struct wl_proxy*)private_output->output),
@@ -229,7 +248,7 @@ _tdm_client_output_cb_connection(void *data, struct wl_tdm_output *wl_tdm_output
 }
 
 static void
-_tdm_client_output_cb_dpms(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value)
+_tdm_client_output_cb_dpms(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error)
 {
        tdm_private_client_output *private_output = (tdm_private_client_output*)data;
        tdm_client_output_handler_info *h = NULL;
@@ -242,6 +261,9 @@ _tdm_client_output_cb_dpms(void *data, struct wl_tdm_output *wl_tdm_output, uint
 
        private_output->dpms = value;
 
+       if (error != TDM_ERROR_NONE)
+               TDM_INFO("dpms event error: %d", error);
+
        TDM_DBG("private_output(%p) wl_tbm_output@%d dpms(%d)",
                        private_output,
                        wl_proxy_get_id((struct wl_proxy*)private_output->output),
@@ -508,9 +530,18 @@ tdm_client_output_add_change_handler(tdm_client_output *output,
        h = calloc(1, sizeof *h);
        TDM_RETURN_VAL_IF_FAIL(h != NULL, TDM_ERROR_OUT_OF_MEMORY);
 
-       if (LIST_IS_EMPTY(&private_output->change_handler_list))
+       if (LIST_IS_EMPTY(&private_output->change_handler_list)) {
                wl_tdm_output_watch_output_changes(private_output->output, 1);
 
+               /* TODO: this is very tricky.
+                * If a client adds the change_handler, we might be able to guess that
+                * the client will watch the tdm client's fd and handle tdm events in
+                * event loop. Otherwise, we CAN'T make sure if a client has event loop
+                * which handles tdm events.
+                */
+               private_output->watch_output_changes = 1;
+       }
+
        h->private_output = private_output;
        h->func = func;
        h->user_data = user_data;
@@ -550,12 +581,24 @@ tdm_error
 tdm_client_output_get_refresh_rate(tdm_client_output *output, unsigned int *refresh)
 {
        tdm_private_client_output *private_output;
+       tdm_private_client *private_client;
 
        TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
        TDM_RETURN_VAL_IF_FAIL(refresh != NULL, TDM_ERROR_INVALID_PARAMETER);
 
        private_output = (tdm_private_client_output*)output;
 
+       if (private_output->watch_output_changes) {
+               *refresh = private_output->refresh;
+               return TDM_ERROR_NONE;
+       }
+
+       private_client = private_output->private_client;
+       TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+       wl_tdm_output_get_mode(private_output->output);
+       wl_display_roundtrip(private_client->display);
+
        *refresh = private_output->refresh;
 
        return TDM_ERROR_NONE;
@@ -565,12 +608,24 @@ tdm_error
 tdm_client_output_get_conn_status(tdm_client_output *output, tdm_output_conn_status *status)
 {
        tdm_private_client_output *private_output;
+       tdm_private_client *private_client;
 
        TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
        TDM_RETURN_VAL_IF_FAIL(status != NULL, TDM_ERROR_INVALID_PARAMETER);
 
        private_output = (tdm_private_client_output*)output;
 
+       if (private_output->watch_output_changes) {
+               *status = private_output->connection;
+               return TDM_ERROR_NONE;
+       }
+
+       private_client = private_output->private_client;
+       TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+       wl_tdm_output_get_connection(private_output->output);
+       wl_display_roundtrip(private_client->display);
+
        *status = private_output->connection;
 
        return TDM_ERROR_NONE;
@@ -580,12 +635,24 @@ tdm_error
 tdm_client_output_get_dpms(tdm_client_output *output, tdm_output_dpms *dpms)
 {
        tdm_private_client_output *private_output;
+       tdm_private_client *private_client;
 
        TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
        TDM_RETURN_VAL_IF_FAIL(dpms != NULL, TDM_ERROR_INVALID_PARAMETER);
 
        private_output = (tdm_private_client_output*)output;
 
+       if (private_output->watch_output_changes) {
+               *dpms = private_output->dpms;
+               return TDM_ERROR_NONE;
+       }
+
+       private_client = private_output->private_client;
+       TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+       wl_tdm_output_get_dpms(private_output->output);
+       wl_display_roundtrip(private_client->display);
+
        *dpms = private_output->dpms;
 
        return TDM_ERROR_NONE;
@@ -594,6 +661,7 @@ tdm_client_output_get_dpms(tdm_client_output *output, tdm_output_dpms *dpms)
 tdm_client_vblank*
 tdm_client_output_create_vblank(tdm_client_output *output, tdm_error *error)
 {
+       tdm_private_client *private_client;
        tdm_private_client_output *private_output;
        tdm_private_client_vblank *private_vblank;
 
@@ -608,6 +676,14 @@ tdm_client_output_create_vblank(tdm_client_output *output, tdm_error *error)
        }
 
        private_output = (tdm_private_client_output*)output;
+       private_client = private_output->private_client;
+
+       if (!private_client) {
+               TDM_ERR("'!private_client' failed");
+               if (error)
+                       *error = TDM_ERROR_INVALID_PARAMETER;
+               return NULL;
+       }
 
        private_vblank = calloc(1, sizeof *private_vblank);
        if (!private_vblank) {
@@ -638,6 +714,7 @@ tdm_client_output_create_vblank(tdm_client_output *output, tdm_error *error)
 
        wl_tdm_vblank_add_listener(private_vblank->vblank,
                                                           &tdm_client_vblank_listener, private_vblank);
+       wl_display_roundtrip(private_client->display);
 
        return (tdm_client_vblank*)private_vblank;
 }
@@ -778,9 +855,15 @@ tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_cli
        if (!private_vblank->started)
                private_vblank->started = 1;
 
-       if (private_output->dpms != TDM_OUTPUT_DPMS_ON && !private_vblank->enable_fake) {
-               TDM_INFO("dpms off");
-               return TDM_ERROR_DPMS_OFF;
+       if (private_output->watch_output_changes && !private_vblank->enable_fake) {
+               if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
+                       TDM_ERR("output disconnected");
+                       return TDM_ERROR_OUTPUT_DISCONNECTED;
+               }
+               if (private_output->dpms != TDM_OUTPUT_DPMS_ON) {
+                       TDM_ERR("dpms off");
+                       return TDM_ERROR_DPMS_OFF;
+               }
        }
 
        w = calloc(1, sizeof *w);
@@ -854,9 +937,15 @@ tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence,
        if (!private_vblank->started)
                private_vblank->started = 1;
 
-       if (private_output->dpms != TDM_OUTPUT_DPMS_ON && !private_vblank->enable_fake) {
-               TDM_INFO("dpms off");
-               return TDM_ERROR_DPMS_OFF;
+       if (private_output->watch_output_changes && !private_vblank->enable_fake) {
+               if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
+                       TDM_ERR("output disconnected");
+                       return TDM_ERROR_OUTPUT_DISCONNECTED;
+               }
+               if (private_output->dpms != TDM_OUTPUT_DPMS_ON) {
+                       TDM_ERR("dpms off");
+                       return TDM_ERROR_DPMS_OFF;
+               }
        }
 
        w = calloc(1, sizeof *w);