#include <dlfcn.h>
#include <Eina.h>
#include <math.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <X11/Xlib.h>
#include <widget_conf.h>
#include <widget_buffer.h>
#include <widget_provider.h>
+#include <widget_provider_buffer.h>
#include <widget_util.h>
+#include <libgen.h>
#include "widget.h"
#include "widget_internal.h"
#define WIDGET_DEFAULT_WIDTH 1
#define WIDGET_DEFAULT_HEIGHT 1
+#define MOUSE_BUTTON_LEFT 1
+
+/**
+ * @note
+ * Supported touch devices are limited to 32.
+ * Because of count of bits of integer type. (32 bits)
+ */
+#define MAX_DEVICE 32
+
+#define IS_PRESSED(info, device) (((device) < MAX_DEVICE) ? (((info)->pressed & (0x01 << (device))) == (0x01 << (device))) : 0)
+
+/**
+ * @note
+ * Short-Circuit
+ */
+#define SET_PRESSED(info, device) ((void)(((device) < MAX_DEVICE) && (((info)->pressed |= (0x01 << (device))))))
+#define SET_RELEASED(info, device) ((void)(((device) < MAX_DEVICE) && (((info)->pressed &= (~(0x01 << (device)))))))
+
static inline Evas_Object *get_highlighted_object(Evas_Object *obj)
{
Evas_Object *o, *ho;
flags |= EVAS_EVENT_FLAG_ON_HOLD;
evas_event_default_flags_set(info->e, flags);
ErrPrint("ON_HOLD[%s] %dx%d - %lf\n", info->id, event_info->info.pointer.x, event_info->info.pointer.y, timestamp);
+ if (info->pressed == 0) {
+ info->flags.field.on_hold_before_down = 1;
+ }
break;
case WIDGET_BUFFER_EVENT_OFF_HOLD:
flags = evas_event_default_flags_get(info->e);
flags = evas_event_default_flags_get(info->e);
flags |= EVAS_EVENT_FLAG_ON_SCROLL;
evas_event_default_flags_set(info->e, flags);
+ if (info->pressed == 0) {
+ info->flags.field.on_scroll_before_down = 1;
+ }
break;
case WIDGET_BUFFER_EVENT_OFF_SCROLL:
flags = evas_event_default_flags_get(info->e);
case WIDGET_BUFFER_EVENT_DOWN:
apply_orientation(info->orientation, &event_info->info.pointer.x, &event_info->info.pointer.y, info->w, info->h, event_info->info.pointer.source);
- if (info->pressed) {
+ if (IS_PRESSED(info, event_info->info.pointer.device)) {
ErrPrint("MOUSE UP is not called\n");
- ErrPrint("UP[%s] %dx%d - %lf\n", info->id, event_info->info.pointer.x, event_info->info.pointer.y, timestamp);
- evas_event_feed_mouse_move(info->e, event_info->info.pointer.x, event_info->info.pointer.y, timestamp, NULL);
- evas_event_feed_mouse_up(info->e, 1, EVAS_BUTTON_NONE, timestamp, NULL);
+ ErrPrint("UP[%s] %dx%d - %lf (%d)\n", info->id, event_info->info.pointer.x, event_info->info.pointer.y, timestamp, event_info->info.pointer.device);
+ if (event_info->info.pointer.device > 0) {
+ /**
+ * @multi touch up
+ */
+ evas_event_feed_multi_up(info->e, event_info->info.pointer.device, event_info->info.pointer.x, event_info->info.pointer.y,
+ 0.0f, 0.0f, 0.0f, /* radius, radius_x, radius_y */
+ 0.0f, 0.0f, 0.0f, 0.0f, /* pressure, angle, fx, fy */
+ EVAS_BUTTON_NONE, timestamp, NULL); /* button_flags, timestamp, ... */
+ } else {
+ evas_event_feed_mouse_move(info->e, event_info->info.pointer.x, event_info->info.pointer.y, timestamp, NULL);
+ evas_event_feed_mouse_up(info->e, MOUSE_BUTTON_LEFT, EVAS_BUTTON_NONE, timestamp, NULL);
+ }
}
/**
* Before processing the DOWN event,
* Reset the evas event flags regarding ON_HOLD option.
* It can be re-enabled while processing down-move-up events.
+ * However if those events are occurred right before DOWN,
+ * Do not clear it.
+ * Some speicific cases, the ON_HOLD(ON_SCROLL) event can be delievered
+ * before MOUSE_DOWN event.
*/
flags = evas_event_default_flags_get(info->e);
- flags &= ~EVAS_EVENT_FLAG_ON_SCROLL;
- flags &= ~EVAS_EVENT_FLAG_ON_HOLD;
+ if (!info->flags.field.on_hold_before_down) {
+ flags &= ~EVAS_EVENT_FLAG_ON_HOLD;
+ }
+ if (!info->flags.field.on_scroll_before_down) {
+ flags &= ~EVAS_EVENT_FLAG_ON_SCROLL;
+ }
evas_event_default_flags_set(info->e, flags);
+
+ /**
+ * @note
+ * Reset flags after dealing with the ON_HOLD/ON_SCROLL event
+ */
+ info->flags.field.on_scroll_before_down = 0;
+ info->flags.field.on_hold_before_down = 0;
/**
* @note
* Calculate the event occurred X & Y on the buffer
*/
- evas_event_feed_mouse_move(info->e, event_info->info.pointer.x, event_info->info.pointer.y, timestamp, NULL);
- evas_event_feed_mouse_down(info->e, 1, EVAS_BUTTON_NONE, timestamp, NULL); /* + 0.2f just for fake event */
- info->pressed = 1;
- ErrPrint("DOWN[%s] %dx%d - %lf\n", info->id, event_info->info.pointer.x, event_info->info.pointer.y, timestamp);
+ if (event_info->info.pointer.device > 0) {
+ evas_event_feed_multi_down(info->e, event_info->info.pointer.device, event_info->info.pointer.x, event_info->info.pointer.y,
+ 0.0f, 0.0f, 0.0f, /* radius, radius_x, radius_y */
+ 0.0f, 0.0f, 0.0f, 0.0f, /* pressure, angle, fx, fy */
+ EVAS_BUTTON_NONE, timestamp, NULL); /* button_flags, timestamp, ... */
+ } else {
+ evas_event_feed_mouse_move(info->e, event_info->info.pointer.x, event_info->info.pointer.y, timestamp, NULL);
+ evas_event_feed_mouse_down(info->e, MOUSE_BUTTON_LEFT, EVAS_BUTTON_NONE, timestamp, NULL); /* + 0.2f just for fake event */
+ }
+
+ SET_PRESSED(info, event_info->info.pointer.device);
+ ErrPrint("DOWN[%s] %dx%d - %lf (%d)\n", info->id, event_info->info.pointer.x, event_info->info.pointer.y, timestamp, event_info->info.pointer.device);
break;
case WIDGET_BUFFER_EVENT_MOVE:
apply_orientation(info->orientation, &event_info->info.pointer.x, &event_info->info.pointer.y, info->w, info->h, event_info->info.pointer.source);
* @note
* Calculate the event occurred X & Y on the buffer
*/
- evas_event_feed_mouse_move(info->e, event_info->info.pointer.x, event_info->info.pointer.y, timestamp, NULL);
+ if (event_info->info.pointer.device > 0) {
+ evas_event_feed_multi_move(info->e, event_info->info.pointer.device, event_info->info.pointer.x, event_info->info.pointer.y,
+ 0.0f, 0.0f, 0.0f, /* radius, radius_x, radius_y */
+ 0.0f, 0.0f, 0.0f, 0.0f, /* pressure, angle, fx, fy */
+ timestamp, NULL); /* timestamp, ... */
+ } else {
+ evas_event_feed_mouse_move(info->e, event_info->info.pointer.x, event_info->info.pointer.y, timestamp, NULL);
+ }
break;
case WIDGET_BUFFER_EVENT_UP:
apply_orientation(info->orientation, &event_info->info.pointer.x, &event_info->info.pointer.y, info->w, info->h, event_info->info.pointer.source);
- evas_event_feed_mouse_move(info->e, event_info->info.pointer.x, event_info->info.pointer.y, timestamp, NULL);
- evas_event_feed_mouse_up(info->e, 1, EVAS_BUTTON_NONE, timestamp, NULL);
- info->pressed = 0;
+
+ if (event_info->info.pointer.device > 0) {
+ evas_event_feed_multi_up(info->e, event_info->info.pointer.device, event_info->info.pointer.x, event_info->info.pointer.y,
+ 0.0f, 0.0f, 0.0f, /* radius, radius_x, radius_y */
+ 0.0f, 0.0f, 0.0f, 0.0f, /* pressure, angle, fx, fy */
+ EVAS_BUTTON_NONE, timestamp, NULL); /* button_flags, timestamp, ... */
+ } else {
+ evas_event_feed_mouse_move(info->e, event_info->info.pointer.x, event_info->info.pointer.y, timestamp, NULL);
+ evas_event_feed_mouse_up(info->e, MOUSE_BUTTON_LEFT, EVAS_BUTTON_NONE, timestamp, NULL);
+ }
+ SET_RELEASED(info, event_info->info.pointer.device);
/**
* @note
* We have to keep the event flags, so we should not clear them from here.
* Sometimes, asynchronously callable Callbacks can refer the evas event flags after up event.
* so if we reset them from here, those kind of callbacks will fails to do their job properly.
*/
- ErrPrint("UP[%s] %dx%d - %lf\n", info->id, event_info->info.pointer.x, event_info->info.pointer.y, timestamp);
+ ErrPrint("UP[%s] %dx%d - %lf (%d)\n", info->id, event_info->info.pointer.x, event_info->info.pointer.y, timestamp, event_info->info.pointer.device);
break;
case WIDGET_BUFFER_EVENT_ACCESS_HIGHLIGHT:
parent_elm = ecore_evas_data_get(info->ee, WIDGET_WIN_TAG);
break;
}
+ return ret;
}
static Eina_Bool pended_event_consumer_cb(void *data)
* because it will waiting result of event processing to do handles state properly.
*/
- if (!info || info->state != VWIN_INFO_CREATED || !info->handle || info->deleted) {
+ if (!info || info->state != VWIN_INFO_CREATED || !info->handle || info->flags.field.deleted) {
/* Just ignore this event */
return 0;
}
}
}
- return;
+ return 0;
}
if (WIDGET_CONF_USE_GETTIMEOFDAY) {
return;
}
- if (widget_conf_premultiplied_alpha()) {
+ if (WIDGET_CONF_PREMULTIPLIED_COLOR) {
Evas_Coord w;
Evas_Coord h;
}
}
+static inline void dump_to_file(void *buffer, int size, const char *fname)
+{
+ int fd;
+
+ fd = open(fname, O_WRONLY | O_CREAT, 0644);
+ if (fd >= 0) {
+ if (write(fd, buffer, size) != size) {
+ ErrPrint("write: %d\n", errno);
+ }
+
+ if (close(fd) < 0) {
+ ErrPrint("close: %d\n", errno);
+ }
+ }
+}
+
static void post_render_cb(void *data, Evas *e, void *event_info)
{
vwin_info_t info = data;
+ const char *ee_key;
if (!info || info->state != VWIN_INFO_CREATED || !info->handle) {
return;
}
- if (widget_conf_premultiplied_alpha()) {
- void *canvas;
- int x, y, w, h;
-
- // Get a pointer of a buffer of the virtual canvas
- canvas = (void *)ecore_evas_buffer_pixels_get(info->ee);
- if (!canvas) {
- ErrPrint("Failed to get pixel canvas\n");
+ ee_key = WIDGET_CONF_EE_KEY_FOR_UPDATE;
+ if (ee_key) {
+ const char *value;
+ value = ecore_evas_data_get(info->ee, ee_key);
+ if (value && strcmp(value, "true")) {
+ DbgPrint("Frame skipped[%s]\n", value);
return;
}
-
- ecore_evas_geometry_get(info->ee, &x, &y, &w, &h);
- evas_data_argb_unpremul(canvas, w * h);
+ ecore_evas_data_set(info->ee, ee_key, "false");
}
- if (info->type == VWIN_GEM) {
- widget_buffer_post_render(info->handle);
- } else if (info->type == VWIN_PIXMAP) {
+ if (info->type == VWIN_PIXMAP) {
int idx;
unsigned int front_resource_id;
for (idx = 0; idx < WIDGET_CONF_EXTRA_BUFFER_COUNT; idx++) {
if (front_resource_id == info->resource_array[idx]) {
- /**
- */
- widget_send_updated_by_idx(info->handle, idx);
break;
}
}
if (idx == WIDGET_CONF_EXTRA_BUFFER_COUNT) {
- /* Send updated event for PRIMARY BUFFER */
- if (front_resource_id == widget_viewer_get_resource_id(info->handle, WIDGET_PRIMARY_BUFFER)) {
- widget_send_updated_by_idx(info->handle, WIDGET_PRIMARY_BUFFER);
- } else {
- DbgPrint("Unable to send updated: %u (%u)\n", front_resource_id, widget_viewer_get_resource_id(info->handle, WIDGET_PRIMARY_BUFFER));
+ idx = WIDGET_PRIMARY_BUFFER;
+ }
+
+ /* Send updated event for PRIMARY BUFFER */
+ if (front_resource_id == widget_viewer_get_resource_id(info->handle, idx)) {
+ if (info->ctrl_mode.dump_to_file) {
+ char fname[512];
+ void *canvas;
+
+ snprintf(fname, sizeof(fname) - 1, "/tmp/%s.%u.%lf.raw", widget_util_basename(info->id), front_resource_id, ecore_time_get());
+ canvas = widget_provider_buffer_dump_frame(info->handle, idx);
+ if (canvas) {
+ int w, h;
+ int size;
+
+ ecore_evas_geometry_get(info->ee, NULL, NULL, &w, &h);
+ size = w * h * sizeof(int);
+
+ dump_to_file(canvas, size, fname);
+ free(canvas);
+ }
}
+ widget_send_updated_by_idx(info->handle, idx);
+ } else {
+ DbgPrint("Unable to send updated: %u (%u)\n", front_resource_id, widget_viewer_get_resource_id(info->handle, idx));
}
- } else if (info->type == VWIN_SW_BUF) {
- widget_viewer_sync_buffer(info->handle);
+ } else {
+ if (WIDGET_CONF_PREMULTIPLIED_COLOR) {
+ void *canvas;
+ int w, h;
+
+ // Get a pointer of a buffer of the virtual canvas
+ canvas = (void *)ecore_evas_buffer_pixels_get(info->ee);
+ if (!canvas) {
+ ErrPrint("Failed to get pixel canvas\n");
+ return;
+ }
+
+ ecore_evas_geometry_get(info->ee, NULL, NULL, &w, &h);
+ evas_data_argb_unpremul(canvas, w * h);
+ }
+
+ if (info->ctrl_mode.dump_to_file) {
+ void *canvas;
+ char fname[512];
+ int size;
+ int w, h;
+
+ canvas = (void *)ecore_evas_buffer_pixels_get(info->ee);
+ if (!canvas) {
+ ErrPrint("Failed to get pixel canvas\n");
+ return;
+ }
+
+ /**
+ * TODO
+ * Save to a file
+ */
+ ecore_evas_geometry_get(info->ee, NULL, NULL, &w, &h);
+ size = w * h * sizeof(int);
+
+ snprintf(fname, sizeof(fname) - 1, "/tmp/%s.%lf.raw", widget_util_basename(info->id), ecore_time_get());
+ dump_to_file(canvas, size, fname);
+ }
+
+ if (info->type == VWIN_GEM) {
+ widget_buffer_post_render(info->handle);
+ } else if (info->type == VWIN_SW_BUF) {
+ widget_viewer_sync_buffer(info->handle);
+ }
+ }
+}
+
+static int pre_ctrl_mode_cb(const char *id, void *data)
+{
+ vwin_info_t info = data;
+ const char *path;
+ int cmd;
+ int value;
+
+ /* Try provider_app first */
+ if (!info || info->state != VWIN_INFO_CREATED || !id || !info->id) {
+ return WIDGET_ERROR_INVALID_PARAMETER;
}
+
+ path = widget_util_uri_to_path(id);
+ if (path && strcmp(info->id, path)) {
+ /* Skip */
+ DbgPrint("SKIP: Pre orientation event callback is called [%s], %s\n", id, info->id);
+ return WIDGET_ERROR_INVALID_PARAMETER;
+ }
+
+ widget_get_last_ctrl_mode(path, &cmd, &value);
+
+ if (cmd == WIDGET_CTRL_MODE_DUMP_FRAME) {
+ info->ctrl_mode.dump_to_file = !!value;
+ DbgPrint("CtrlMode: DumpToFile: %d\n", info->ctrl_mode.dump_to_file);
+ }
+
+ return WIDGET_ERROR_NONE;
}
static int pre_orientation_cb(const char *id, void *data)
}
widget_del_pre_callback(WIDGET_PRE_DESTROY_CALLBACK, pre_destroy_cb, info);
+ widget_del_pre_callback(WIDGET_PRE_CTRL_MODE_CALLBACK, pre_ctrl_mode_cb, info);
if (info->e) {
evas_event_callback_del(info->e, EVAS_CALLBACK_RENDER_POST, post_render_cb);
evas_event_callback_del(info->e, EVAS_CALLBACK_RENDER_PRE, pre_render_cb);
}
- info->deleted = 1;
+ info->flags.field.deleted = 1;
info->ee = NULL;
}
}
#ifdef WIDGET_FEATURE_GBAR_SUPPORTED
- info->is_gbar = is_gbar;
+ info->flags.field.is_gbar = is_gbar;
#else
- info->is_gbar = 0;
+ info->flags.field.is_gbar = 0;
#endif /* WIDGET_FEATURE_GBAR_SUPPORTED */
/**
* Acquire a buffer for canvas.
*/
- info->handle = widget_create_buffer(info->id, info->is_gbar,
+ info->handle = widget_create_buffer(info->id, info->flags.field.is_gbar,
binder_widget_auto_align(),
event_handler_cb, info);
widget_add_pre_callback(WIDGET_PRE_DESTROY_CALLBACK, pre_destroy_cb, info);
widget_add_pre_callback(WIDGET_PRE_ORIENTATION_CALLBACK, pre_orientation_cb, info);
+ widget_add_pre_callback(WIDGET_PRE_CTRL_MODE_CALLBACK, pre_ctrl_mode_cb, info);
orientation = widget_get_orientation(info->id);
if (orientation < 0) {