efl/src/modules/ecore_evas/engines/x/ecore_evas_x.c

5985 lines
194 KiB
C

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <Eina.h>
#include <Ecore.h>
#include "ecore_private.h"
#include <Ecore_Input.h>
#include <Ecore_Input_Evas.h>
#include <Ecore_X.h>
#include <Ecore_X_Atoms.h>
#include <Efreet.h>
#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
# include <Evas_Engine_Software_X11.h>
#endif
#ifdef BUILD_ECORE_EVAS_OPENGL_X11
# include <Evas_Engine_GL_X11.h>
#endif
#include <Ecore_Evas.h>
#include "ecore_evas_private.h"
#include "ecore_evas_x11.h"
#ifdef EAPI
# undef EAPI
#endif
#ifdef _WIN32
# ifdef DLL_EXPORT
# define EAPI __declspec(dllexport)
# else
# define EAPI
# endif /* ! DLL_EXPORT */
#else
# ifdef __GNUC__
# if __GNUC__ >= 4
# define EAPI __attribute__ ((visibility("default")))
# else
# define EAPI
# endif
# else
# define EAPI
# endif
#endif /* ! _WIN32 */
#define ECORE_EVAS_X11_SELECTION 0x7F
#define EDBG(...) \
EINA_LOG(_ecore_evas_log_dom, EINA_LOG_LEVEL_DBG + 1, __VA_ARGS__);
static int _ecore_evas_init_count = 0;
static Ecore_Event_Handler *ecore_evas_event_handlers[14];
static int leader_ref = 0;
static Ecore_X_Window leader_win = 0;
static const char *interface_x11_name = "x11";
static const int interface_x11_version = 1;
static const char *interface_software_x11_name = "software_x11";
static const int interface_software_x11_version = 1;
#ifdef BUILD_ECORE_EVAS_OPENGL_X11
static const char *interface_gl_x11_name = "gl_x11";
#endif
static const int interface_gl_x11_version = 1;
static Eina_Bool wm_exists;
typedef struct _Ecore_Evas_Engine_Data_X11 Ecore_Evas_Engine_Data_X11;
typedef struct {
EINA_MAGIC;
Ecore_Evas_Selection_Callbacks callbacks;
Ecore_Evas_Selection_Buffer buffer;
Ecore_Evas *ee;
Eina_Promise *delivery;
Eina_Array *acceptable_type;
Eina_Stringshare *requested_type;
Eina_Stringshare *later_conversion;
} Ecore_Evas_X11_Selection_Data;
struct _Ecore_Evas_Engine_Data_X11 {
Ecore_X_Window win_root;
Eina_List *win_extra;
Ecore_X_Pixmap pmap;
Ecore_X_Pixmap mask;
Ecore_X_GC gc;
Ecore_X_XRegion *damages;
Ecore_Timer *outdelay;
Ecore_X_Event_Mouse_Out out_ev;
Ecore_X_Window leader;
Ecore_X_Sync_Counter netwm_sync_counter;
int configure_reqs;
int netwm_sync_val_hi;
unsigned int netwm_sync_val_lo;
int screen_num;
int px, py, pw, ph;
unsigned char direct_resize : 1;
unsigned char using_bg_pixmap : 1;
unsigned char managed : 1;
unsigned char netwm_sync_set : 1;
unsigned char configure_coming : 1;
struct {
unsigned char modal : 1;
unsigned char sticky : 1;
unsigned char maximized_v : 1;
unsigned char maximized_h : 1;
unsigned char shaded : 1;
unsigned char skip_taskbar : 1;
unsigned char skip_pager : 1;
unsigned char fullscreen : 1;
unsigned char above : 1;
unsigned char below : 1;
} state;
struct {
unsigned char available : 1; // need to setup available profiles in a w
unsigned char change : 1; // need to send change event to the WM
unsigned char done : 1; // need to send change done event to the WM
} profile;
struct {
unsigned char supported: 1;
unsigned char prepare : 1;
unsigned char request : 1;
unsigned char done : 1;
unsigned char configure_coming : 1;
Ecore_Job *manual_mode_job;
} wm_rot;
Ecore_X_Window win_shaped_input;
struct
{
unsigned int front, back; // front and back pixmaps (double-buffer)
Evas_Coord w, h; // store pixmap size (saves X roundtrips)
int depth; // store depth to save us from fetching engine info pre_render
void *visual; // store visual used to create pixmap
unsigned long colormap; // store colormap used to create pixmap
} pixmap;
Ecore_Evas_X11_Selection_Data selection_data[ECORE_EVAS_SELECTION_BUFFER_LAST];
Eina_Array *xserver_atom_name_during_dnd;
Ecore_Event_Handler *mouse_up_handler;
Ecore_Job *init_job;
int skip_clean_event;
Eina_Bool destroyed : 1; // X window has been deleted and cannot be used
Eina_Bool fully_obscured : 1; // X window is fully obscured
Eina_Bool configured : 1; // X window has been configured
};
static Ecore_Evas_Interface_X11 * _ecore_evas_x_interface_x11_new(void);
#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
static Ecore_Evas_Interface_Software_X11 *_ecore_evas_x_interface_software_x11_new(void);
#endif
#ifdef BUILD_ECORE_EVAS_OPENGL_X11
static Ecore_Evas_Interface_Gl_X11 *_ecore_evas_x_interface_gl_x11_new(void);
#endif
static void _ecore_evas_x_rotation_set(Ecore_Evas *ee, int rotation, int resize);
static Eina_Bool _ecore_evas_x_wm_rot_manual_rotation_done_timeout(void *data);
static void _ecore_evas_x_wm_rot_manual_rotation_done_timeout_update(Ecore_Evas *ee);
static void _ecore_evas_x_aux_hints_set(Ecore_Evas *ee, const char *hints);
static void _resize_shape_do(Ecore_Evas *);
static void _shaped_do(Ecore_Evas *, int);
static void _alpha_do(Ecore_Evas *, int);
static void _transparent_do(Ecore_Evas *, int);
static void _avoid_damage_do(Ecore_Evas *, int);
static void _rotation_do(Ecore_Evas *, int, int);
static void _ecore_evas_x_selection_init(void);
static void _ecore_evas_x_selection_window_init(Ecore_Evas *ee);
#define SWAP_INT(a, b) do { a ^= b; b ^= a; a ^= b; } while (0)
static void
_ecore_evas_x_hints_update(Ecore_Evas *ee)
{
Ecore_X_Window_State_Hint initial_state = ECORE_X_WINDOW_STATE_HINT_NORMAL;
if (ee->prop.iconified)
initial_state = ECORE_X_WINDOW_STATE_HINT_ICONIC;
ecore_x_icccm_hints_set
(ee->prop.window,
!ee->prop.focus_skip /* accepts_focus */,
initial_state /* initial_state */,
0 /* icon_pixmap */,
0 /* icon_mask */,
0 /* icon_window */,
ee->prop.group_ee_win /* window_group */,
ee->prop.urgent /* is_urgent */);
}
static void
_ecore_evas_x_group_leader_set(Ecore_Evas *ee)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
leader_ref++;
if (leader_ref == 1)
{
char *id = NULL;
leader_win =
ecore_x_window_override_new(edata->win_root, 1234, 5678, 1, 2);
ecore_x_window_defaults_set(leader_win);
if ((id = getenv("DESKTOP_STARTUP_ID")))
ecore_x_netwm_startup_id_set(leader_win,id);
ecore_x_icccm_client_leader_set(leader_win, leader_win);
}
edata->leader = leader_win;
ecore_x_icccm_client_leader_set(ee->prop.window, leader_win);
}
static void
_ecore_evas_x_group_leader_unset(Ecore_Evas *ee)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
if (!edata->destroyed)
ecore_x_window_prop_property_del(ee->prop.window,
ECORE_X_ATOM_WM_CLIENT_LEADER);
if (edata->leader == leader_win)
{
leader_ref--;
if (leader_ref <= 0)
{
ecore_x_window_free(leader_win);
leader_win = 0;
}
edata->leader = 0;
}
}
static void
_ecore_evas_x_group_leader_update(Ecore_Evas *ee)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
if (edata->leader)
ecore_x_icccm_client_leader_set(ee->prop.window, edata->leader);
}
static void
_ecore_evas_x_protocols_set(Ecore_Evas *ee)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
Ecore_X_Atom protos[3];
unsigned int num = 0, tmp = 0;
if (ee->deleted) return;
if (ee->func.fn_delete_request)
protos[num++] = ECORE_X_ATOM_WM_DELETE_WINDOW;
protos[num++] = ECORE_X_ATOM_NET_WM_PING;
protos[num++] = ECORE_X_ATOM_NET_WM_SYNC_REQUEST;
ecore_x_icccm_protocol_atoms_set(ee->prop.window, protos, num);
if (!edata->netwm_sync_counter)
edata->netwm_sync_counter = ecore_x_sync_counter_new(0);
tmp = edata->netwm_sync_counter;
ecore_x_window_prop_card32_set(ee->prop.window,
ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER,
&tmp, 1);
// set property on window to say "I talk the deiconify approve protcol"
tmp = 1;
ecore_x_window_prop_card32_set(ee->prop.window,
ECORE_X_ATOM_E_DEICONIFY_APPROVE,
&tmp, 1);
}
static void
_ecore_evas_x_wm_rotation_protocol_set(Ecore_Evas *ee)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
if (ecore_x_e_window_rotation_supported_get(edata->win_root))
ee->prop.wm_rot.supported = 1;
else
ee->prop.wm_rot.supported = 0;
}
static void
_ecore_evas_x_window_profile_protocol_set(Ecore_Evas *ee)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
/* check and set profile protocol hint */
if (ecore_x_e_window_profile_supported_get(edata->win_root))
{
unsigned int v = 1;
ecore_x_window_prop_card32_set
(ee->prop.window,
ECORE_X_ATOM_E_WINDOW_PROFILE_SUPPORTED,
&v, 1);
ee->profile_supported = 1;
}
else
ee->profile_supported = 0;
}
static void
_ecore_evas_x_window_profile_set(Ecore_Evas *ee)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
if (((ee->should_be_visible) || (ee->visible)) &&
(ee->profile_supported))
{
if (edata->profile.available)
{
ecore_x_e_window_available_profiles_set
(ee->prop.window,
(const char **)ee->prop.profile.available_list,
(const int)ee->prop.profile.count);
edata->profile.available = 0;
}
if (edata->profile.change)
{
if (ee->prop.profile.name)
{
/* We need to keep the profile as an x property to let the WM.
* Then the WM reads it when creating the border window.
*/
Ecore_X_Atom a = ecore_x_atom_get(ee->prop.profile.name);
ecore_x_window_prop_atom_set
(ee->prop.window,
ECORE_X_ATOM_E_WINDOW_PROFILE_CHANGE,
&a, 1);
ecore_x_e_window_profile_change_send
(edata->win_root,
ee->prop.window,
ee->prop.profile.name);
}
edata->profile.change = 0;
}
}
}
static void
_ecore_evas_x_wm_rot_manual_rotation_done_job(void *data)
{
Ecore_Evas *ee = (Ecore_Evas *)data;
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
edata->wm_rot.manual_mode_job = NULL;
ee->prop.wm_rot.manual_mode.wait_for_done = EINA_FALSE;
ecore_x_e_window_rotation_change_done_send
(edata->win_root, ee->prop.window, ee->rotation, ee->w, ee->h);
edata->wm_rot.done = 0;
}
static void
_ecore_evas_x_aux_hints_supported_update(Ecore_Evas *ee)
{
Ecore_X_Window root = ecore_x_window_root_first_get();
unsigned char *data = NULL;
unsigned int num = 0, i = 0;
int res = 0, n = 0;
char **str;
const char *hint;
EINA_LIST_FREE(ee->prop.aux_hint.supported_list, hint)
{
eina_stringshare_del(hint);
}
res = ecore_x_window_prop_property_get
(root, ECORE_X_ATOM_E_WINDOW_AUX_HINT_SUPPORTED_LIST,
ECORE_X_ATOM_STRING, 0, &data, &n);
if ((res == 8) && (n > 0))
{
str = eina_str_split_full((char *)data, ",", -1, &num);
for (i = 0; i < num; i++)
{
hint = eina_stringshare_add(str[i]);
ee->prop.aux_hint.supported_list =
eina_list_append(ee->prop.aux_hint.supported_list, hint);
}
if (str)
{
free(str[0]);
free(str);
}
}
free(data);
}
static void
_ecore_evas_x_aux_hints_update(Ecore_Evas *ee)
{
Eina_Strbuf *buf = _ecore_evas_aux_hints_string_get(ee);
if (buf)
{
_ecore_evas_x_aux_hints_set(ee, eina_strbuf_string_get(buf));
eina_strbuf_free(buf);
}
}
# ifdef BUILD_ECORE_EVAS_OPENGL_X11
static Ecore_X_Window
_ecore_evas_x_gl_window_new(Ecore_Evas *ee, Ecore_X_Window parent, int x, int y, int w, int h, Eina_Bool override, int argb, const int *opt)
{
Evas_Engine_Info_GL_X11 *einfo;
Ecore_X_Window win;
einfo = (Evas_Engine_Info_GL_X11 *)evas_engine_info_get(ee->evas);
if (einfo)
{
int screen;
if (opt)
{
int op;
for (op = 0; opt[op]; op++)
{
if (opt[op] == ECORE_EVAS_GL_X11_OPT_INDIRECT)
{
op++;
einfo->indirect = opt[op];
}
else if (opt[op] == ECORE_EVAS_GL_X11_OPT_VSYNC)
{
op++;
einfo->vsync = opt[op];
}
#ifdef EVAS_ENGINE_GL_X11_SWAP_MODE_EXISTS
else if (opt[op] == ECORE_EVAS_GL_X11_OPT_SWAP_MODE)
{
op++;
if ((evas_version->major >= 1) &&
(evas_version->minor >= 7) &&
(evas_version->micro >= 99))
einfo->swap_mode = opt[op];
}
#endif
else if (opt[op] == ECORE_EVAS_GL_X11_OPT_GL_DEPTH)
{
op++;
einfo->depth_bits = opt[op];
}
else if (opt[op] == ECORE_EVAS_GL_X11_OPT_GL_STENCIL)
{
op++;
einfo->stencil_bits = opt[op];
}
else if (opt[op] == ECORE_EVAS_GL_X11_OPT_GL_MSAA)
{
op++;
einfo->msaa_bits = opt[op];
}
}
}
/* FIXME: this is inefficient as its 1 or more round trips */
screen = ecore_x_screen_index_get(ecore_x_default_screen_get());
if (ecore_x_screen_count_get() > 1)
{
Ecore_X_Window *roots;
int num, i;
num = 0;
roots = ecore_x_window_root_list(&num);
if (roots)
{
Ecore_X_Window root;
root = ecore_x_window_root_get(parent);
for (i = 0; i < num; i++)
{
if (root == roots[i])
{
screen = i;
break;
}
}
free(roots);
}
}
einfo->info.display = ecore_x_display_get();
einfo->info.screen = screen;
einfo->info.destination_alpha = argb;
einfo->info.visual = einfo->func.best_visual_get(einfo);
einfo->info.colormap = einfo->func.best_colormap_get(einfo);
einfo->info.depth = einfo->func.best_depth_get(einfo);
if ((!einfo->info.visual) ||
(!einfo->info.colormap) || (!einfo->info.depth))
{
WRN("OpenGL X11 init engine '%s' failed - no visual, colormap or depth.", ee->driver);
if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
{
ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
return 0;
}
}
win = ecore_x_window_full_new(parent, x, y, w, h,
einfo->info.visual,
einfo->info.colormap,
einfo->info.depth,
override);
ecore_x_window_pixel_gravity_set(win, ECORE_X_GRAVITY_FORGET);
ecore_x_vsync_animator_tick_source_set(win);
/* attr.backing_store = NotUseful; */
/* attr.override_redirect = override; */
/* attr.colormap = einfo->info.colormap; */
/* attr.border_pixel = 0; */
/* attr.background_pixmap = None; */
/* attr.event_mask = */
/* KeyPressMask | KeyReleaseMask | */
/* ExposureMask | ButtonPressMask | ButtonReleaseMask | */
/* EnterWindowMask | LeaveWindowMask | */
/* PointerMotionMask | StructureNotifyMask | VisibilityChangeMask | */
/* FocusChangeMask | PropertyChangeMask | ColormapChangeMask; */
/* attr.bit_gravity = ForgetGravity; */
/* win = */
/* XCreateWindow(einfo->info.display, parent, x, y, w, h, 0, */
/* einfo->info.depth, InputOutput, einfo->info.visual, */
/* CWBackingStore | CWColormap | CWBackPixmap | */
/* CWBorderPixel | CWBitGravity | CWEventMask | */
/* CWOverrideRedirect, &attr); */
einfo->info.drawable = win;
if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
{
WRN("evas_engine_info_set() for engine '%s' failed.", ee->driver);
ecore_x_window_free(win);
return 0;
}
}
else
win = 0;
return win;
}
#endif
static int
_render_updates_process(Ecore_Evas *ee, Eina_List *updates)
{
int rend = 0;
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
if (ee->prop.avoid_damage)
{
if (edata->using_bg_pixmap)
{
if (updates)
{
Eina_List *l = NULL;
Eina_Rectangle *r;
EINA_LIST_FOREACH(updates, l, r)
ecore_x_window_area_clear(ee->prop.window,
r->x, r->y, r->w, r->h);
if (ee->shaped)
{
ecore_x_window_shape_mask_set(ee->prop.window,
edata->mask);
}
if (ee->alpha)
{
// ecore_x_window_shape_input_mask_set(ee->prop.window, edata->mask);
}
_ecore_evas_idle_timeout_update(ee);
rend = 1;
}
}
else
{
if (updates)
{
Eina_List *l = NULL;
Eina_Rectangle *r;
EINA_LIST_FOREACH(updates, l, r)
{
Ecore_X_Rectangle rect;
Ecore_X_XRegion *tmpr;
if (!edata->damages)
edata->damages = ecore_x_xregion_new();
tmpr = ecore_x_xregion_new();
if (ee->rotation == 0)
{
rect.x = r->x;
rect.y = r->y;
rect.width = r->w;
rect.height = r->h;
}
else if (ee->rotation == 90)
{
rect.x = r->y;
rect.y = ee->h - r->x - r->w;
rect.width = r->h;
rect.height = r->w;
}
else if (ee->rotation == 180)
{
rect.x = ee->w - r->x - r->w;
rect.y = ee->h - r->y - r->h;
rect.width = r->w;
rect.height = r->h;
}
else if (ee->rotation == 270)
{
rect.x = ee->w - r->y - r->h;
rect.y = r->x;
rect.width = r->h;
rect.height = r->w;
}
ecore_x_xregion_union_rect(tmpr, edata->damages,
&rect);
ecore_x_xregion_free(edata->damages);
edata->damages = tmpr;
}
if (edata->damages)
{
if (ee->shaped)
{
/* if we have a damage pixmap - we can avoid exposures by
* disabling them just for setting the mask */
ecore_x_event_mask_unset(ee->prop.window, ECORE_X_EVENT_MASK_WINDOW_DAMAGE);
ecore_x_window_shape_mask_set(ee->prop.window,
edata->mask);
/* and re-enable them again */
ecore_x_event_mask_set(ee->prop.window, ECORE_X_EVENT_MASK_WINDOW_DAMAGE);
}
ecore_x_xregion_set(edata->damages, edata->gc);
ecore_x_pixmap_paste(edata->pmap, ee->prop.window,
edata->gc, 0, 0, ee->w, ee->h,
0, 0);
ecore_x_xregion_free(edata->damages);
edata->damages = NULL;
}
_ecore_evas_idle_timeout_update(ee);
rend = 1;
}
}
}
else if (((ee->visible) && (!ee->draw_block)) ||
((ee->should_be_visible) && (ee->prop.fullscreen)) ||
((ee->should_be_visible) && (ee->prop.override)))
{
if (updates)
{
if (ee->shaped)
{
ecore_x_window_shape_mask_set(ee->prop.window,
edata->mask);
}
if (ee->alpha)
{
// ecore_x_window_shape_input_mask_set(ee->prop.window, edata->mask);
}
_ecore_evas_idle_timeout_update(ee);
rend = 1;
}
}
else
evas_norender(ee->evas);
if (ee->func.fn_post_render) ee->func.fn_post_render(ee);
/*
if (rend)
{
static int frames = 0;
static double t0 = 0.0;
double t, td;
t = ecore_time_get();
frames++;
if ((t - t0) > 1.0)
{
td = t - t0;
printf("FPS: %3.3f\n", (double)frames / td);
frames = 0;
t0 = t;
}
}
*/
return rend;
}
static void
_ecore_evas_x_render_updates(void *data, Evas *e EINA_UNUSED, void *event_info)
{
Evas_Event_Render_Post *ev = event_info;
Ecore_Evas *ee = data;
if (!ev) return;
EDBG("ee=%p finished asynchronous render.", ee);
ee->in_async_render = EINA_FALSE;
_render_updates_process(ee, ev->updated_area);
if (ee->delayed.resize_shape)
{
_resize_shape_do(ee);
ee->delayed.resize_shape = EINA_FALSE;
}
if (ee->delayed.shaped_changed)
{
_shaped_do(ee, ee->delayed.shaped);
ee->delayed.shaped_changed = EINA_FALSE;
}
if (ee->delayed.alpha_changed)
{
_alpha_do(ee, ee->delayed.alpha);
ee->delayed.alpha_changed = EINA_FALSE;
}
if (ee->delayed.transparent_changed)
{
_transparent_do(ee, ee->delayed.transparent);
ee->delayed.transparent_changed = EINA_FALSE;
}
if (ee->delayed.avoid_damage != ee->prop.avoid_damage)
_avoid_damage_do(ee, ee->delayed.avoid_damage);
if (ee->delayed.rotation_changed)
{
_rotation_do(ee, ee->delayed.rotation, ee->delayed.rotation_resize);
ee->delayed.rotation_changed = EINA_FALSE;
}
}
static int
_ecore_evas_x_render(Ecore_Evas *ee)
{
int rend = 0;
if (ee->in_async_render)
{
EDBG("ee=%p is rendering asynchronously, skip.", ee);
return 0;
}
rend = ecore_evas_render_prepare(ee);
if (!ee->can_async_render)
{
Eina_List *updates = evas_render_updates(ee->evas);
rend = _render_updates_process(ee, updates);
evas_render_updates_free(updates);
}
else if (evas_render_async(ee->evas))
{
EDBG("ee=%p started asynchronous render.", ee);
ee->in_async_render = EINA_TRUE;
rend = 1;
}
else if (ee->func.fn_post_render) ee->func.fn_post_render(ee);
return rend;
}
static void
_resize_shape_do(Ecore_Evas *ee)
{
#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
Evas_Engine_Info_Software_X11 *einfo;
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas);
if (einfo)
{
unsigned int foreground;
int fw = 0, fh = 0;
Ecore_X_GC gc;
evas_output_framespace_get(ee->evas, NULL, NULL, &fw, &fh);
if (edata->mask)
{
ecore_x_pixmap_free(edata->mask);
edata->mask = 0;
}
if (!ee->shaped) return;
edata->mask = ecore_x_pixmap_new(ee->prop.window, ee->w + fw, ee->h + fh, 1);
foreground = 0;
gc = ecore_x_gc_new(edata->mask,
ECORE_X_GC_VALUE_MASK_FOREGROUND,
&foreground);
ecore_x_drawable_rectangle_fill(edata->mask, gc,
0, 0, ee->w + fw, ee->h + fh);
ecore_x_gc_free(gc);
einfo->info.mask = edata->mask;
if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
{
ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
}
evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
}
#endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 */
}
static void
_ecore_evas_x_resize_shape(Ecore_Evas *ee)
{
if (!strcmp(ee->driver, "software_x11"))
{
if (ee->in_async_render)
{
ee->delayed.resize_shape = EINA_TRUE;
return;
}
_resize_shape_do(ee);
}
}
/* TODO: we need to make this work for all the states, not just sticky */
static Eina_Bool
_ecore_evas_x_event_property_change(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_Evas *ee;
Ecore_X_Event_Window_Property *e;
Ecore_Evas_Engine_Data_X11 *edata;
int state_change = 0;
e = event;
if (e->win == ecore_x_window_root_first_get())
{
if (e->atom == ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK)
wm_exists = !ecore_x_window_prop_window_get(ecore_x_window_root_first_get(), ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK, NULL, 0);
}
ee = ecore_event_window_match(e->win);
if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; /* pass on event */
edata = ee->engine.data;
if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
if (e->atom == ECORE_X_ATOM_NET_WM_STATE)
{
unsigned int i, num;
Ecore_X_Window_State *state;
struct {
struct {
unsigned char modal : 1;
unsigned char sticky : 1;
unsigned char maximized_v : 1;
unsigned char maximized_h : 1;
unsigned char shaded : 1;
unsigned char skip_taskbar : 1;
unsigned char skip_pager : 1;
unsigned char fullscreen : 1;
unsigned char above : 1;
unsigned char below : 1;
} x;
struct {
Eina_Bool modal : 1;
Eina_Bool maximized : 1;
Eina_Bool sticky : 1;
Eina_Bool fullscreen : 1;
Eina_Bool focus_skip : 1;
} prop;
} prev;
prev.x.modal = edata->state.modal;
prev.x.sticky = edata->state.sticky;
prev.x.maximized_v = edata->state.maximized_v;
prev.x.maximized_h = edata->state.maximized_h;
prev.x.shaded = edata->state.shaded;
prev.x.skip_taskbar = edata->state.skip_taskbar;
prev.x.skip_pager = edata->state.skip_pager;
prev.x.fullscreen = edata->state.fullscreen;
prev.x.above = edata->state.above;
prev.x.below = edata->state.below;
prev.prop.modal = ee->prop.modal;
prev.prop.maximized = ee->prop.maximized;
prev.prop.sticky = ee->prop.sticky;
prev.prop.fullscreen = ee->prop.fullscreen;
prev.prop.focus_skip = ee->prop.focus_skip;
edata->state.modal = 0;
edata->state.sticky = 0;
edata->state.maximized_v = 0;
edata->state.maximized_h = 0;
edata->state.shaded = 0;
edata->state.skip_taskbar = 0;
edata->state.skip_pager = 0;
edata->state.fullscreen = 0;
edata->state.above = 0;
edata->state.below = 0;
ee->prop.modal = EINA_FALSE;
ee->prop.maximized = EINA_FALSE;
ee->prop.sticky = EINA_FALSE;
ee->prop.fullscreen = EINA_FALSE;
// ee->prop.focus_skip = EINA_FALSE;
ecore_x_netwm_window_state_get(e->win, &state, &num);
if (state)
{
for (i = 0; i < num; i++)
{
switch (state[i])
{
case ECORE_X_WINDOW_STATE_MODAL:
edata->state.modal = 1;
ee->prop.modal = EINA_TRUE;
break;
case ECORE_X_WINDOW_STATE_STICKY:
ee->prop.sticky = EINA_TRUE;
edata->state.sticky = 1;
break;
case ECORE_X_WINDOW_STATE_MAXIMIZED_VERT:
edata->state.maximized_v = 1;
ee->prop.maximized = EINA_TRUE;
break;
case ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ:
edata->state.maximized_h = 1;
ee->prop.maximized = EINA_TRUE;
break;
case ECORE_X_WINDOW_STATE_SHADED:
edata->state.shaded = 1;
break;
case ECORE_X_WINDOW_STATE_SKIP_TASKBAR:
edata->state.skip_taskbar = 1;
break;
case ECORE_X_WINDOW_STATE_SKIP_PAGER:
edata->state.skip_pager = 1;
break;
case ECORE_X_WINDOW_STATE_FULLSCREEN:
ee->prop.fullscreen = 1;
edata->state.fullscreen = 1;
break;
case ECORE_X_WINDOW_STATE_ABOVE:
edata->state.above = 1;
break;
case ECORE_X_WINDOW_STATE_BELOW:
edata->state.below = 1;
break;
default:
break;
}
}
free(state);
}
if (
// (prev.x.modal != edata->state.modal) ||
(prev.x.sticky != edata->state.sticky) ||
(prev.x.maximized_v != edata->state.maximized_v) ||
(prev.x.maximized_h != edata->state.maximized_h) ||
// (prev.x.shaded != edata->state.shaded) ||
(prev.x.skip_taskbar != edata->state.skip_taskbar) ||
(prev.x.skip_pager != edata->state.skip_pager) ||
(prev.x.fullscreen != edata->state.fullscreen) ||
// (prev.x.above != edata->state.above) ||
// (prev.x.below != edata->state.below) ||
// (prev.prop.modal != ee->prop.modal) ||
(prev.prop.maximized != ee->prop.maximized) ||
(prev.prop.sticky != ee->prop.sticky) ||
(prev.prop.fullscreen != ee->prop.fullscreen) ||
(prev.prop.focus_skip != ee->prop.focus_skip))
state_change = 1;
}
else if (e->atom == ECORE_X_ATOM_WM_STATE)
{
Ecore_X_Window_State_Hint state;
// handle WM_STATE changes
state = ecore_x_icccm_state_get(e->win);
switch (state)
{
case ECORE_X_WINDOW_STATE_HINT_WITHDRAWN:
if ((!ee->prop.withdrawn) || (ee->prop.iconified))
{
state_change = 1;
ee->prop.withdrawn = EINA_TRUE;
ee->prop.iconified = EINA_FALSE;
}
break;
case ECORE_X_WINDOW_STATE_HINT_ICONIC:
if ((!ee->prop.iconified) || (ee->prop.withdrawn))
{
state_change = 1;
ee->prop.iconified = EINA_TRUE;
ee->prop.withdrawn = EINA_FALSE;
}
break;
case ECORE_X_WINDOW_STATE_HINT_NORMAL:
if ((ee->prop.iconified) || (ee->prop.withdrawn))
{
state_change = 1;
ee->prop.iconified = EINA_FALSE;
ee->prop.withdrawn = EINA_FALSE;
}
break;
default:
break;
}
}
if (state_change)
{
if (ee->func.fn_state_change) ee->func.fn_state_change(ee);
}
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_ecore_evas_x_event_visibility_change(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_Evas *ee;
Ecore_X_Event_Window_Visibility_Change *e;
Ecore_Evas_Engine_Data_X11 *edata;
e = event;
ee = ecore_event_window_match(e->win);
if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
edata = ee->engine.data;
if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
// printf("VIS CHANGE OBSCURED: %p %i\n", ee, e->fully_obscured);
edata->fully_obscured = e->fully_obscured;
if (e->fully_obscured)
{
/* FIXME: round trip */
if ((!wm_exists) || (!ecore_x_screen_is_composited(edata->screen_num)))
ee->draw_block = !edata->configured;
}
else if (ee->draw_block)
{
if (!edata->configure_coming)
edata->configured = 1;
ee->draw_block = !edata->configured;
}
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_ecore_evas_x_event_window_create(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_X_Event_Window_Create *e = event;
Ecore_Evas *ee;
Ecore_Evas_Engine_Data_X11 *edata;
ee = ecore_event_window_match(e->win);
if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
edata = ee->engine.data;
if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
if (!ee->draw_block) return ECORE_CALLBACK_RENEW;
if ((ee->req.w == e->w) && (ee->req.h == e->h))
{
/* window created with desired size: canvas can be drawn */
ee->draw_block = EINA_FALSE;
edata->configured = EINA_TRUE;
}
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_ecore_evas_x_event_client_message(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_Evas *ee;
Ecore_X_Event_Client_Message *e;
Ecore_Evas_Engine_Data_X11 *edata;
e = event;
if (e->format != 32) return ECORE_CALLBACK_PASS_ON;
if ((e->message_type == ECORE_X_ATOM_WM_PROTOCOLS) &&
(e->data.l[0] == (int)ECORE_X_ATOM_NET_WM_SYNC_REQUEST))
{
ee = ecore_event_window_match(e->win);
if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
edata = ee->engine.data;
edata->netwm_sync_val_lo = (unsigned int)e->data.l[2];
edata->netwm_sync_val_hi = (int)e->data.l[3];
edata->netwm_sync_set = 1;
}
else if (e->message_type == ECORE_X_ATOM_E_WINDOW_PROFILE_CHANGE_REQUEST)
{
ee = ecore_event_window_match(e->win);
if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
edata = ee->engine.data;
if (ee->profile_supported)
{
char *p = ecore_x_atom_name_get(e->data.l[1]);
if (p)
{
_ecore_evas_window_profile_free(ee);
ee->prop.profile.name = (char *)eina_stringshare_add(p);
/* window profiles of each sub_ecore_evas will be changed
* in fn_state_change callback.
*/
if (ee->func.fn_state_change)
ee->func.fn_state_change(ee);
edata->profile.done = 1;
free(p);
}
}
}
else if (e->message_type == ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL)
{
///TODO after access structure determined
// if (ee->func.fn_msg_handle)
// ee->func.fn_msg_handle(ee, msg_domain, msg_id, data, size);
}
else if (e->message_type == ECORE_X_ATOM_E_DEICONIFY_APPROVE)
{
ee = ecore_event_window_match(e->win);
if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
if (e->data.l[1] != 0) //wm sends request message using value 0
return ECORE_CALLBACK_PASS_ON;
if (ecore_evas_manual_render_get(ee))
ecore_evas_manual_render(ee);
//client sends reply message using value 1
ecore_x_client_message32_send(e->win, ECORE_X_ATOM_E_DEICONIFY_APPROVE,
ECORE_X_EVENT_MASK_WINDOW_CONFIGURE,
e->win, 1,
0, 0, 0);
}
else if (e->message_type == ECORE_X_ATOM_E_WINDOW_ROTATION_CHANGE_PREPARE)
{
ee = ecore_event_window_match(e->data.l[0]);
if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
edata = ee->engine.data;
if (e->data.l[0] != (long)ee->prop.window)
return ECORE_CALLBACK_PASS_ON;
if (ee->prop.wm_rot.supported)
{
if (ee->prop.wm_rot.app_set)
{
ee->prop.wm_rot.angle = (int)e->data.l[1];
ee->prop.wm_rot.win_resize = (int)e->data.l[2];
ee->prop.wm_rot.w = (int)e->data.l[3];
ee->prop.wm_rot.h = (int)e->data.l[4];
if ((ee->prop.wm_rot.win_resize) &&
((ee->w != ee->prop.wm_rot.w) ||
(ee->h != ee->prop.wm_rot.h)))
edata->wm_rot.configure_coming = 1;
edata->wm_rot.prepare = 1;
edata->wm_rot.request = 0;
edata->wm_rot.done = 0;
}
}
}
else if (e->message_type == ECORE_X_ATOM_E_WINDOW_ROTATION_CHANGE_REQUEST)
{
ee = ecore_event_window_match(e->data.l[0]);
if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
edata = ee->engine.data;
if (e->data.l[0] != (long)ee->prop.window)
return ECORE_CALLBACK_PASS_ON;
if (ee->prop.wm_rot.supported)
{
if (ee->prop.wm_rot.app_set)
{
int angle = ee->prop.wm_rot.angle;
Eina_Bool resize = ee->prop.wm_rot.win_resize;
edata->wm_rot.prepare = 0;
edata->wm_rot.request = 1;
edata->wm_rot.done = 0;
if (resize)
{
if ((ee->w == ee->prop.wm_rot.w) &&
(ee->h == ee->prop.wm_rot.h))
{
edata->wm_rot.configure_coming = 0;
}
}
if (!edata->wm_rot.configure_coming)
{
if (ee->prop.wm_rot.manual_mode.set)
{
ee->prop.wm_rot.manual_mode.wait_for_done = EINA_TRUE;
_ecore_evas_x_wm_rot_manual_rotation_done_timeout_update(ee);
}
_ecore_evas_x_rotation_set(ee, angle, (!resize));
}
}
}
}
else if (e->message_type == ECORE_X_ATOM_E_WINDOW_AUX_HINT_ALLOWED)
{
ee = ecore_event_window_match(e->win);
if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
int id = e->data.l[1]; /* id of aux hint */
Eina_List *l;
Ecore_Evas_Aux_Hint *aux;
EINA_LIST_FOREACH(ee->prop.aux_hint.hints, l, aux)
{
if (id == aux->id)
{
aux->allowed = 1;
if (!aux->notified)
{
if (ee->func.fn_state_change) ee->func.fn_state_change(ee);
aux->notified = 1;
}
break;
}
}
}
return ECORE_CALLBACK_PASS_ON;
}
static inline void
_feed_cancel_out(const Ecore_X_Event_Mouse_Out *e, Eina_Bool cancel)
{
/* equivalent to:
* if (cancel) evas_event_feed_mouse_cancel(ee->evas, e->time, NULL);
* evas_event_feed_mouse_out(ee->evas, e->time, NULL);
* but this goes through ecore_event_evas and direct eo event callback
*/
if (cancel)
{
Ecore_Event_Mouse_Button ev = {
.event_window = (Ecore_Window) e->win, /* not event_win */
.modifiers = e->modifiers,
.timestamp = e->time,
.window = (Ecore_Window) e->win,
.x = e->x,
.y = e->y,
};
ecore_event_evas_mouse_button_cancel(NULL, ECORE_EVENT_MOUSE_BUTTON_CANCEL, &ev);
}
Ecore_Event_Mouse_IO io = {
.event_window = (Ecore_Window) e->win, /* not event_win */
.modifiers = e->modifiers,
.timestamp = e->time,
.window = (Ecore_Window) e->win,
.x = e->x,
.y = e->y
};
ecore_event_evas_mouse_out(NULL, ECORE_EVENT_MOUSE_OUT, &io);
}
static Eina_Bool
_fake_out(void *data)
{
Ecore_Evas *ee = data;
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
Ecore_X_Event_Mouse_Out *e = &(edata->out_ev);
edata->outdelay = NULL;
ecore_event_evas_modifier_lock_update(ee->evas, e->modifiers);
_ecore_evas_mouse_move_process(ee, e->x, e->y, e->time);
_feed_cancel_out(e, (e->mode == ECORE_X_EVENT_MODE_GRAB));
_ecore_evas_mouse_inout_set(ee, NULL, EINA_FALSE, EINA_TRUE);
_ecore_evas_default_cursor_hide(ee);
return EINA_FALSE;
}
static Eina_Bool
_ecore_evas_x_event_mouse_in(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_Evas *ee;
Ecore_X_Event_Mouse_In *e;
Ecore_Evas_Engine_Data_X11 *edata;
e = event;
ee = ecore_event_window_match(e->win);
if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; /* pass on event */
if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
edata = ee->engine.data;
/*
{
time_t t;
char *ct;
const char *modes[] = {
"MODE_NORMAL",
"MODE_WHILE_GRABBED",
"MODE_GRAB",
"MODE_UNGRAB"
};
const char *details[] = {
"DETAIL_ANCESTOR",
"DETAIL_VIRTUAL",
"DETAIL_INFERIOR",
"DETAIL_NON_LINEAR",
"DETAIL_NON_LINEAR_VIRTUAL",
"DETAIL_POINTER",
"DETAIL_POINTER_ROOT",
"DETAIL_DETAIL_NONE"
};
t = time(NULL);
ct = ctime(&t);
ct[strlen(ct) - 1] = 0;
printf("@@ ->IN 0x%x 0x%x %s md=%s dt=%s\n",
e->win, e->event_win,
ct,
modes[e->mode],
details[e->detail]);
}
*/
// disable. causes more problems than it fixes
// if ((e->mode == ECORE_X_EVENT_MODE_GRAB) ||
// (e->mode == ECORE_X_EVENT_MODE_UNGRAB))
// return 0;
// handle click to focus passive buton grab side-effects
if ((e->mode == ECORE_X_EVENT_MODE_UNGRAB) &&
(e->detail == ECORE_X_EVENT_DETAIL_ANCESTOR) &&
(edata->outdelay))
{
ecore_timer_del(edata->outdelay);
edata->outdelay = NULL;
return 0;
}
if (edata->outdelay)
{
ecore_timer_del(edata->outdelay);
edata->outdelay = NULL;
_fake_out(ee);
}
/* if (e->mode != ECORE_X_EVENT_MODE_NORMAL) return 0; */
if (!_ecore_evas_mouse_in_check(ee, NULL))
{
Ecore_Event_Mouse_IO io = {
.event_window = (Ecore_Window) e->win, /* not event_win! */
.modifiers = e->modifiers,
.timestamp = e->time,
.window = (Ecore_Window) e->win,
.x = e->x,
.y = e->y
};
_ecore_evas_mouse_inout_set(ee, NULL, EINA_TRUE, EINA_FALSE);
ecore_event_evas_mouse_in(NULL, ECORE_EVENT_MOUSE_IN, &io);
}
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_ecore_evas_x_event_mouse_out(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_Evas *ee;
Ecore_X_Event_Mouse_Out *e;
Ecore_Evas_Engine_Data_X11 *edata;
e = event;
ee = ecore_event_window_match(e->win);
if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON;
/* pass on event */
if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
edata = ee->engine.data;
/*
{
time_t t;
char *ct;
const char *modes[] = {
"MODE_NORMAL",
"MODE_WHILE_GRABBED",
"MODE_GRAB",
"MODE_UNGRAB"
};
const char *details[] = {
"DETAIL_ANCESTOR",
"DETAIL_VIRTUAL",
"DETAIL_INFERIOR",
"DETAIL_NON_LINEAR",
"DETAIL_NON_LINEAR_VIRTUAL",
"DETAIL_POINTER",
"DETAIL_POINTER_ROOT",
"DETAIL_DETAIL_NONE"
};
t = time(NULL);
ct = ctime(&t);
ct[strlen(ct) - 1] = 0;
printf("@@ ->OUT 0x%x 0x%x %s md=%s dt=%s\n",
e->win, e->event_win,
ct,
modes[e->mode],
details[e->detail]);
}
*/
// disable. causes more problems than it fixes
// if ((e->mode == ECORE_X_EVENT_MODE_GRAB) ||
// (e->mode == ECORE_X_EVENT_MODE_UNGRAB))
// return 0;
// click to focus mouse out+in work-around
if ((e->mode == ECORE_X_EVENT_MODE_GRAB) &&
(e->detail == ECORE_X_EVENT_DETAIL_ANCESTOR))
{
// defer out handling in case its a "fake" out thanks to click
// to focus (which gets us another out soon after
if (edata->outdelay) ecore_timer_del(edata->outdelay);
edata->out_ev = *e;
edata->outdelay = ecore_timer_add(0.05, _fake_out, ee);
return 0;
}
if (edata->outdelay)
{
ecore_timer_del(edata->outdelay);
edata->outdelay = NULL;
}
// if (e->mode != ECORE_X_EVENT_MODE_NORMAL) return 0;
// printf("OUT: ee->in=%i, e->mode=%i, e->detail=%i, dount_count=%i\n",
// ee->in, e->mode, e->detail, evas_event_down_count_get(ee->evas));
if (_ecore_evas_mouse_in_check(ee, NULL))
{
if ((evas_event_down_count_get(ee->evas) > 0) &&
(!((e->mode == ECORE_X_EVENT_MODE_GRAB) &&
(e->detail == ECORE_X_EVENT_DETAIL_NON_LINEAR))))
return ECORE_CALLBACK_PASS_ON;
ecore_event_evas_modifier_lock_update(ee->evas, e->modifiers);
_ecore_evas_mouse_move_process(ee, e->x, e->y, e->time);
_ecore_evas_mouse_inout_set(ee, NULL, EINA_FALSE, EINA_FALSE);
_feed_cancel_out(e, (e->mode == ECORE_X_EVENT_MODE_GRAB));
_ecore_evas_default_cursor_hide(ee);
}
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_ecore_evas_x_event_window_focus_in(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_Evas *ee;
Ecore_X_Event_Window_Focus_In *e;
e = event;
ee = ecore_event_window_match(e->win);
if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; /* pass on event */
if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
//xx// filtering with these doesnt help
//xx// if (e->mode == ECORE_X_EVENT_MODE_UNGRAB) return ECORE_CALLBACK_PASS_ON;
_ecore_evas_focus_device_set(ee, NULL, EINA_TRUE);
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_ecore_evas_x_event_window_focus_out(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_Evas *ee;
Ecore_X_Event_Window_Focus_Out *e;
e = event;
ee = ecore_event_window_match(e->win);
if ((!ee) || (ee->ignore_events)) return ECORE_CALLBACK_PASS_ON; /* pass on event */
if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
//xx// filtering with these doesnt help
//xx// if (e->mode == ECORE_X_EVENT_MODE_GRAB) return ECORE_CALLBACK_PASS_ON;
// if (ee->prop.fullscreen)
// ecore_x_window_focus(ee->prop.window);
_ecore_evas_focus_device_set(ee, NULL, EINA_FALSE);
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_ecore_evas_x_event_window_damage(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_Evas *ee;
Ecore_X_Event_Window_Damage *e;
Ecore_Evas_Engine_Data_X11 *edata;
e = event;
ee = ecore_event_window_match(e->win);
if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
edata = ee->engine.data;
if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
if (edata->using_bg_pixmap) return ECORE_CALLBACK_PASS_ON;
// printf("EXPOSE %p [%i] %i %i %ix%i\n", ee, ee->prop.avoid_damage, e->x, e->y, e->w, e->h);
if (ee->prop.avoid_damage)
{
Ecore_X_Rectangle rect;
Ecore_X_XRegion *tmpr;
if (!edata->damages)
edata->damages = ecore_x_xregion_new();
tmpr = ecore_x_xregion_new();
rect.x = e->x;
rect.y = e->y;
rect.width = e->w;
rect.height = e->h;
ecore_x_xregion_union_rect(tmpr, edata->damages, &rect);
ecore_x_xregion_free(edata->damages);
edata->damages = tmpr;
/* no - this breaks things badly. disable. Ecore_X_Rectangle != XRectangle - see
* the typedefs in x's headers and ecore_x's. also same with Region - it's a pointer in x - not an X ID
Ecore_X_Rectangle rect;
Ecore_X_XRegion *tmpr;
if (!edata->damages) edata->damages = ecore_x_xregion_new();
tmpr = ecore_x_xregion_new();
rect.x = e->x;
rect.y = e->y;
rect.width = e->w;
rect.height = e->h;
ecore_x_xregion_union_rect(tmpr, edata->damages, &rect);
ecore_x_xregion_free(edata->damages);
edata->damages = tmpr;
*/
}
else
{
if (ee->rotation == 0)
evas_damage_rectangle_add(ee->evas, e->x, e->y, e->w, e->h);
else if (ee->rotation == 90)
evas_damage_rectangle_add(ee->evas,
ee->h - e->y - e->h, e->x, e->h, e->w);
else if (ee->rotation == 180)
evas_damage_rectangle_add(ee->evas, ee->w - e->x - e->w,
ee->h - e->y - e->h, e->w, e->h);
else if (ee->rotation == 270)
evas_damage_rectangle_add(ee->evas, e->y, ee->w - e->x - e->w,
e->h, e->w);
}
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_ecore_evas_x_event_window_destroy(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_Evas *ee;
Ecore_X_Event_Window_Destroy *e;
Ecore_Evas_Engine_Data_X11 *edata;
e = event;
ee = ecore_event_window_match(e->win);
if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
edata = ee->engine.data;
if (ee->func.fn_destroy) ee->func.fn_destroy(ee);
edata->destroyed = 1;
ecore_evas_free(ee);
return ECORE_CALLBACK_PASS_ON;
}
static inline void
_ecore_evas_x_shadow_update(Ecore_Evas *ee)
{
if (EINA_LIKELY(!ee->shadow.changed)) return;
int shadow[4] = { ee->shadow.l, ee->shadow.r, ee->shadow.t, ee->shadow.b };
ee->shadow.changed = EINA_FALSE;
ecore_x_window_prop_property_set(ee->prop.window,
ECORE_X_ATOM_GTK_FRAME_EXTENTS,
ECORE_X_ATOM_CARDINAL, 32, shadow, 4);
}
static void _ecore_evas_x_size_pos_hints_update(Ecore_Evas *ee);
static Eina_Bool
_ecore_evas_x_event_window_configure(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
const Evas_Device *pointer;
Ecore_Evas_Cursor *cursor;
Ecore_Evas *ee;
Ecore_X_Event_Window_Configure *e;
Ecore_Evas_Engine_Data_X11 *edata;
Eina_Bool framespace_resized = EINA_FALSE;
int fw = 0, fh = 0, w, h;
e = event;
ee = ecore_event_window_match(e->win);
if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
edata = ee->engine.data;
if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
if ((!wm_exists) || (e->from_wm) || (ee->prop.override))
{
if (!edata->configured)
{
if (edata->fully_obscured)
{
/* FIXME: round trip */
if ((!wm_exists) || (!ecore_x_screen_is_composited(edata->screen_num)))
ee->draw_block = EINA_FALSE;
}
else
ee->draw_block = EINA_FALSE;
}
edata->configure_coming = 0;
edata->configured = 1;
}
if (edata->direct_resize) return ECORE_CALLBACK_PASS_ON;
pointer = evas_default_device_get(ee->evas, EFL_INPUT_DEVICE_TYPE_MOUSE);
pointer = evas_device_parent_get(pointer);
cursor = eina_hash_find(ee->prop.cursors, &pointer);
EINA_SAFETY_ON_NULL_RETURN_VAL(cursor, ECORE_CALLBACK_PASS_ON);
if (edata->configure_reqs > 0) edata->configure_reqs--;
if ((e->from_wm) || (ee->prop.override))
{
if ((ee->x != e->x) || (ee->y != e->y))
{
ee->x = e->x;
ee->y = e->y;
ee->req.x = ee->x;
ee->req.y = ee->y;
if (ee->func.fn_move) ee->func.fn_move(ee);
}
}
_ecore_evas_x_shadow_update(ee);
evas_output_framespace_get(ee->evas, NULL, NULL, &fw, &fh);
if (!ECORE_EVAS_PORTRAIT(ee))
SWAP_INT(fw, fh);
if ((fw != ee->framespace.w) || (fh != ee->framespace.h))
{
ee->framespace.w = fw;
ee->framespace.h = fh;
framespace_resized = EINA_TRUE;
}
if (((ee->w + fw) != e->w) || ((ee->h + fh) != e->h) ||
((ee->req.w + fw) != e->w) || ((ee->req.h + fh) != e->h) ||
framespace_resized)
{
w = e->w;
h = e->h;
ee->w = w - fw;
ee->h = h - fh;
if (edata->configure_reqs == 0)
{
ee->req.w = ee->w;
ee->req.h = ee->h;
}
if (ECORE_EVAS_PORTRAIT(ee))
{
evas_output_size_set(ee->evas, w, h);
evas_output_viewport_set(ee->evas, 0, 0, w, h);
}
else
{
evas_output_size_set(ee->evas, h, w);
evas_output_viewport_set(ee->evas, 0, 0, h, w);
}
if (ee->prop.avoid_damage)
{
int pdam;
pdam = ecore_evas_avoid_damage_get(ee);
ecore_evas_avoid_damage_set(ee, 0);
ecore_evas_avoid_damage_set(ee, pdam);
}
if ((ee->shaped) || (ee->alpha))
_ecore_evas_x_resize_shape(ee);
if ((ee->expecting_resize.w > 0) && (ee->expecting_resize.h > 0))
{
if ((ee->expecting_resize.w == ee->w) &&
(ee->expecting_resize.h == ee->h))
_ecore_evas_mouse_move_process(ee, cursor->pos_x, cursor->pos_y,
ecore_x_current_time_get());
ee->expecting_resize.w = 0;
ee->expecting_resize.h = 0;
}
if (ee->func.fn_resize) ee->func.fn_resize(ee);
if (ee->prop.wm_rot.supported)
{
if (edata->wm_rot.prepare)
{
if ((ee->prop.wm_rot.w == e->w) &&
(ee->prop.wm_rot.h == e->h))
{
ee->prop.wm_rot.win_resize = 0;
edata->wm_rot.configure_coming = 0;
}
}
else if (edata->wm_rot.request)
{
if ((edata->wm_rot.configure_coming) &&
(ee->prop.wm_rot.w == e->w) &&
(ee->prop.wm_rot.h == e->h))
{
edata->wm_rot.configure_coming = 0;
if (ee->prop.wm_rot.manual_mode.set)
{
ee->prop.wm_rot.manual_mode.wait_for_done = EINA_TRUE;
_ecore_evas_x_wm_rot_manual_rotation_done_timeout_update(ee);
}
_ecore_evas_x_rotation_set(ee,
ee->prop.wm_rot.angle,
EINA_TRUE);
}
}
}
if (framespace_resized)
_ecore_evas_x_size_pos_hints_update(ee);
}
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_ecore_evas_x_event_window_delete_request(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_Evas *ee;
Ecore_X_Event_Window_Delete_Request *e;
e = event;
ee = ecore_event_window_match(e->win);
if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
if (ee->func.fn_delete_request) ee->func.fn_delete_request(ee);
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_ecore_evas_x_event_window_show(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_Evas *ee;
Ecore_X_Event_Window_Show *e;
static int first_map_bug = -1;
e = event;
ee = ecore_event_window_match(e->win);
if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
if (first_map_bug < 0)
{
char *bug = NULL;
if ((bug = getenv("ECORE_EVAS_GL_FIRST_MAP_BUG")))
first_map_bug = atoi(bug);
else
first_map_bug = 0;
}
if ((first_map_bug) && (!strcmp(ee->driver, "opengl_x11")))
evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
if (ee->visible) return ECORE_CALLBACK_PASS_ON;
// if (ee->visible) return ECORE_CALLBACK_DONE;
// printf("SHOW EVENT %p\n", ee);
ee->visible = 1;
if (ee->func.fn_show) ee->func.fn_show(ee);
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_ecore_evas_x_event_window_hide(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_Evas *ee;
Ecore_X_Event_Window_Hide *e;
e = event;
ee = ecore_event_window_match(e->win);
if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */
if (e->win != ee->prop.window) return ECORE_CALLBACK_PASS_ON;
if (_ecore_evas_mouse_in_check(ee, NULL))
{
Ecore_X_Event_Mouse_Out out = {
.event_win = e->event_win,
.modifiers = 0,
.time = e->time,
.win = e->win,
.x = 0,
.y = 0,
};
_feed_cancel_out(&out, EINA_TRUE);
_ecore_evas_mouse_inout_set(ee, NULL, EINA_FALSE, EINA_FALSE);
_ecore_evas_default_cursor_hide(ee);
}
if (ee->prop.override)
{
ee->prop.withdrawn = EINA_TRUE;
if (ee->func.fn_state_change) ee->func.fn_state_change(ee);
}
if (!ee->visible) return ECORE_CALLBACK_PASS_ON;
// if (!ee->visible) return ECORE_CALLBACK_DONE;
// printf("HIDE EVENT %p\n", ee);
ee->visible = 0;
if (ee->func.fn_hide) ee->func.fn_hide(ee);
return ECORE_CALLBACK_PASS_ON;
}
/* FIXME, should be in idler */
/* FIXME, round trip */
static void
_ecore_evas_x_size_pos_hints_update(Ecore_Evas *ee)
{
int fw, fh;
fw = ee->framespace.w;
fh = ee->framespace.h;
ecore_x_icccm_size_pos_hints_set(ee->prop.window,
ee->prop.request_pos /*request_pos */,
ECORE_X_GRAVITY_NW /* gravity */,
ee->prop.min.w + fw /* min_w */,
ee->prop.min.h + fh /* min_h */,
ee->prop.max.w + fw /* max_w */,
ee->prop.max.h + fh /* max_h */,
ee->prop.base.w + fw /* base_w */,
ee->prop.base.h + fh /* base_h */,
ee->prop.step.w /* step_x */,
ee->prop.step.h /* step_y */,
ee->prop.aspect /* min_aspect */,
ee->prop.aspect /* max_aspect */);
}
/* FIXME, should be in idler */
static void
_ecore_evas_x_state_update(Ecore_Evas *ee)
{
Ecore_X_Window_State state[10];
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
int num = 0;
if (ee->prop.modal)
state[num++] = ECORE_X_WINDOW_STATE_MODAL;
if (ee->prop.sticky)
state[num++] = ECORE_X_WINDOW_STATE_STICKY;
if (ee->prop.maximized)
state[num++] = ECORE_X_WINDOW_STATE_MAXIMIZED_VERT;
if (ee->prop.maximized)
state[num++] = ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ;
// if (bd->client.netwm.state.shaded)
// state[num++] = ECORE_X_WINDOW_STATE_SHADED;
if (ee->prop.focus_skip)
state[num++] = ECORE_X_WINDOW_STATE_SKIP_TASKBAR;
if (ee->prop.focus_skip)
state[num++] = ECORE_X_WINDOW_STATE_SKIP_PAGER;
// if (bd->client.netwm.state.hidden)
// state[num++] = ECORE_X_WINDOW_STATE_HIDDEN;
if (edata->state.fullscreen)
state[num++] = ECORE_X_WINDOW_STATE_FULLSCREEN;
if (edata->state.above)
state[num++] = ECORE_X_WINDOW_STATE_ABOVE;
if (edata->state.below)
state[num++] = ECORE_X_WINDOW_STATE_BELOW;
if (ee->prop.demand_attention)
state[num++] = ECORE_X_WINDOW_STATE_DEMANDS_ATTENTION;
ecore_x_netwm_window_state_set(ee->prop.window, state, num);
}
static void
_ecore_evas_x_layer_update(Ecore_Evas *ee)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
if (ee->should_be_visible)
{
/* We need to send a netwm request to the wm */
/* FIXME: Do we have to remove old state before adding new? */
if (ee->prop.layer < 3)
{
if (edata->state.above)
{
edata->state.above = 0;
ecore_x_netwm_state_request_send(ee->prop.window,
edata->win_root,
ECORE_X_WINDOW_STATE_ABOVE, -1, 0);
}
if (!edata->state.below)
{
edata->state.below = 1;
ecore_x_netwm_state_request_send(ee->prop.window,
edata->win_root,
ECORE_X_WINDOW_STATE_BELOW, -1, 1);
}
}
else if (ee->prop.layer > 5)
{
if (edata->state.below)
{
edata->state.below = 0;
ecore_x_netwm_state_request_send(ee->prop.window,
edata->win_root,
ECORE_X_WINDOW_STATE_BELOW, -1, 0);
}
if (!edata->state.above)
{
edata->state.above = 1;
ecore_x_netwm_state_request_send(ee->prop.window,
edata->win_root,
ECORE_X_WINDOW_STATE_ABOVE, -1, 1);
}
}
else
{
if (edata->state.below)
{
edata->state.below = 0;
ecore_x_netwm_state_request_send(ee->prop.window,
edata->win_root,
ECORE_X_WINDOW_STATE_BELOW, -1, 0);
}
if (edata->state.above)
{
edata->state.above = 0;
ecore_x_netwm_state_request_send(ee->prop.window,
edata->win_root,
ECORE_X_WINDOW_STATE_ABOVE, -1, 0);
}
}
}
else
{
/* Just set the state */
if (ee->prop.layer < 3)
{
if ((edata->state.above) || (!edata->state.below))
{
edata->state.above = 0;
edata->state.below = 1;
_ecore_evas_x_state_update(ee);
}
}
else if (ee->prop.layer > 5)
{
if ((!edata->state.above) || (edata->state.below))
{
edata->state.above = 1;
edata->state.below = 0;
_ecore_evas_x_state_update(ee);
}
}
else
{
if ((edata->state.above) || (edata->state.below))
{
edata->state.above = 0;
edata->state.below = 0;
_ecore_evas_x_state_update(ee);
}
}
}
/* FIXME: Set gnome layer */
}
EAPI void ecore_x_window_root_properties_select(void);
static int
_ecore_evas_x_init(void)
{
_ecore_evas_init_count++;
if (_ecore_evas_init_count > 1) return _ecore_evas_init_count;
ecore_x_window_root_properties_select();
wm_exists = !ecore_x_window_prop_window_get(ecore_x_window_root_first_get(), ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK, NULL, 0);
ecore_evas_event_handlers[0] =
ecore_event_handler_add(ECORE_X_EVENT_MOUSE_IN,
_ecore_evas_x_event_mouse_in, NULL);
ecore_evas_event_handlers[1] =
ecore_event_handler_add(ECORE_X_EVENT_MOUSE_OUT,
_ecore_evas_x_event_mouse_out, NULL);
ecore_evas_event_handlers[2] =
ecore_event_handler_add(ECORE_X_EVENT_WINDOW_FOCUS_IN,
_ecore_evas_x_event_window_focus_in, NULL);
ecore_evas_event_handlers[3] =
ecore_event_handler_add(ECORE_X_EVENT_WINDOW_FOCUS_OUT,
_ecore_evas_x_event_window_focus_out, NULL);
ecore_evas_event_handlers[4] =
ecore_event_handler_add(ECORE_X_EVENT_WINDOW_DAMAGE,
_ecore_evas_x_event_window_damage, NULL);
ecore_evas_event_handlers[5] =
ecore_event_handler_add(ECORE_X_EVENT_WINDOW_DESTROY,
_ecore_evas_x_event_window_destroy, NULL);
ecore_evas_event_handlers[6] =
ecore_event_handler_add(ECORE_X_EVENT_WINDOW_CONFIGURE,
_ecore_evas_x_event_window_configure, NULL);
ecore_evas_event_handlers[7] =
ecore_event_handler_add(ECORE_X_EVENT_WINDOW_DELETE_REQUEST,
_ecore_evas_x_event_window_delete_request, NULL);
ecore_evas_event_handlers[8] =
ecore_event_handler_add(ECORE_X_EVENT_WINDOW_SHOW,
_ecore_evas_x_event_window_show, NULL);
ecore_evas_event_handlers[9] =
ecore_event_handler_add(ECORE_X_EVENT_WINDOW_HIDE,
_ecore_evas_x_event_window_hide, NULL);
ecore_evas_event_handlers[10] =
ecore_event_handler_add(ECORE_X_EVENT_WINDOW_PROPERTY,
_ecore_evas_x_event_property_change, NULL);
ecore_evas_event_handlers[11] =
ecore_event_handler_add(ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE,
_ecore_evas_x_event_visibility_change, NULL);
ecore_evas_event_handlers[12] =
ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE,
_ecore_evas_x_event_client_message, NULL);
ecore_evas_event_handlers[13] =
ecore_event_handler_add(ECORE_X_EVENT_WINDOW_CREATE,
_ecore_evas_x_event_window_create, NULL);
ecore_event_evas_init();
_ecore_evas_x_selection_init();
return _ecore_evas_init_count;
}
int
_ecore_evas_x_shutdown(void)
{
_ecore_evas_init_count--;
if (_ecore_evas_init_count == 0)
{
unsigned int i;
for (i = 0; i < sizeof(ecore_evas_event_handlers) / sizeof(Ecore_Event_Handler*); i++)
{
if (ecore_evas_event_handlers[i])
ecore_event_handler_del(ecore_evas_event_handlers[i]);
}
ecore_event_evas_shutdown();
}
if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0;
return _ecore_evas_init_count;
}
static void
_ecore_evas_x_free(Ecore_Evas *ee)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
ecore_job_del(edata->init_job);
if (edata->pixmap.back)
ecore_x_pixmap_free(edata->pixmap.back);
if (edata->pixmap.front)
ecore_x_pixmap_free(edata->pixmap.front);
if (edata->wm_rot.manual_mode_job)
{
ecore_job_del(edata->wm_rot.manual_mode_job);
edata->wm_rot.manual_mode_job = NULL;
}
_ecore_evas_x_group_leader_unset(ee);
if (edata->netwm_sync_counter)
ecore_x_sync_counter_free(edata->netwm_sync_counter);
if (edata->win_shaped_input)
ecore_x_window_free(edata->win_shaped_input);
ecore_event_window_unregister(ee->prop.window);
if (ee->prop.window && (!edata->destroyed)) ecore_x_window_free(ee->prop.window);
if (edata->pmap) ecore_x_pixmap_free(edata->pmap);
if (edata->mask) ecore_x_pixmap_free(edata->mask);
if (edata->gc) ecore_x_gc_free(edata->gc);
if (edata->damages) ecore_x_xregion_free(edata->damages);
edata->pmap = 0;
edata->mask = 0;
edata->gc = 0;
edata->damages = NULL;
while (edata->win_extra)
{
Ecore_X_Window *winp;
winp = edata->win_extra->data;
edata->win_extra =
eina_list_remove_list(edata->win_extra, edata->win_extra);
ecore_event_window_unregister(*winp);
free(winp);
}
if (edata->outdelay)
{
ecore_timer_del(edata->outdelay);
edata->outdelay = NULL;
}
free(edata);
_ecore_evas_x_shutdown();
ecore_x_shutdown();
}
static void
_ecore_evas_x_callback_delete_request_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func)
{
ee->func.fn_delete_request = func;
_ecore_evas_x_protocols_set(ee);
}
static void
_ecore_evas_x_move(Ecore_Evas *ee, int x, int y)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
Eina_Bool changed = EINA_FALSE;
if ((ee->req.x != x) || (ee->req.y != y))
{
changed = EINA_TRUE;
ee->req.x = x;
ee->req.y = y;
}
if (edata->direct_resize)
{
if (!edata->managed)
{
if ((x != ee->x) || (y != ee->y))
{
ee->x = x;
ee->y = y;
if (changed) edata->configure_reqs++;
ecore_x_window_move(ee->prop.window, x, y);
if (!ee->should_be_visible)
{
/* We need to request pos */
ee->prop.request_pos = EINA_TRUE;
_ecore_evas_x_size_pos_hints_update(ee);
}
if (ee->func.fn_move) ee->func.fn_move(ee);
}
}
}
else
{
if (((ee->x != x) || (ee->y != y)) ||
(edata->configure_coming))
{
edata->configure_coming = 1;
if (!edata->managed)
{
ee->x = x;
ee->y = y;
}
if (changed) edata->configure_reqs++;
ecore_x_window_move(ee->prop.window, x, y);
}
if (!ee->should_be_visible)
{
/* We need to request pos */
ee->prop.request_pos = EINA_TRUE;
_ecore_evas_x_size_pos_hints_update(ee);
}
}
}
static void
_ecore_evas_x_managed_move(Ecore_Evas *ee, int x, int y)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
ee->req.x = x;
ee->req.y = y;
if (edata->direct_resize)
{
edata->managed = 1;
if ((x != ee->x) || (y != ee->y))
{
ee->x = x;
ee->y = y;
if (ee->func.fn_move) ee->func.fn_move(ee);
}
}
}
static void
_ecore_evas_x_resize(Ecore_Evas *ee, int w, int h)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
Eina_Bool changed = EINA_FALSE;
int fw = 0, fh = 0, vw = w, vh = h;
evas_output_framespace_get(ee->evas, NULL, NULL, &fw, &fh);
if (!ECORE_EVAS_PORTRAIT(ee)) SWAP_INT(fw, fh);
vw += fw;
vh += fh;
if ((ee->req.w != w) || (ee->req.h != h))
{
changed = EINA_TRUE;
ee->req.w = w;
ee->req.h = h;
}
/* check for valid property window
*
* NB: If we do not have one, check for valid pixmap rendering */
if (!ee->prop.window)
{
/* the ecore_evas was resized. we need to free the back pixmap */
if ((edata->pixmap.w != vw) || (edata->pixmap.h != vh))
{
/* free the backing pixmap */
if (edata->pixmap.back)
ecore_x_pixmap_free(edata->pixmap.back);
}
}
if ((!changed) && (ee->w == w) && (ee->h == h)) return;
_ecore_evas_x_shadow_update(ee);
if (edata->direct_resize)
{
ee->w = w;
ee->h = h;
if (changed) edata->configure_reqs++;
if (ee->prop.window) ecore_x_window_resize(ee->prop.window, vw, vh);
if (ECORE_EVAS_PORTRAIT(ee))
{
evas_output_size_set(ee->evas, vw, vh);
evas_output_viewport_set(ee->evas, 0, 0, vw, vh);
}
else
{
evas_output_size_set(ee->evas, vh, vw);
evas_output_viewport_set(ee->evas, 0, 0, vh, vw);
}
if (ee->prop.avoid_damage)
{
int pdam;
pdam = ecore_evas_avoid_damage_get(ee);
ecore_evas_avoid_damage_set(ee, 0);
ecore_evas_avoid_damage_set(ee, pdam);
}
if ((ee->shaped) || (ee->alpha))
_ecore_evas_x_resize_shape(ee);
if (ee->func.fn_resize) ee->func.fn_resize(ee);
}
else
{
edata->configure_coming = 1;
if (changed) edata->configure_reqs++;
if (ee->prop.window) ecore_x_window_resize(ee->prop.window, vw, vh);
}
}
static void
_ecore_evas_x_move_resize(Ecore_Evas *ee, int x, int y, int w, int h)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
Eina_Bool changed = EINA_FALSE;
int fx = 0, fy = 0, fw = 0, fh = 0, vw = w, vh = h;
// vw,vh is viewport/output size
evas_output_framespace_get(ee->evas, &fx, &fy, &fw, &fh);
if (ECORE_EVAS_PORTRAIT(ee)) SWAP_INT(fw, fh);
vw += fw;
vh += fh;
if ((ee->req.x != x) || (ee->req.y != y) ||
(ee->req.w != w) || (ee->req.h != h))
{
changed = EINA_TRUE;
ee->req.x = x;
ee->req.y = y;
ee->req.w = w;
ee->req.h = h;
}
if (edata->direct_resize)
{
if ((ee->w != w) || (ee->h != h) || (x != ee->x) || (y != ee->y))
{
int change_size = 0, change_pos = 0;
if ((ee->w != w) || (ee->h != h)) change_size = 1;
if (!edata->managed)
{
if ((x != ee->x) || (y != ee->y)) change_pos = 1;
}
if (changed) edata->configure_reqs++;
ecore_x_window_move_resize(ee->prop.window, x, y, vw, vh);
if (!edata->managed)
{
ee->x = x;
ee->y = y;
}
ee->w = w;
ee->h = h;
if (ECORE_EVAS_PORTRAIT(ee))
{
evas_output_size_set(ee->evas, vw, vh);
evas_output_viewport_set(ee->evas, 0, 0, vw, vh);
}
else
{
evas_output_size_set(ee->evas, vh, vw);
evas_output_viewport_set(ee->evas, 0, 0, vh, vw);
}
if (ee->prop.avoid_damage)
{
int pdam;
pdam = ecore_evas_avoid_damage_get(ee);
ecore_evas_avoid_damage_set(ee, 0);
ecore_evas_avoid_damage_set(ee, pdam);
}
if ((ee->shaped) || (ee->alpha))
_ecore_evas_x_resize_shape(ee);
if (change_pos)
{
if (ee->func.fn_move) ee->func.fn_move(ee);
}
if (change_size)
{
if (ee->func.fn_resize) ee->func.fn_resize(ee);
}
}
}
else
{
if ((ee->x != x) || (ee->y != y) || (edata->configure_coming))
{
edata->configure_coming = 1;
if (changed) edata->configure_reqs++;
ecore_x_window_move_resize(ee->prop.window, x, y, vw, vh);
if (!edata->managed)
{
ee->x = x;
ee->y = y;
}
}
else
{
if ((!changed) && (ee->w == w) && (ee->h == h)) return;
edata->configure_coming = 1;
if (changed) edata->configure_reqs++;
if (ee->prop.window) ecore_x_window_resize(ee->prop.window, vw, vh);
}
}
}
static void
_ecore_evas_x_rotation_set_internal(Ecore_Evas *ee, int rotation, int resize,
Evas_Engine_Info *einfo)
{
const Evas_Device *pointer;
Ecore_Evas_Cursor *cursor;
int rot_dif;
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
int fw = 0, fh = 0;
pointer = evas_default_device_get(ee->evas, EFL_INPUT_DEVICE_TYPE_MOUSE);
pointer = evas_device_parent_get(pointer);
cursor = eina_hash_find(ee->prop.cursors, &pointer);
EINA_SAFETY_ON_NULL_RETURN(cursor);
rot_dif = ee->rotation - rotation;
if (rot_dif < 0) rot_dif = -rot_dif;
evas_output_framespace_get(ee->evas, NULL, NULL, &fw, &fh);
if (rot_dif != 180)
{
int minw, minh, maxw, maxh, basew, baseh, stepw, steph;
if (!evas_engine_info_set(ee->evas, einfo))
{
ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
}
if (!resize)
{
edata->configure_coming = 1;
if (!ee->prop.fullscreen)
{
ecore_x_window_resize(ee->prop.window, ee->req.h + fw, ee->req.w + fh);
ee->expecting_resize.w = ee->h;
ee->expecting_resize.h = ee->w;
evas_output_size_set(ee->evas, ee->req.h + fw, ee->req.w + fh);
evas_output_viewport_set(ee->evas, 0, 0, ee->req.h + fw, ee->req.w + fh);
}
else
{
int w, h;
ecore_x_window_size_get(ee->prop.window, &w, &h);
ecore_x_window_resize(ee->prop.window, h, w);
if (PORTRAIT_CHECK(rotation))
{
evas_output_size_set(ee->evas, ee->req.w + fw, ee->req.h + fh);
evas_output_viewport_set(ee->evas, 0, 0, ee->req.w + fw, ee->req.h + fh);
}
else
{
evas_output_size_set(ee->evas, ee->req.h + fw, ee->req.w + fh);
evas_output_viewport_set(ee->evas, 0, 0, ee->req.h + fw, ee->req.w + fh);
}
if (ee->func.fn_resize) ee->func.fn_resize(ee);
}
if (PORTRAIT_CHECK(rotation))
evas_damage_rectangle_add(ee->evas, 0, 0, ee->req.w + fw, ee->req.h + fh);
else
evas_damage_rectangle_add(ee->evas, 0, 0, ee->req.h + fw, ee->req.w + fh);
}
else
{
/* int w, h; */
/* ecore_x_window_size_get(ee->prop.window, &w, &h); */
if (PORTRAIT_CHECK(rotation))
{
evas_output_size_set(ee->evas, ee->w + fw, ee->h + fh);
evas_output_viewport_set(ee->evas, 0, 0, ee->w + fw, ee->h + fh);
}
else
{
evas_output_size_set(ee->evas, ee->h + fw, ee->w + fh);
evas_output_viewport_set(ee->evas, 0, 0, ee->h + fw, ee->w + fh);
}
if (ee->func.fn_resize) ee->func.fn_resize(ee);
if (PORTRAIT_CHECK(rotation))
evas_damage_rectangle_add(ee->evas, 0, 0, ee->w + fw, ee->h + fh);
else
evas_damage_rectangle_add(ee->evas, 0, 0, ee->h + fw, ee->w + fh);
}
ecore_evas_size_min_get(ee, &minw, &minh);
ecore_evas_size_max_get(ee, &maxw, &maxh);
ecore_evas_size_base_get(ee, &basew, &baseh);
ecore_evas_size_step_get(ee, &stepw, &steph);
ee->rotation = rotation;
ecore_evas_size_min_set(ee, minh, minw);
ecore_evas_size_max_set(ee, maxh, maxw);
ecore_evas_size_base_set(ee, baseh, basew);
ecore_evas_size_step_set(ee, steph, stepw);
_ecore_evas_mouse_move_process(ee, cursor->pos_x, cursor->pos_y,
ecore_x_current_time_get());
}
else
{
if (!evas_engine_info_set(ee->evas, einfo))
{
ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
}
ee->rotation = rotation;
_ecore_evas_mouse_move_process(ee, cursor->pos_x, cursor->pos_y,
ecore_x_current_time_get());
if (ee->func.fn_resize) ee->func.fn_resize(ee);
if (ECORE_EVAS_PORTRAIT(ee))
evas_damage_rectangle_add(ee->evas, 0, 0, ee->w + fw, ee->h + fh);
else
evas_damage_rectangle_add(ee->evas, 0, 0, ee->h + fw, ee->w + fh);
}
}
static Eina_Bool
_ecore_evas_x_wm_rotation_check(Ecore_Evas *ee)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
if (ee->prop.wm_rot.supported)
{
if (ee->prop.wm_rot.app_set)
{
if (edata->wm_rot.request)
{
if (ee->prop.wm_rot.win_resize)
{
if (!((ee->w == ee->prop.wm_rot.w) &&
(ee->h == ee->prop.wm_rot.h)))
{
return EINA_FALSE;
}
else
edata->wm_rot.configure_coming = 0;
}
}
}
}
return EINA_TRUE;
}
static void
_rotation_do(Ecore_Evas *ee, int rotation, int resize)
{
#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
if (ee->prop.wm_rot.supported)
if (!_ecore_evas_x_wm_rotation_check(ee)) return;
Evas_Engine_Info_Software_X11 *einfo;
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas);
if (!einfo) return;
einfo->info.rotation = rotation;
_ecore_evas_x_rotation_set_internal(ee, rotation, resize,
(Evas_Engine_Info *)einfo);
if (ee->prop.wm_rot.supported)
{
if (ee->prop.wm_rot.app_set)
{
if (edata->wm_rot.request)
{
if (ee->func.fn_state_change) ee->func.fn_state_change(ee);
edata->wm_rot.request = 0;
edata->wm_rot.done = 1;
}
}
}
int angles[2] = { rotation, rotation };
ecore_x_window_prop_property_set(ee->prop.window,
ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE,
ECORE_X_ATOM_CARDINAL, 32, &angles, 2);
#endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 */
}
static void
_ecore_evas_x_rotation_set(Ecore_Evas *ee, int rotation, int resize)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
if (ee->rotation == rotation)
{
if (ee->prop.wm_rot.supported)
{
if (edata->wm_rot.request)
{
if (ee->prop.wm_rot.manual_mode.set)
{
ee->prop.wm_rot.manual_mode.wait_for_done = EINA_FALSE;
if (ee->prop.wm_rot.manual_mode.timer)
ecore_timer_del(ee->prop.wm_rot.manual_mode.timer);
ee->prop.wm_rot.manual_mode.timer = NULL;
}
/* send rotation done message to wm, even if window is already rotated.
* that's why wm must be wait for comming rotation done message
* after sending rotation request.
*/
ecore_x_e_window_rotation_change_done_send
(edata->win_root, ee->prop.window, ee->rotation, ee->w, ee->h);
edata->wm_rot.request = 0;
}
}
return;
}
if (ee->prop.wm_rot.supported)
if (!_ecore_evas_x_wm_rotation_check(ee)) return;
if (!strcmp(ee->driver, "opengl_x11"))
{
#ifdef BUILD_ECORE_EVAS_OPENGL_X11
Evas_Engine_Info_GL_X11 *einfo;
einfo = (Evas_Engine_Info_GL_X11 *)evas_engine_info_get(ee->evas);
if (!einfo) return;
einfo->info.rotation = rotation;
_ecore_evas_x_rotation_set_internal(ee, rotation, resize,
(Evas_Engine_Info *)einfo);
if (ee->prop.wm_rot.supported)
{
if (ee->prop.wm_rot.app_set)
{
if (edata->wm_rot.request)
{
if (ee->func.fn_state_change) ee->func.fn_state_change(ee);
edata->wm_rot.request = 0;
edata->wm_rot.done = 1;
}
}
}
int angles[2] = { rotation, rotation };
ecore_x_window_prop_property_set(ee->prop.window,
ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE,
ECORE_X_ATOM_CARDINAL, 32, &angles, 2);
#endif /* BUILD_ECORE_EVAS_OPENGL_X11 */
}
else if (!strcmp(ee->driver, "software_x11"))
{
if (ee->in_async_render)
{
ee->delayed.rotation = rotation;
ee->delayed.rotation_resize = resize;
ee->delayed.rotation_changed = EINA_TRUE;
return;
}
_rotation_do(ee, rotation, resize);
return;
}
}
static void
_shaped_do(Ecore_Evas *ee, int shaped)
{
#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
Evas_Engine_Info_Software_X11 *einfo;
if (ee->shaped == shaped) return;
einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas);
ee->shaped = shaped;
if (einfo)
{
if (ee->shaped)
{
unsigned int foreground;
Ecore_X_GC gc;
if (!edata->mask)
edata->mask = ecore_x_pixmap_new(ee->prop.window, ee->w, ee->h, 1);
foreground = 0;
gc = ecore_x_gc_new(edata->mask,
ECORE_X_GC_VALUE_MASK_FOREGROUND,
&foreground);
ecore_x_drawable_rectangle_fill(edata->mask, gc,
0, 0, ee->w, ee->h);
ecore_x_gc_free(gc);
einfo->info.mask = edata->mask;
if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
{
ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
}
evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
ecore_x_window_shape_input_mask_set(ee->prop.window, 0);
}
else
{
if (edata->mask) ecore_x_pixmap_free(edata->mask);
edata->mask = 0;
einfo->info.mask = 0;
if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
{
ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
}
ecore_x_window_shape_mask_set(ee->prop.window, 0);
ecore_x_window_shape_input_mask_set(ee->prop.window, 0);
}
}
#endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 */
}
static void
_ecore_evas_x_shaped_set(Ecore_Evas *ee, int shaped)
{
if (!strcmp(ee->driver, "opengl_x11")) return;
if (!strcmp(ee->driver, "software_x11"))
{
if (ee->in_async_render)
{
ee->delayed.shaped = shaped;
ee->delayed.shaped_changed = EINA_TRUE;
return;
}
_shaped_do(ee, shaped);
}
}
static void
_alpha_do(Ecore_Evas *ee, int alpha)
{
char *id = NULL;
#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
Ecore_X_Window_Attributes att;
Evas_Engine_Info_Software_X11 *einfo;
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
if (ee->alpha == alpha) return;
einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas);
if (!einfo) return;
if (!ecore_x_composite_query()) return;
ee->shaped = 0;
ee->alpha = alpha;
ecore_x_window_free(ee->prop.window);
ecore_event_window_unregister(ee->prop.window);
if (ee->alpha)
{
if (ee->prop.override)
ee->prop.window = ecore_x_window_override_argb_new(edata->win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h);
else
ee->prop.window = ecore_x_window_argb_new(edata->win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h);
// if (!edata->mask)
// edata->mask = ecore_x_pixmap_new(ee->prop.window, ee->req.w, ee->req.h, 1);
}
else
{
if (ee->prop.override)
ee->prop.window = ecore_x_window_override_new(edata->win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h);
else
ee->prop.window = ecore_x_window_new(edata->win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h);
if (edata->mask) ecore_x_pixmap_free(edata->mask);
edata->mask = 0;
ecore_x_window_shape_input_mask_set(ee->prop.window, 0);
ecore_x_vsync_animator_tick_source_set(ee->prop.window);
}
einfo->info.destination_alpha = alpha;
ecore_x_window_attributes_get(ee->prop.window, &att);
einfo->info.visual = att.visual;
einfo->info.colormap = att.colormap;
einfo->info.depth = att.depth;
// if (edata->mask) ecore_x_pixmap_free(edata->mask);
// edata->mask = 0;
einfo->info.mask = edata->mask;
einfo->info.drawable = ee->prop.window;
if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
{
ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
}
evas_damage_rectangle_add(ee->evas, 0, 0, ee->req.w, ee->req.h);
ecore_x_window_shape_mask_set(ee->prop.window, 0);
ecore_x_input_multi_select(ee->prop.window);
ecore_event_window_register(ee->prop.window, ee, ee->evas,
(Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process,
(Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process,
(Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process,
(Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process);
_ecore_event_window_direct_cb_set(ee->prop.window, _ecore_evas_input_direct_cb);
if (ee->prop.borderless)
ecore_x_mwm_borderless_set(ee->prop.window, ee->prop.borderless);
if (ee->visible || ee->should_be_visible)
ecore_x_window_show(ee->prop.window);
if (ecore_evas_focus_device_get(ee, NULL)) ecore_x_window_focus(ee->prop.window);
if (ee->prop.title)
{
ecore_x_icccm_title_set(ee->prop.window, ee->prop.title);
ecore_x_netwm_name_set(ee->prop.window, ee->prop.title);
}
if (ee->prop.name)
ecore_x_icccm_name_class_set(ee->prop.window,
ee->prop.name, ee->prop.clas);
_ecore_evas_x_hints_update(ee);
_ecore_evas_x_group_leader_update(ee);
ecore_x_window_defaults_set(ee->prop.window);
_ecore_evas_x_protocols_set(ee);
_ecore_evas_x_window_profile_protocol_set(ee);
_ecore_evas_x_wm_rotation_protocol_set(ee);
_ecore_evas_x_aux_hints_supported_update(ee);
_ecore_evas_x_aux_hints_update(ee);
_ecore_evas_x_size_pos_hints_update(ee);
_ecore_evas_x_selection_window_init(ee);
#endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 */
if ((id = getenv("DESKTOP_STARTUP_ID")))
{
ecore_x_netwm_startup_id_set(ee->prop.window, id);
/* NB: on linux this may simply empty the env as opposed to completely
* unset it to being empty - unsure as solartis libc crashes looking
* for the '=' char */
// putenv((char*)"DESKTOP_STARTUP_ID=");
}
}
/* FIXME, round trip */
static void
_ecore_evas_x_alpha_set(Ecore_Evas *ee, int alpha)
{
char *id = NULL;
if (!strcmp(ee->driver, "software_x11"))
{
if (ee->in_async_render)
{
if (ee->visible)
{
ee->delayed.alpha = alpha;
ee->delayed.alpha_changed = EINA_TRUE;
return;
}
evas_sync(ee->evas);
}
_alpha_do(ee, alpha);
}
else if (!strcmp(ee->driver, "opengl_x11"))
{
#ifdef BUILD_ECORE_EVAS_OPENGL_X11
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
Ecore_X_Window_Attributes att;
if (ee->alpha == alpha) return;
Evas_Engine_Info_GL_X11 *einfo;
Ecore_Window prev_win;
einfo = (Evas_Engine_Info_GL_X11 *)evas_engine_info_get(ee->evas);
if (!einfo) return;
if (!ecore_x_composite_query()) return;
ee->shaped = 0;
ee->alpha = alpha;
prev_win = ee->prop.window;
ee->prop.window = 0;
einfo->info.destination_alpha = alpha;
if (edata->win_root != 0)
{
/* FIXME: round trip in ecore_x_window_argb_get */
if (ecore_x_window_argb_get(edata->win_root))
{
ee->prop.window =
_ecore_evas_x_gl_window_new(ee, edata->win_root,
ee->req.x, ee->req.y,
ee->req.w, ee->req.h,
ee->prop.override, 1, NULL);
}
else
{
ee->prop.window =
_ecore_evas_x_gl_window_new(ee, edata->win_root,
ee->req.x, ee->req.y,
ee->req.w, ee->req.h,
ee->prop.override, ee->alpha,
NULL);
}
}
else
{
ee->prop.window =
_ecore_evas_x_gl_window_new(ee, edata->win_root,
ee->req.x, ee->req.y,
ee->req.w, ee->req.h,
ee->prop.override, ee->alpha, NULL);
}
ecore_x_window_free(prev_win);
ecore_event_window_unregister(prev_win);
if (!ee->prop.window) return;
/*
if (ee->alpha)
{
if (ee->prop.override)
ee->prop.window = ecore_x_window_override_argb_new(edata->win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h);
else
ee->prop.window = ecore_x_window_argb_new(edata->win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h);
if (!edata->mask)
edata->mask = ecore_x_pixmap_new(ee->prop.window, ee->req.w, ee->req.h, 1);
}
else
{
if (ee->prop.override)
ee->prop.window = ecore_x_window_override_new(edata->win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h);
else
ee->prop.window = ecore_x_window_new(edata->win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h);
if (edata->mask) ecore_x_pixmap_free(edata->mask);
edata->mask = 0;
ecore_x_window_shape_input_mask_set(ee->prop.window, 0);
}
*/
ecore_x_window_attributes_get(ee->prop.window, &att);
einfo->info.visual = att.visual;
einfo->info.colormap = att.colormap;
einfo->info.depth = att.depth;
// if (edata->mask) ecore_x_pixmap_free(edata->mask);
// edata->mask = 0;
// einfo->info.mask = edata->mask;
einfo->info.drawable = ee->prop.window;
if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
{
ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
}
evas_damage_rectangle_add(ee->evas, 0, 0, ee->req.w, ee->req.h);
// ecore_x_window_shape_mask_set(ee->prop.window, 0);
ecore_x_input_multi_select(ee->prop.window);
ecore_event_window_register(ee->prop.window, ee, ee->evas,
(Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process,
(Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process,
(Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process,
(Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process);
_ecore_event_window_direct_cb_set(ee->prop.window, _ecore_evas_input_direct_cb);
if (ee->prop.borderless)
ecore_x_mwm_borderless_set(ee->prop.window, ee->prop.borderless);
if (ee->visible || ee->should_be_visible)
ecore_x_window_show(ee->prop.window);
if (ecore_evas_focus_device_get(ee, NULL)) ecore_x_window_focus(ee->prop.window);
if (ee->prop.title)
{
ecore_x_icccm_title_set(ee->prop.window, ee->prop.title);
ecore_x_netwm_name_set(ee->prop.window, ee->prop.title);
}
if (ee->prop.name)
ecore_x_icccm_name_class_set(ee->prop.window,
ee->prop.name, ee->prop.clas);
_ecore_evas_x_hints_update(ee);
_ecore_evas_x_group_leader_update(ee);
ecore_x_window_defaults_set(ee->prop.window);
_ecore_evas_x_protocols_set(ee);
_ecore_evas_x_window_profile_protocol_set(ee);
_ecore_evas_x_wm_rotation_protocol_set(ee);
_ecore_evas_x_aux_hints_supported_update(ee);
_ecore_evas_x_aux_hints_update(ee);
_ecore_evas_x_size_pos_hints_update(ee);
_ecore_evas_x_selection_window_init(ee);
#endif /* BUILD_ECORE_EVAS_OPENGL_X11 */
if ((id = getenv("DESKTOP_STARTUP_ID")))
{
ecore_x_netwm_startup_id_set(ee->prop.window, id);
/* NB: on linux this may simply empty the env as opposed to completely
* unset it to being empty - unsure as solartis libc crashes looking
* for the '=' char */
// putenv((char*)"DESKTOP_STARTUP_ID=");
}
}
}
static void
_transparent_do(Ecore_Evas *ee, int transparent)
{
#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
if (ee->transparent == transparent) return;
Evas_Engine_Info_Software_X11 *einfo;
einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas);
if (!einfo) return;
ee->transparent = transparent;
einfo->info.destination_alpha = transparent;
if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
{
ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
}
evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
#endif
}
static void
_ecore_evas_x_transparent_set(Ecore_Evas *ee, int transparent)
{
if (!strcmp(ee->driver, "software_x11"))
{
if (ee->in_async_render)
{
ee->delayed.transparent = transparent;
ee->delayed.transparent_changed = EINA_TRUE;
return;
}
_transparent_do(ee, transparent);
}
}
static void
_ecore_evas_x_window_group_set(Ecore_Evas *ee, const Ecore_Evas *group_ee)
{
if (ee->prop.group_ee == group_ee) return;
ee->prop.group_ee = (Ecore_Evas *)group_ee;
if (ee->prop.group_ee)
ee->prop.group_ee_win = group_ee->prop.window;
else
ee->prop.group_ee_win = 0;
_ecore_evas_x_hints_update(ee);
}
static void
_ecore_evas_x_aspect_set(Ecore_Evas *ee, double aspect)
{
if (EINA_FLT_EQ(ee->prop.aspect, aspect)) return;
ee->prop.aspect = aspect;
_ecore_evas_x_size_pos_hints_update(ee);
// netwm state
// if (ee->should_be_visible)
// ecore_x_netwm_state_request_send(ee->prop.window, ee->engine.x.win_root,
// ECORE_X_WINDOW_STATE_STICKY, -1, sticky);
// else
// _ecore_evas_x_state_update(ee);
}
static void
_ecore_evas_x_urgent_set(Ecore_Evas *ee, Eina_Bool on)
{
if (ee->prop.urgent == on) return;
ee->prop.urgent = on;
_ecore_evas_x_hints_update(ee);
}
static void
_ecore_evas_x_modal_set(Ecore_Evas *ee, Eina_Bool on)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
if (ee->prop.modal == on) return;
ee->prop.modal = on;
if (ee->should_be_visible)
ecore_x_netwm_state_request_send(ee->prop.window, edata->win_root,
ECORE_X_WINDOW_STATE_MODAL, -1, on);
else
_ecore_evas_x_state_update(ee);
}
static void
_ecore_evas_x_demand_attention_set(Ecore_Evas *ee, Eina_Bool on)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
if (ee->prop.demand_attention == on) return;
ee->prop.demand_attention = on;
if (ee->should_be_visible)
ecore_x_netwm_state_request_send(ee->prop.window, edata->win_root,
ECORE_X_WINDOW_STATE_DEMANDS_ATTENTION,
-1, on);
else
_ecore_evas_x_state_update(ee);
}
static void
_ecore_evas_x_focus_skip_set(Ecore_Evas *ee, Eina_Bool on)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
if (ee->prop.focus_skip == on) return;
ee->prop.focus_skip = on;
if (ee->should_be_visible)
{
ecore_x_netwm_state_request_send(ee->prop.window, edata->win_root,
ECORE_X_WINDOW_STATE_SKIP_TASKBAR, -1,
on);
ecore_x_netwm_state_request_send(ee->prop.window, edata->win_root,
ECORE_X_WINDOW_STATE_SKIP_PAGER, -1,
on);
}
else
_ecore_evas_x_state_update(ee);
_ecore_evas_x_hints_update(ee);
}
static void
_ecore_evas_x_show(Ecore_Evas *ee)
{
ee->should_be_visible = 1;
if (ee->prop.avoid_damage)
_ecore_evas_x_render(ee);
_ecore_evas_x_window_profile_set(ee);
if (!ee->prop.withdrawn) _ecore_evas_x_hints_update(ee);
else
{
ee->prop.withdrawn = EINA_FALSE;
_ecore_evas_x_hints_update(ee);
ee->prop.withdrawn = EINA_TRUE;
}
ecore_x_window_show(ee->prop.window);
if (ee->prop.fullscreen) ecore_x_window_focus(ee->prop.window);
}
static void
_ecore_evas_x_hide(Ecore_Evas *ee)
{
ecore_x_window_hide(ee->prop.window);
ee->should_be_visible = 0;
}
static void
_ecore_evas_x_raise(Ecore_Evas *ee)
{
ecore_x_window_raise(ee->prop.window);
}
static void
_ecore_evas_x_lower(Ecore_Evas *ee)
{
ecore_x_window_lower(ee->prop.window);
}
static void
_ecore_evas_x_activate(Ecore_Evas *ee)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
ecore_evas_show(ee);
ecore_x_netwm_client_active_request(edata->win_root,
ee->prop.window, 2, 0);
}
static void
_ecore_evas_x_title_set(Ecore_Evas *ee, const char *t)
{
if (eina_streq(ee->prop.title, t)) return;
if (ee->prop.title) free(ee->prop.title);
ee->prop.title = NULL;
if (!t) return;
ee->prop.title = strdup(t);
ecore_x_icccm_title_set(ee->prop.window, ee->prop.title);
ecore_x_netwm_name_set(ee->prop.window, ee->prop.title);
}
static void
_ecore_evas_x_name_class_set(Ecore_Evas *ee, const char *n, const char *c)
{
if (!eina_streq(n, ee->prop.name))
{
free(ee->prop.name);
ee->prop.name = NULL;
if (n) ee->prop.name = strdup(n);
}
if (!eina_streq(c, ee->prop.clas))
{
free(ee->prop.clas);
ee->prop.clas = NULL;
if (c) ee->prop.clas = strdup(c);
}
ecore_x_icccm_name_class_set(ee->prop.window, ee->prop.name, ee->prop.clas);
}
static void
_ecore_evas_x_size_min_set(Ecore_Evas *ee, int w, int h)
{
if (w < 0) w = 0;
if (h < 0) h = 0;
if ((ee->prop.min.w == w) && (ee->prop.min.h == h)) return;
ee->prop.min.w = w;
ee->prop.min.h = h;
_ecore_evas_x_size_pos_hints_update(ee);
}
static void
_ecore_evas_x_size_max_set(Ecore_Evas *ee, int w, int h)
{
if (w < 0) w = 0;
if (h < 0) h = 0;
if ((ee->prop.max.w == w) && (ee->prop.max.h == h)) return;
ee->prop.max.w = w;
ee->prop.max.h = h;
_ecore_evas_x_size_pos_hints_update(ee);
}
static void
_ecore_evas_x_size_base_set(Ecore_Evas *ee, int w, int h)
{
if (w < 0) w = 0;
if (h < 0) h = 0;
if ((ee->prop.base.w == w) && (ee->prop.base.h == h)) return;
ee->prop.base.w = w;
ee->prop.base.h = h;
_ecore_evas_x_size_pos_hints_update(ee);
}
static void
_ecore_evas_x_size_step_set(Ecore_Evas *ee, int w, int h)
{
if (w < 1) w = 1;
if (h < 1) h = 1;
if ((ee->prop.step.w == w) && (ee->prop.step.h == h)) return;
ee->prop.step.w = w;
ee->prop.step.h = h;
_ecore_evas_x_size_pos_hints_update(ee);
}
static void
_ecore_evas_x_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj,
int layer EINA_UNUSED, int hot_x EINA_UNUSED,
int hot_y EINA_UNUSED)
{
if (obj != _ecore_evas_default_cursor_image_get(ee))
ecore_x_window_cursor_show(ee->prop.window, 0);
}
static void
_ecore_evas_x_object_cursor_unset(Ecore_Evas *ee)
{
ecore_x_window_cursor_show(ee->prop.window, 1);
}
/*
* @param ee
* @param layer If < 3, @a ee will be put below all other windows.
* If > 5, @a ee will be "always-on-top"
* If = 4, @a ee will be put in the default layer.
* Acceptable values range from 1 to 255 (0 reserved for
* desktop windows)
*/
static void
_ecore_evas_x_layer_set(Ecore_Evas *ee, int layer)
{
if (ee->prop.layer == layer) return;
/* FIXME: Should this logic be here? */
if (layer < 1)
layer = 1;
else if (layer > 255)
layer = 255;
ee->prop.layer = layer;
_ecore_evas_x_layer_update(ee);
}
static void
_ecore_evas_x_focus_set(Ecore_Evas *ee, Eina_Bool on EINA_UNUSED)
{
ecore_x_window_focus(ee->prop.window);
}
static void
_ecore_evas_x_iconified_set(Ecore_Evas *ee, Eina_Bool on)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
if (ee->prop.iconified == on) return;
ee->prop.iconified = on;
_ecore_evas_x_hints_update(ee);
if (on)
ecore_x_icccm_iconic_request_send(ee->prop.window, edata->win_root);
else
ecore_evas_activate(ee);
}
static void
_ecore_evas_x_borderless_set(Ecore_Evas *ee, Eina_Bool on)
{
if (ee->prop.borderless == on) return;
ee->prop.borderless = on;
ecore_x_mwm_borderless_set(ee->prop.window, ee->prop.borderless);
}
/* FIXME: This function changes the initial state of the ee
* whilest the iconic function changes the current state! */
static void
_ecore_evas_x_withdrawn_set(Ecore_Evas *ee, Eina_Bool on)
{
if (ee->prop.withdrawn == on) return;
// ee->prop.withdrawn = on;
if (on)
ecore_evas_hide(ee);
else
ecore_evas_show(ee);
}
static void
_ecore_evas_x_sticky_set(Ecore_Evas *ee, Eina_Bool on)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
if (ee->prop.sticky == on) return;
/* We dont want to set prop.sticky here as it will cause
* the sticky callback not to get called. Its set on the
* property change event.
* ee->prop.sticky = on;
*/
// edata->state.sticky = on;
if (ee->should_be_visible)
ecore_x_netwm_state_request_send(ee->prop.window, edata->win_root,
ECORE_X_WINDOW_STATE_STICKY, -1, on);
else
_ecore_evas_x_state_update(ee);
}
static void
_ecore_evas_x_ignore_events_set(Ecore_Evas *ee, int ignore)
{
if (ee->ignore_events == ignore) return;
ee->ignore_events = ignore;
if (ee->prop.window)
ecore_x_window_ignore_set(ee->prop.window, ignore);
}
/*
static void
_ecore_evas_x_reinit_win(Ecore_Evas *ee)
{
if (!strcmp(ee->driver, "software_x11"))
{
#ifdef BUILD_ECORE_EVAS_X11
Evas_Engine_Info_Software_X11 *einfo;
einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas);
if (einfo)
{
einfo->info.drawable = ee->prop.window;
if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
{
ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
}
}
#endif
}
else if (!strcmp(ee->driver, "opengl_x11"))
{
#ifdef BUILD_ECORE_EVAS_OPENGL_X11
Evas_Engine_Info_GL_X11 *einfo;
einfo = (Evas_Engine_Info_GL_X11 *)evas_engine_info_get(ee->evas);
if (einfo)
{
einfo->info.drawable = ee->prop.window;
if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
{
ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
}
}
#endif
}
}
*/
static void
_ecore_evas_x_override_set(Ecore_Evas *ee, Eina_Bool on)
{
if (ee->prop.override == on) return;
if (ee->should_be_visible) ecore_x_window_hide(ee->prop.window);
ecore_x_window_override_set(ee->prop.window, on);
if (ee->should_be_visible) ecore_x_window_show(ee->prop.window);
if (ecore_evas_focus_device_get(ee, NULL)) ecore_x_window_focus(ee->prop.window);
ee->prop.override = on;
}
static void
_ecore_evas_x_maximized_set(Ecore_Evas *ee, Eina_Bool on)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
if (ee->should_be_visible)
{
ecore_x_netwm_state_request_send(ee->prop.window, edata->win_root,
ECORE_X_WINDOW_STATE_MAXIMIZED_VERT,
ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ,
on);
}
else
{
if (ee->prop.maximized == on) return;
ee->prop.maximized = on;
edata->state.maximized_h = on;
edata->state.maximized_v = on;
_ecore_evas_x_state_update(ee);
}
}
static void
_ecore_evas_x_fullscreen_set(Ecore_Evas *ee, Eina_Bool on)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
if (ee->prop.fullscreen == on) return;
/* FIXME: Detect if WM is EWMH compliant and handle properly if not,
* i.e. reposition, resize, and change borderless hint */
edata->state.fullscreen = on;
if (ee->should_be_visible)
ecore_x_netwm_state_request_send(ee->prop.window, edata->win_root,
ECORE_X_WINDOW_STATE_FULLSCREEN, -1, on);
else
_ecore_evas_x_state_update(ee);
}
static void
_ecore_evas_x_profile_set(Ecore_Evas *ee, const char *profile)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
_ecore_evas_window_profile_free(ee);
ee->prop.profile.name = NULL;
if (profile)
ee->prop.profile.name = (char *)eina_stringshare_add(profile);
edata->profile.change = 1;
_ecore_evas_x_window_profile_set(ee);
}
static void
_ecore_evas_x_profiles_set(Ecore_Evas *ee, const char **plist, int n)
{
int i;
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
_ecore_evas_window_available_profiles_free(ee);
ee->prop.profile.available_list = NULL;
if ((plist) && (n >= 1))
{
ee->prop.profile.available_list = calloc(n, sizeof(char *));
if (ee->prop.profile.available_list)
{
for (i = 0; i < n; i++)
ee->prop.profile.available_list[i] = (char *)eina_stringshare_add(plist[i]);
ee->prop.profile.count = n;
}
}
edata->profile.available = 1;
_ecore_evas_x_window_profile_set(ee);
}
static void
_avoid_damage_do(Ecore_Evas *ee, int on)
{
#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
Evas_Engine_Info_Software_X11 *einfo;
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
ee->prop.avoid_damage = on;
einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas);
if (einfo)
{
if (ee->prop.avoid_damage)
{
edata->pmap = ecore_x_pixmap_new(ee->prop.window, ee->w, ee->h, einfo->info.depth);
edata->gc = ecore_x_gc_new(edata->pmap, 0, NULL);
einfo->info.drawable = edata->pmap;
if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
{
ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
}
if (ECORE_EVAS_PORTRAIT(ee))
evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h);
else
evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w);
if (ee->prop.avoid_damage == ECORE_EVAS_AVOID_DAMAGE_BUILT_IN)
{
edata->using_bg_pixmap = 1;
ecore_x_window_pixmap_set(ee->prop.window, edata->pmap);
ecore_x_window_area_expose(ee->prop.window, 0, 0, ee->w, ee->h);
}
if (edata->direct_resize)
{
/* Turn this off for now
edata->using_bg_pixmap = 1;
ecore_x_window_pixmap_set(ee->prop.window, edata->pmap);
*/
}
}
else
{
if (edata->pmap) ecore_x_pixmap_free(edata->pmap);
if (edata->gc) ecore_x_gc_free(edata->gc);
if (edata->using_bg_pixmap)
{
ecore_x_window_pixmap_set(ee->prop.window, 0);
edata->using_bg_pixmap = 0;
ecore_x_window_area_expose(ee->prop.window, 0, 0, ee->w, ee->h);
}
edata->pmap = 0;
edata->gc = 0;
einfo->info.drawable = ee->prop.window;
if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
{
ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
}
}
}
#endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 */
}
static void
_ecore_evas_x_avoid_damage_set(Ecore_Evas *ee, int on)
{
if (ee->prop.avoid_damage == on) return;
if (!strcmp(ee->driver, "opengl_x11")) return;
if (!strcmp(ee->driver, "software_x11"))
{
if (ee->in_async_render)
{
ee->delayed.avoid_damage = on;
return;
}
_avoid_damage_do(ee, on);
}
}
static void
_ecore_evas_x_screen_geometry_get(const Ecore_Evas *ee, int *x, int *y, int *w, int *h)
{
int outnum = 0, i;
int px = 0, py = 0, pw = 0, ph = 0;
Ecore_X_Window root;
Ecore_X_Randr_Output *out = NULL;
Ecore_X_Randr_Crtc crtc;
unsigned int val[4] = { 0 };
Eina_Bool found = EINA_FALSE;
if (ecore_x_window_prop_card32_get
(ee->prop.window, ecore_x_atom_get("E_ZONE_GEOMETRY"), val, 4) == 4)
{
if (x) *x = (int)val[0];
if (y) *y = (int)val[1];
if (w) *w = (int)val[2];
if (h) *h = (int)val[3];
return;
}
root = ecore_x_window_root_get(ee->prop.window);
out = ecore_x_randr_window_outputs_get(ee->prop.window, &outnum);
if (!out)
{
norandr:
if (x) *x = 0;
if (y) *y = 0;
ecore_x_window_size_get(root, w, h);
return;
}
for (i = 0; i < outnum; i++)
{
Eina_Rectangle winrect, outrect;
crtc = ecore_x_randr_output_crtc_get(root, out[i]);
if (!crtc) continue;
ecore_x_randr_crtc_geometry_get(root, crtc, &px, &py, &pw, &ph);
if ((pw == 0) || (ph == 0)) continue;
if ((i == 0) || (ecore_x_randr_primary_output_get(root) == out[i]))
{
found = EINA_TRUE;
if (x) *x = px;
if (y) *y = py;
if (w) *w = pw;
if (h) *h = ph;
}
winrect.x = ee->x + (ee->w / 2);
winrect.y = ee->y + (ee->h / 2);
winrect.w = 1;
winrect.h = 1;
outrect.x = px;
outrect.y = py;
outrect.w = pw;
outrect.h = ph;
if (eina_rectangles_intersect(&outrect, &winrect))
{
if (x) *x = px;
if (y) *y = py;
if (w) *w = pw;
if (h) *h = ph;
free(out);
return;
}
}
free(out);
if (!found) goto norandr;
}
static void
_ecore_evas_x_screen_dpi_get(const Ecore_Evas *ee, int *xdpi, int *ydpi)
{
int scdpi, xmm = 0, ymm = 0, outnum = 0, w = 0, h = 0;
int px = 0, py = 0, i;
Ecore_X_Window root;
Ecore_X_Randr_Output *out = NULL;
Ecore_X_Randr_Crtc crtc;
Eina_Bool found = EINA_FALSE;
root = ecore_x_window_root_get(ee->prop.window);
out = ecore_x_randr_window_outputs_get(ee->prop.window, &outnum);
if (!out)
{
norandr:
scdpi = ecore_x_dpi_get();
if (xdpi) *xdpi = scdpi;
if (ydpi) *ydpi = scdpi;
return;
}
for (i = 0; i < outnum; i++)
{
Eina_Rectangle winrect, outrect;
crtc = ecore_x_randr_output_crtc_get(root, out[i]);
if (!crtc) continue;
ecore_x_randr_crtc_geometry_get(root, crtc, &px, &py, &w, &h);
if ((w == 0) || (h == 0)) continue;
ecore_x_randr_output_size_mm_get(root, out[i], &xmm, &ymm);
if ((xmm == 0) || (ymm == 0)) continue;
if ((i == 0) || (ecore_x_randr_primary_output_get(root) == out[i]))
{
found = EINA_TRUE;
if (xdpi) *xdpi = (w * 254) / (xmm * 10); // 25.4mm / inch
if (ydpi) *ydpi = (h * 254) / (ymm * 10); // 25.4mm / inch
}
winrect.x = ee->x + (ee->w / 2);
winrect.y = ee->y + (ee->h / 2);
winrect.w = 1;
winrect.h = 1;
outrect.x = px;
outrect.y = py;
outrect.w = w;
outrect.h = h;
if (eina_rectangles_intersect(&outrect, &winrect))
{
if (xdpi) *xdpi = (w * 254) / (xmm * 10); // 25.4mm / inch
if (ydpi) *ydpi = (h * 254) / (ymm * 10); // 25.4mm / inch
free(out);
return;
}
}
free(out);
if (!found) goto norandr;
}
static void
_ecore_evas_x_pointer_xy_get(const Ecore_Evas *ee, Evas_Coord *x, Evas_Coord *y)
{
if (ee->prop.window)
ecore_x_pointer_xy_get(ee->prop.window, x, y);
}
static Eina_Bool
_ecore_evas_x_pointer_warp(const Ecore_Evas *ee, Evas_Coord x, Evas_Coord y)
{
return ecore_x_pointer_warp(ee->prop.window, x, y);
}
static void
_ecore_evas_x_wm_rot_preferred_rotation_set(Ecore_Evas *ee, int rot)
{
if (ee->prop.wm_rot.supported)
{
if (!ee->prop.wm_rot.app_set)
{
ecore_x_e_window_rotation_app_set(ee->prop.window, EINA_TRUE);
ee->prop.wm_rot.app_set = EINA_TRUE;
}
ecore_x_e_window_rotation_preferred_rotation_set(ee->prop.window, rot);
ee->prop.wm_rot.preferred_rot = rot;
}
}
static void
_ecore_evas_x_wm_rot_available_rotations_set(Ecore_Evas *ee, const int *rots, unsigned int count)
{
if (ee->prop.wm_rot.supported)
{
if (!ee->prop.wm_rot.app_set)
{
ecore_x_e_window_rotation_app_set(ee->prop.window, EINA_TRUE);
ee->prop.wm_rot.app_set = EINA_TRUE;
}
if (ee->prop.wm_rot.available_rots)
{
free(ee->prop.wm_rot.available_rots);
ee->prop.wm_rot.available_rots = NULL;
}
ee->prop.wm_rot.count = 0;
if (count > 0)
{
ee->prop.wm_rot.available_rots = calloc(count, sizeof(int));
if (!ee->prop.wm_rot.available_rots) return;
memcpy(ee->prop.wm_rot.available_rots, rots, sizeof(int) * count);
}
ee->prop.wm_rot.count = count;
ecore_x_e_window_rotation_available_rotations_set(ee->prop.window, rots, count);
}
}
static void
_ecore_evas_x_wm_rot_manual_rotation_done_set(Ecore_Evas *ee, Eina_Bool set)
{
ee->prop.wm_rot.manual_mode.set = set;
}
static void
_ecore_evas_x_wm_rot_manual_rotation_done(Ecore_Evas *ee)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
if ((ee->prop.wm_rot.supported) &&
(ee->prop.wm_rot.app_set) &&
(ee->prop.wm_rot.manual_mode.set))
{
if (ee->prop.wm_rot.manual_mode.wait_for_done)
{
if (ee->prop.wm_rot.manual_mode.timer)
ecore_timer_del(ee->prop.wm_rot.manual_mode.timer);
ee->prop.wm_rot.manual_mode.timer = NULL;
if (edata->wm_rot.manual_mode_job)
ecore_job_del(edata->wm_rot.manual_mode_job);
edata->wm_rot.manual_mode_job = ecore_job_add
(_ecore_evas_x_wm_rot_manual_rotation_done_job, ee);
}
}
}
static Eina_Bool
_ecore_evas_x_wm_rot_manual_rotation_done_timeout(void *data)
{
Ecore_Evas *ee = data;
ee->prop.wm_rot.manual_mode.timer = NULL;
_ecore_evas_x_wm_rot_manual_rotation_done(ee);
return ECORE_CALLBACK_CANCEL;
}
static void
_ecore_evas_x_wm_rot_manual_rotation_done_timeout_update(Ecore_Evas *ee)
{
if (ee->prop.wm_rot.manual_mode.timer)
ecore_timer_del(ee->prop.wm_rot.manual_mode.timer);
ee->prop.wm_rot.manual_mode.timer = ecore_timer_add
(4.0f, _ecore_evas_x_wm_rot_manual_rotation_done_timeout, ee);
}
static void
_ecore_evas_x_aux_hints_set(Ecore_Evas *ee, const char *hints)
{
if (hints)
ecore_x_window_prop_property_set
(ee->prop.window, ECORE_X_ATOM_E_WINDOW_AUX_HINT,
ECORE_X_ATOM_STRING, 8, (void *)hints, strlen(hints) + 1);
else
ecore_x_window_prop_property_del
(ee->prop.window, ECORE_X_ATOM_E_WINDOW_AUX_HINT);
}
static Ecore_X_Atom ecore_evas_selection_to_atom[] = {0, 0, 0, 0};
static Ecore_Event_Handler *ecore_evas_selection_handlers[8];
static inline Ecore_Evas_Selection_Buffer
_atom_to_selection(Ecore_X_Atom atom)
{
for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i)
{
if (ecore_evas_selection_to_atom[i] == atom)
return i;
}
return ECORE_EVAS_SELECTION_BUFFER_LAST;
}
static Eina_Stringshare*
_decrypt_type(const char *target)
{
// reference https://tronche.com/gui/x/icccm/sec-2.html
if (eina_streq(target, "TEXT")) return eina_stringshare_add("text/plain");
//FIXME no support in eina_content for that so far
if (eina_streq(target, "COMPOUND_TEXT")) return eina_stringshare_add("text/plain");
// reference https://tronche.com/gui/x/icccm/sec-2.html
if (eina_streq(target, "STRING")) return eina_stringshare_add("text/plain;charset=iso-8859-1");
if (eina_streq(target, "UTF8_STRING")) return eina_stringshare_add("text/plain;charset=utf-8");
return eina_stringshare_add(target);
}
static Eina_Stringshare*
_mime_to_xserver_type(const char *target)
{
// FIXME // reference https://tronche.com/gui/x/icccm/sec-2.html says it is in the owners choice of encoding, not sure what this means directly here
if (eina_streq(target, "text/plain")) return eina_stringshare_add("TEXT");
// reference https://tronche.com/gui/x/icccm/sec-2.html
if (eina_streq(target, "text/plain;charset=iso-8859-1")) return eina_stringshare_add("STRING");
if (eina_streq(target, "text/plain;charset=utf-8")) return eina_stringshare_add("UTF8_STRING");
return eina_stringshare_add(target);
}
static inline void
_clear_selection(Ecore_Evas *ee, Ecore_Evas_Selection_Buffer selection)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
Ecore_Evas_Selection_Callbacks *cbs = &edata->selection_data[selection].callbacks;
EINA_SAFETY_ON_FALSE_RETURN(cbs->cancel);
cbs->cancel(ee, 1, selection);
eina_array_free(cbs->available_types);
cbs->delivery = NULL;
cbs->cancel = NULL;
cbs->available_types = NULL;
}
static void
_clear_selection_delivery(Ecore_Evas *ee, Ecore_Evas_Selection_Buffer selection)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
eina_stringshare_replace(&edata->selection_data[selection].requested_type, NULL);
eina_stringshare_replace(&edata->selection_data[selection].later_conversion, NULL);
edata->selection_data[selection].delivery = NULL;
eina_array_free(edata->selection_data[selection].acceptable_type);
edata->selection_data[selection].acceptable_type = NULL;
}
static void
_ecore_x_selection_request(Ecore_X_Window win, Ecore_Evas_Selection_Buffer selection, const char *type)
{
if (selection == ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER)
ecore_x_selection_primary_request(win, type);
else if (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER)
ecore_x_selection_clipboard_request(win, type);
else
ecore_x_selection_xdnd_request(win, type);
}
static void
_search_fitting_type(Ecore_Evas *ee, Ecore_Evas_Engine_Data_X11 *edata, Ecore_Evas_Selection_Buffer selection, Eina_Array *arr)
{
Eina_Stringshare *mime_type;
Eina_Bool found_conversion = EINA_FALSE;
#define HANDLE_TYPE() \
{ \
edata->selection_data[selection].requested_type = eina_stringshare_add(x11_name); \
edata->selection_data[selection].later_conversion = eina_stringshare_add(acceptable_type);\
found_conversion = EINA_TRUE; \
break; \
}
EINA_SAFETY_ON_NULL_RETURN(edata->selection_data[selection].acceptable_type);
for (unsigned int i = 0; i < eina_array_count(arr) && !found_conversion; ++i)
{
const char *x11_name = eina_array_data_get(arr, i);
mime_type = _decrypt_type(x11_name);
for (unsigned int j = 0; j < eina_array_count(edata->selection_data[selection].acceptable_type) && !found_conversion; ++j)
{
const char *acceptable_type = (const char*) eina_array_data_get(edata->selection_data[selection].acceptable_type, j);
if (mime_type == acceptable_type)
HANDLE_TYPE()
//if there is no available type yet, check if we can convert to the desired type via this type
if (!found_conversion)
{
const char *convertion_type = NULL;
Eina_Iterator *iter = eina_content_converter_possible_conversions(mime_type);
EINA_ITERATOR_FOREACH(iter, convertion_type)
{
if (convertion_type == acceptable_type)
HANDLE_TYPE()
}
eina_iterator_free(iter);
}
}
eina_stringshare_del(mime_type);
}
if (found_conversion)
{
_ecore_x_selection_request(ee->prop.window, selection, edata->selection_data[selection].requested_type);
}
else
{
eina_promise_resolve(edata->selection_data[selection].delivery, eina_value_error_init(ecore_evas_no_matching_type));
_clear_selection_delivery(ee, selection);
}
#undef HANDLE_TYPE
}
static void
_search_fitting_type_from_event(Ecore_Evas *ee, Ecore_Evas_Engine_Data_X11 *edata, Ecore_Evas_Selection_Buffer selection, Ecore_X_Event_Selection_Notify *ev)
{
Ecore_X_Atom *available_atoms;
Ecore_X_Selection_Data_Targets *targets;
Eina_Array *tmp = eina_array_new(10);
targets = ev->data;
available_atoms = (Ecore_X_Atom *)targets->data.data;
for (int i = 0; i < targets->data.length; ++i)
{
Ecore_X_Atom atom = available_atoms[i];
eina_array_push(tmp, ecore_x_atom_name_get(atom));
}
_search_fitting_type(ee, edata, selection, tmp);
eina_array_free(tmp);
}
static Eina_Content*
_create_delivery_content(unsigned long int size, const void *mem, const char *mime_type)
{
Eina_Content *content;
content = eina_content_new((Eina_Slice){.len = size, .mem = mem}, mime_type);
return content;
}
static void
_deliver_content(Ecore_Evas *ee, Ecore_Evas_Engine_Data_X11 *edata, Ecore_Evas_Selection_Buffer selection, Ecore_X_Event_Selection_Notify *ev)
{
Eina_Content *result = NULL;
Eina_Stringshare *mime_type = _decrypt_type(edata->selection_data[selection].requested_type);
EINA_SAFETY_ON_NULL_GOTO(ev->data, err);
if (eina_streq(mime_type, "text/uri-list"))
{
Ecore_X_Selection_Data_Files *files = ev->data;
Efreet_Uri *uri;
Eina_Strbuf *strbuf;
int i;
strbuf = eina_strbuf_new();
for (i = 0; i < files->num_files ; i++)
{
uri = efreet_uri_decode(files->files[i]);
if (uri)
{
eina_strbuf_append(strbuf, uri->path);
efreet_uri_free(uri);
}
else
{
eina_strbuf_append(strbuf, files->files[i]);
}
if (i < (files->num_files - 1))
eina_strbuf_append(strbuf, "\n");
}
result = _create_delivery_content(eina_strbuf_length_get(strbuf) + 1, eina_strbuf_string_get(strbuf), mime_type);
eina_strbuf_free(strbuf);
}
else if (eina_str_has_prefix(mime_type,"text"))
{
Ecore_X_Selection_Data *x11_data = ev->data;
//ensure that we always have a \0 at the end, there is no assertion that \0 is included here.
void *null_terminated = eina_memdup(x11_data->data, x11_data->length, EINA_TRUE);
result = _create_delivery_content(x11_data->length + 1, null_terminated, mime_type);
free(null_terminated);
}
else if (eina_str_has_prefix(mime_type,"image"))
{
Ecore_X_Selection_Data *x11_data = ev->data;
Eina_Content *tmp_container = eina_content_new((Eina_Slice){.len = x11_data->length, .mem = x11_data->data}, mime_type);
const char *file = eina_content_as_file(tmp_container);
result = _create_delivery_content(strlen(file), file, mime_type);
eina_content_free(tmp_container);
}
else
{
Ecore_X_Selection_Data *x11_data = ev->data;
result = _create_delivery_content(x11_data->length, x11_data->data, mime_type);
}
EINA_SAFETY_ON_NULL_GOTO(result, err);
//ensure that we deliver the correct type, we might have choosen a convertion before
if (edata->selection_data[selection].later_conversion != mime_type)
{
Eina_Content *tmp = eina_content_convert(result, edata->selection_data[selection].later_conversion);
eina_content_free(result);
result = tmp;
}
eina_promise_resolve(edata->selection_data[selection].delivery, eina_value_content_init(result));
eina_content_free(result);
_clear_selection_delivery(ee, selection);
if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER)
ecore_x_dnd_send_finished();
return;
err:
eina_promise_reject(edata->selection_data[selection].delivery, ecore_evas_no_selection);
if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER)
ecore_x_dnd_send_finished();
}
static Eina_Bool
_ecore_evas_x_selection_notify(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_X_Event_Selection_Notify *ev = event;
Ecore_Evas_Selection_Buffer selection;
Ecore_Evas_Engine_Data_X11 *edata;
Ecore_Evas *ee;
ee = ecore_event_window_match(ev->win);
selection = _atom_to_selection(ev->atom);
EINA_SAFETY_ON_FALSE_GOTO(!!ee, end);
EINA_SAFETY_ON_FALSE_GOTO(selection != ECORE_EVAS_SELECTION_BUFFER_LAST, end);
edata = ee->engine.data;
//if dnd drops above us, and even if we did not request anything, we are getting notified, refuse to do anything
if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER &&
!edata->selection_data[selection].later_conversion)
{
ecore_x_dnd_send_finished();
}
else
{
if (eina_streq(ev->target, "TARGETS") || eina_streq(ev->target, "ATOMS"))
{
//This will decide for a type, and will sent that via _ecore_x_selection_request
EINA_SAFETY_ON_FALSE_RETURN_VAL(!edata->selection_data[selection].later_conversion, EINA_FALSE);
EINA_SAFETY_ON_FALSE_RETURN_VAL(!edata->selection_data[selection].requested_type, EINA_FALSE);
_search_fitting_type_from_event(ee, edata, selection, ev);
}
else
{
//This will read the data, fill it into a Eina_Content apply all conversions required.
EINA_SAFETY_ON_FALSE_RETURN_VAL(edata->selection_data[selection].later_conversion, EINA_FALSE);
EINA_SAFETY_ON_FALSE_RETURN_VAL(edata->selection_data[selection].requested_type, EINA_FALSE);
_deliver_content(ee, edata, selection, ev);
}
}
end:
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_ecore_evas_x_selection_clear(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_X_Event_Selection_Clear *ev = event;
Ecore_Evas_Selection_Callbacks *cbs;
Ecore_Evas_Engine_Data_X11 *edata;
Ecore_Evas_Selection_Buffer selection;
Ecore_Evas *ee;
ee = ecore_event_window_match(ev->win);
selection = _atom_to_selection(ev->atom);
EINA_SAFETY_ON_FALSE_GOTO(ee, end);
EINA_SAFETY_ON_FALSE_GOTO(selection != ECORE_EVAS_SELECTION_BUFFER_LAST, end);
edata = ee->engine.data;
cbs = &edata->selection_data[selection].callbacks;
//skip clean event
if (edata->skip_clean_event)
{
edata->skip_clean_event --;
goto end;
}
if (cbs->cancel)
_clear_selection(ee, selection);
end:
return ECORE_CALLBACK_PASS_ON;
}
static void
_force_stop_self_dnd(Ecore_Evas *ee)
{
Ecore_Evas_Engine_Data_X11 *edata;
EINA_SAFETY_ON_NULL_RETURN(ee);
edata = ee->engine.data;
EINA_SAFETY_ON_NULL_RETURN(edata);
//Never clear the buffer for selection here.
//Selection buffer is freed as a response to the FINISHED event.
ecore_x_pointer_ungrab();
ecore_x_dnd_self_drop();
ecore_x_dnd_aware_set(ee->prop.window, EINA_FALSE);
ecore_event_handler_del(edata->mouse_up_handler);
edata->mouse_up_handler = NULL;
if (ee->drag.free)
ee->drag.free(ee, 1, ee->drag.data, ee->drag.accepted);
ee->drag.free = NULL;
}
static Eina_Bool
_ecore_evas_x_selection_fixes_notify(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_X_Event_Fixes_Selection_Notify *ev = event;
Ecore_Evas *ee;
Ecore_Evas_Selection_Buffer selection;
ee = ecore_event_window_match(ev->win);
selection = _atom_to_selection(ev->atom);
EINA_SAFETY_ON_FALSE_GOTO(!!ee, end);
EINA_SAFETY_ON_FALSE_GOTO(selection != ECORE_EVAS_SELECTION_BUFFER_LAST, end);
//notify that the selection has changed on this ecore evas
if (ee->func.fn_selection_changed)
ee->func.fn_selection_changed(ee, 0, selection);
end:
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_eina_content_converter(char *target, void *data, int size EINA_UNUSED, void **data_ret, int *size_ret, Ecore_X_Atom *ttype, int *typesize)
{
Ecore_Evas_X11_Selection_Data *sdata = data;
Eina_Bool ret = EINA_FALSE;;
if (size != sizeof(Ecore_Evas_X11_Selection_Data)) return EINA_FALSE;
if (!EINA_MAGIC_CHECK(sdata, ECORE_EVAS_X11_SELECTION)) return EINA_FALSE;
if (eina_streq(target, "TARGETS") || eina_streq(target, "ATOM"))
{
//list all available types that we have currently
Ecore_X_Atom *result = calloc(eina_array_count(sdata->callbacks.available_types), sizeof(Ecore_X_Atom));
for (unsigned int i = 0; i < eina_array_count(sdata->callbacks.available_types); ++i)
{
result[i] = ecore_x_atom_get(eina_array_data_get(sdata->callbacks.available_types, i));
}
*size_ret = eina_array_count(sdata->callbacks.available_types);
*data_ret = result;
*ttype = ECORE_X_ATOM_ATOM;
*typesize = 32; /* urk */
ret = EINA_TRUE;
}
else
{
const char *mime_type = _decrypt_type(target);
for (unsigned int i = 0; i < eina_array_count(sdata->callbacks.available_types); ++i)
{
if (mime_type == eina_array_data_get(sdata->callbacks.available_types, i))
{
Eina_Rw_Slice slice;
sdata->callbacks.delivery(sdata->ee, 1, sdata->buffer, mime_type, &slice);
*size_ret = slice.len;
*data_ret = slice.mem;
*ttype = ecore_x_atom_get(target); //use here target in order to get the correct atom
//FIXME in selection manager we never set here the typesize, isn't that weird ?
ret = EINA_TRUE;
// XXX: fixup for strings to not include nul byte if last
// byte is nul byte
if (((!strncmp(target, "text/", 5)) ||
(!strcmp(target, "tex")) ||
(!strcmp(target, "TEXT")) ||
(!strcmp(target, "COMPOUND_TEXT")) ||
(!strcmp(target, "STRING")) ||
(!strcmp(target, "UTF8_STRING"))) &&
(slice.len > 0) && (slice.bytes[slice.len - 1] == '\0'))
{
*size_ret = *size_ret - 1;
}
break;
}
}
eina_stringshare_del(mime_type);
}
return ret;
}
static Eina_Bool
_ecore_evas_x_dnd_enter(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_X_Event_Xdnd_Enter *enter = event;
Eina_Array *mime_tmp;
Ecore_Evas_Engine_Data_X11 *edata;
Ecore_Evas *ee;
mime_tmp = eina_array_new(10);
ee = ecore_event_window_match(enter->win);
EINA_SAFETY_ON_NULL_GOTO(ee, end);
edata = ee->engine.data;
edata->xserver_atom_name_during_dnd = eina_array_new(10);
for (int i = 0; i < enter->num_types; ++i)
{
const char *mime_type = _decrypt_type(enter->types[i]);
eina_array_push(mime_tmp, mime_type);
eina_array_push(edata->xserver_atom_name_during_dnd, eina_stringshare_add(enter->types[i]));
}
ecore_evas_dnd_enter(ee, 1, eina_array_iterator_new(mime_tmp), EINA_POSITION2D(0,0)); //FIXME
end:
eina_array_free(mime_tmp);
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_ecore_evas_x_dnd_leave(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_X_Event_Xdnd_Leave *leave = event;
Ecore_Evas_Engine_Data_X11 *edata;
Ecore_Evas *ee;
ee = ecore_event_window_match(leave->win);
EINA_SAFETY_ON_NULL_GOTO(ee, end);
edata = ee->engine.data;
ecore_evas_dnd_leave(ee, 1, EINA_POSITION2D(0,0));
for (unsigned int i = 0; i < eina_array_count(edata->xserver_atom_name_during_dnd); ++i)
{
eina_stringshare_del(eina_array_data_get(edata->xserver_atom_name_during_dnd, i));
}
eina_array_free(edata->xserver_atom_name_during_dnd);
edata->xserver_atom_name_during_dnd = NULL;
end:
return ECORE_CALLBACK_PASS_ON;
}
static Ecore_X_Atom
_x11_dnd_action_rev_map(const char* action)
{
if (eina_streq(action, "copy")) return ECORE_X_ATOM_XDND_ACTION_COPY;
if (eina_streq(action, "move")) return ECORE_X_ATOM_XDND_ACTION_MOVE;
else if (eina_streq(action, "privat")) return ECORE_X_ATOM_XDND_ACTION_PRIVATE;
else if (eina_streq(action, "ask")) return ECORE_X_ATOM_XDND_ACTION_ASK;
else if (eina_streq(action, "list")) return ECORE_X_ATOM_XDND_ACTION_LIST;
else if (eina_streq(action, "link")) return ECORE_X_ATOM_XDND_ACTION_LINK;
else if (eina_streq(action, "description")) return ECORE_X_ATOM_XDND_ACTION_DESCRIPTION;
return 0;
}
static const char*
_x11_dnd_action_map(Ecore_X_Atom action)
{
if (action == ECORE_X_DND_ACTION_COPY) return "copy";
if (action == ECORE_X_ATOM_XDND_ACTION_MOVE) return "move";
if (action == ECORE_X_ATOM_XDND_ACTION_PRIVATE) return "privat";
if (action == ECORE_X_ATOM_XDND_ACTION_ASK) return "ask";
if (action == ECORE_X_ATOM_XDND_ACTION_LIST) return "list";
if (action == ECORE_X_ATOM_XDND_ACTION_LINK) return "link";
if (action == ECORE_X_ATOM_XDND_ACTION_DESCRIPTION) return "description";
return "unknown";
}
static Eina_Bool
_ecore_evas_x_dnd_position(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_X_Event_Xdnd_Position *pos = event;
int x, y, w, h;
Ecore_Evas *ee;
ee = ecore_event_window_match(pos->win);
EINA_SAFETY_ON_NULL_GOTO(ee, end);
ecore_evas_geometry_get(ee, &x, &y, &w, &h);
Eina_Bool used = ecore_evas_dnd_position_set(ee, 1, EINA_POSITION2D(pos->position.x - x, pos->position.y - y));
if (used)
ecore_x_dnd_send_status(EINA_TRUE, EINA_FALSE, (Ecore_X_Rectangle){x,y,w,h}, pos->action);
end:
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_ecore_evas_x_dnd_drop(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_X_Event_Xdnd_Drop *drop = event;
Ecore_Evas_Engine_Data_X11 *edata;
Ecore_Evas *ee;
ee = ecore_event_window_match(drop->win);
EINA_SAFETY_ON_NULL_GOTO(ee, end);
edata = ee->engine.data;
if (ee->func.fn_dnd_drop)
ee->func.fn_dnd_drop(ee, 1, ecore_evas_dnd_pos_get(ee, 1), _x11_dnd_action_map(drop->action));
if (edata->selection_data[ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER].delivery &&
!edata->selection_data[ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER].requested_type)
{
//only abort dnd if we have something to deliver here, otherwise some other dnd implementation in our own window is handling that
ecore_x_dnd_send_finished();
}
ecore_evas_dnd_leave(ee, 1, EINA_POSITION2D(drop->position.x ,drop->position.y));
eina_array_free(edata->xserver_atom_name_during_dnd);
edata->xserver_atom_name_during_dnd = NULL;
end:
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_ecore_evas_x_finished(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event)
{
Ecore_X_Event_Xdnd_Finished *finished = event;
Ecore_Evas *ee;
ee = ecore_event_window_match(finished->win);
EINA_SAFETY_ON_NULL_GOTO(ee, end);
_clear_selection(ee, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER);
end:
return ECORE_CALLBACK_PASS_ON;
}
static void
_ecore_evas_x_selection_init(void)
{
Ecore_X_Atom _ecore_evas_selection_to_atom[] = {ECORE_X_ATOM_SELECTION_PRIMARY, ECORE_X_ATOM_SELECTION_CLIPBOARD, ECORE_X_ATOM_SELECTION_XDND};
for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i)
{
ecore_evas_selection_to_atom[i] = _ecore_evas_selection_to_atom[i];
}
ecore_evas_selection_handlers[0] =
ecore_event_handler_add(ECORE_X_EVENT_SELECTION_NOTIFY,
_ecore_evas_x_selection_notify, NULL);
ecore_evas_selection_handlers[1] =
ecore_event_handler_add(ECORE_X_EVENT_SELECTION_CLEAR,
_ecore_evas_x_selection_clear, NULL);
if (ECORE_X_EVENT_FIXES_SELECTION_NOTIFY)
ecore_evas_selection_handlers[2] =
ecore_event_handler_add(ECORE_X_EVENT_FIXES_SELECTION_NOTIFY,
_ecore_evas_x_selection_fixes_notify, NULL);
ecore_evas_selection_handlers[3] = ecore_event_handler_add(ECORE_X_EVENT_XDND_ENTER,
_ecore_evas_x_dnd_enter, NULL);
ecore_evas_selection_handlers[4] = ecore_event_handler_add(ECORE_X_EVENT_XDND_LEAVE,
_ecore_evas_x_dnd_leave, NULL);
ecore_evas_selection_handlers[5] = ecore_event_handler_add(ECORE_X_EVENT_XDND_POSITION,
_ecore_evas_x_dnd_position, NULL);
ecore_evas_selection_handlers[6] = ecore_event_handler_add(ECORE_X_EVENT_XDND_DROP,
_ecore_evas_x_dnd_drop, NULL);
ecore_evas_selection_handlers[7] = ecore_event_handler_add(ECORE_X_EVENT_XDND_FINISHED,
_ecore_evas_x_finished, NULL);
/* for us known type */
char *supported_types[] = {
"text/plain",
"text/plain;charset=utf-8",
"image/png",
"image/jpeg",
"image/x-ms-bmp",
"image/gif",
"image/tiff",
"image/svg+xml",
"image/x-xpixmap",
"image/x-tga",
"image/x-portable-pixmap",
"TEXT",
"COMPOUND_TEXT",
"STRING",
"UTF8_STRING",
"text/x-vcard",
"text/uri-list",
"application/x-elementary-markup",
"ATOM",
"TARGETS",
NULL
};
for (int i = 0; supported_types[i]; ++i)
{
ecore_x_selection_converter_add(supported_types[i], _eina_content_converter);
}
}
static Eina_Bool
_ecore_evas_x_selection_has_owner(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection)
{
return !!ecore_x_selection_owner_get(ecore_evas_selection_to_atom[selection]);
}
static void
_deliver_selection_changed(void *data)
{
Ecore_Evas *ee = data;
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
if (!ee->func.fn_selection_changed)
goto end;
if (_ecore_evas_x_selection_has_owner(ee, 1, ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER))
ee->func.fn_selection_changed(ee, 1, ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER);
if (_ecore_evas_x_selection_has_owner(ee, 1, ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER))
ee->func.fn_selection_changed(ee, 1, ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER);
if (_ecore_evas_x_selection_has_owner(ee, 1, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER))
ee->func.fn_selection_changed(ee, 1, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER);
end:
edata->init_job = NULL;
}
static void
_ecore_evas_x_selection_window_init(Ecore_Evas *ee)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i)
{
ecore_x_fixes_window_selection_notification_request(ee->prop.window, ecore_evas_selection_to_atom[i]);
edata->selection_data[i].ee = ee;
edata->selection_data[i].buffer = i;
EINA_MAGIC_SET(&edata->selection_data[i], ECORE_EVAS_X11_SELECTION);
}
ecore_x_dnd_aware_set(ee->prop.window, EINA_TRUE);
edata->init_job = ecore_job_add(_deliver_selection_changed, ee);
}
static void
_store_selection_cbs(Ecore_Evas *ee, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Eina_Bool (*delivery)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, const char *type, Eina_Rw_Slice *slice), void (*cancel)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer))
{
Ecore_Evas_X11_Selection_Data *sdata;
Ecore_Evas_Engine_Data_X11 *edata;
Ecore_Evas_Selection_Callbacks *cbs;
edata = ee->engine.data;
sdata = &edata->selection_data[selection];
cbs = &sdata->callbacks;
if (cbs->cancel)
{
_clear_selection(ee, selection);
edata->skip_clean_event ++; //we are going to overwrite our own selection, this will emit a clean event, but we already freed it.
}
cbs->delivery = delivery;
cbs->cancel = cancel;
cbs->available_types = available_types;
}
static Eina_Bool
_ecore_evas_x_selection_claim(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection, Eina_Array *available_types, Ecore_Evas_Selection_Internal_Delivery delivery, Ecore_Evas_Selection_Internal_Cancel cancel)
{
Ecore_Evas_X11_Selection_Data *sdata;
Ecore_Evas_Engine_Data_X11 *edata;
edata = ee->engine.data;
sdata = &edata->selection_data[selection];
_store_selection_cbs(ee, selection, available_types, delivery, cancel);
if (eina_array_count(available_types) > 0)
{
//the commands below will *copy* the content of sdata, this you have to ensure that clear is called when sdata is changed.
if (selection == ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER)
ecore_x_selection_primary_set(ee->prop.window, sdata, sizeof(Ecore_Evas_X11_Selection_Data));
else if (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER)
ecore_x_selection_clipboard_set(ee->prop.window, sdata, sizeof(Ecore_Evas_X11_Selection_Data));
}
else
{
if (selection == ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER)
ecore_x_selection_primary_clear();
else if (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER)
ecore_x_selection_clipboard_clear();
}
//for drag and drop, we are not calling anything in here
return EINA_TRUE;
}
Eina_Future*
_ecore_evas_x_selection_request(Ecore_Evas *ee EINA_UNUSED, unsigned int seat EINA_UNUSED, Ecore_Evas_Selection_Buffer selection, Eina_Array *acceptable_type)
{
Ecore_Evas_X11_Selection_Data *sdata;
Ecore_Evas_Engine_Data_X11 *edata;
Eina_Future *future;
edata = ee->engine.data;
sdata = &edata->selection_data[selection];
if (sdata->delivery)
{
eina_promise_reject(sdata->delivery, ecore_evas_request_replaced);
_clear_selection_delivery(ee, selection);
}
sdata->delivery = efl_loop_promise_new(efl_main_loop_get());
sdata->acceptable_type = acceptable_type;
future = eina_future_new(sdata->delivery);
if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER)
{
//when in dnd - we are requesting out of the set that we know from the enter event
EINA_SAFETY_ON_FALSE_RETURN_VAL(!edata->selection_data[selection].later_conversion, NULL);
EINA_SAFETY_ON_FALSE_RETURN_VAL(!edata->selection_data[selection].requested_type, NULL);
_search_fitting_type(ee, edata, selection, edata->xserver_atom_name_during_dnd);
}
else
{
//when not dnd - we are first wanting to know what is available
_ecore_x_selection_request(ee->prop.window, selection, ECORE_X_SELECTION_TARGET_TARGETS);
}
return future;
}
static void
_x11_drag_move(void *data, Ecore_X_Xdnd_Position *pos)
{
Ecore_Evas *ee = data;
Eina_Rect rect;
ecore_evas_geometry_get(ee->drag.rep, &rect.x, &rect.y, &rect.w, &rect.h);
ecore_evas_move(ee->drag.rep, pos->position.x - rect.w / 2, pos->position.y - rect.h/2);
}
static Eina_Bool
_x11_drag_mouse_up(void *data, int etype EINA_UNUSED, void *event EINA_UNUSED)
{
Ecore_Evas *ee = data;
_force_stop_self_dnd(ee);
return EINA_TRUE;
}
static Eina_Bool
_ecore_evas_x_dnd_start(Ecore_Evas *ee, unsigned int seat EINA_UNUSED, Eina_Array *available_types, Ecore_Evas *drag_rep, Eina_Bool (*delivery)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer, const char *type, Eina_Rw_Slice *slice), void (*cancel)(Ecore_Evas *ee, unsigned int seat, Ecore_Evas_Selection_Buffer buffer), const char* action)
{
Ecore_Evas_X11_Selection_Data *sdata;
Ecore_Evas_Engine_Data_X11 *edata;
Ecore_X_Atom actx;
edata = ee->engine.data;
sdata = &edata->selection_data[ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER];
_store_selection_cbs(ee, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER, available_types, delivery, cancel);
//first set all types we have
ecore_x_dnd_types_set(ee->prop.window, NULL, 0);
for (unsigned int i = 0; i < eina_array_count(available_types); ++i)
{
const char *xserver_mime_type = _mime_to_xserver_type(eina_array_data_get(available_types, i));
ecore_x_dnd_type_set(ee->prop.window, xserver_mime_type, EINA_TRUE);
eina_stringshare_del(xserver_mime_type);
}
ecore_x_dnd_aware_set(ee->prop.window, EINA_TRUE);
ecore_x_dnd_callback_pos_update_set(_x11_drag_move, ee);
ecore_x_dnd_self_begin(ee->prop.window, (unsigned char*)sdata, sizeof(Ecore_Evas_X11_Selection_Data));
actx = _x11_dnd_action_rev_map(action);
ecore_x_dnd_source_action_set(actx);
ecore_x_pointer_grab(ee->prop.window);
ecore_x_window_ignore_set(drag_rep->prop.window, EINA_TRUE);
if (edata->mouse_up_handler)
ecore_event_handler_del(edata->mouse_up_handler);
edata->mouse_up_handler = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP,
_x11_drag_mouse_up, ee);
return EINA_TRUE;
}
static Eina_Bool
_ecore_evas_x_dnd_stop(Ecore_Evas *ee, unsigned int seat EINA_UNUSED)
{
_force_stop_self_dnd(ee);
_clear_selection(ee, ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER);
ecore_x_selection_xdnd_clear(); //This is needed otherwise a outdated sdata struct will be accessed
return EINA_TRUE;
}
static Ecore_Evas_Engine_Func _ecore_x_engine_func =
{
_ecore_evas_x_free,
NULL,
NULL,
NULL,
NULL,
_ecore_evas_x_callback_delete_request_set,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
_ecore_evas_x_move,
_ecore_evas_x_managed_move,
_ecore_evas_x_resize,
_ecore_evas_x_move_resize,
_ecore_evas_x_rotation_set,
_ecore_evas_x_shaped_set,
_ecore_evas_x_show,
_ecore_evas_x_hide,
_ecore_evas_x_raise,
_ecore_evas_x_lower,
_ecore_evas_x_activate,
_ecore_evas_x_title_set,
_ecore_evas_x_name_class_set,
_ecore_evas_x_size_min_set,
_ecore_evas_x_size_max_set,
_ecore_evas_x_size_base_set,
_ecore_evas_x_size_step_set,
_ecore_evas_x_object_cursor_set,
_ecore_evas_x_object_cursor_unset,
_ecore_evas_x_layer_set,
_ecore_evas_x_focus_set,
_ecore_evas_x_iconified_set,
_ecore_evas_x_borderless_set,
_ecore_evas_x_override_set,
_ecore_evas_x_maximized_set,
_ecore_evas_x_fullscreen_set,
_ecore_evas_x_avoid_damage_set,
_ecore_evas_x_withdrawn_set,
_ecore_evas_x_sticky_set,
_ecore_evas_x_ignore_events_set,
_ecore_evas_x_alpha_set,
_ecore_evas_x_transparent_set,
_ecore_evas_x_profiles_set,
_ecore_evas_x_profile_set,
_ecore_evas_x_window_group_set,
_ecore_evas_x_aspect_set,
_ecore_evas_x_urgent_set,
_ecore_evas_x_modal_set,
_ecore_evas_x_demand_attention_set,
_ecore_evas_x_focus_skip_set,
NULL, // render
_ecore_evas_x_screen_geometry_get,
_ecore_evas_x_screen_dpi_get,
NULL,
NULL, //fn_msg_send
_ecore_evas_x_pointer_xy_get,
_ecore_evas_x_pointer_warp,
_ecore_evas_x_wm_rot_preferred_rotation_set,
_ecore_evas_x_wm_rot_available_rotations_set,
_ecore_evas_x_wm_rot_manual_rotation_done_set,
_ecore_evas_x_wm_rot_manual_rotation_done,
_ecore_evas_x_aux_hints_set,
NULL, // fn_animator_register
NULL, // fn_animator_unregister
NULL, // fn_evas_changed
NULL, //fn_focus_device_set
NULL, //fn_callback_focus_device_in_set
NULL, //fn_callback_focus_device_out_set
NULL, //fn_callback_device_mouse_in_set
NULL, //fn_callback_device_mouse_out_set
NULL, //fn_pointer_device_xy_get
NULL, //fn_prepare
NULL, //fn_last_tick_get
_ecore_evas_x_selection_claim, //fn_selection_claim
_ecore_evas_x_selection_has_owner, //fn_selection_has_owner
_ecore_evas_x_selection_request, //fn_selection_request
_ecore_evas_x_dnd_start, //fn_dnd_start
_ecore_evas_x_dnd_stop, //fn_dnd_stop
};
/*
* FIXME: there are some round trips. Especially, we can split
* ecore_x_init in 2 functions and suppress some round trips.
*/
#if defined (BUILD_ECORE_EVAS_SOFTWARE_X11) || defined (BUILD_ECORE_EVAS_OPENGL_X11)
static void
_ecore_evas_x_render_pre(void *data, Evas *e EINA_UNUSED, void *event_info EINA_UNUSED)
{
Ecore_Evas *ee = data;
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
/* printf("Ecore_Evas Render Pre\n"); */
/* printf("\tPixman Size: %d %d\n", edata->pixmap.w, edata->pixmap.h); */
/* printf("\tEE Size: %d %d\n", ee->w, ee->h); */
/* before rendering to the back buffer pixmap, we should check the
* size. If the back buffer is not the proper size, destroy it and
* create a new one at the proper size */
if ((edata->pixmap.w != ee->w) || (edata->pixmap.h != ee->h))
{
int fw = 0, fh = 0;
/* free the backing pixmap */
if (edata->pixmap.back)
ecore_x_pixmap_free(edata->pixmap.back);
edata->pixmap.back =
ecore_x_pixmap_new(edata->win_root, ee->w, ee->h,
edata->pixmap.depth);
evas_output_framespace_get(ee->evas, NULL, NULL, &fw, &fh);
edata->pixmap.w = ee->w + fw;
edata->pixmap.h = ee->h + fh;
if (!strcmp(ee->driver, "software_x11"))
{
# ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
Evas_Engine_Info_Software_X11 *einfo;
einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas);
if (einfo)
{
einfo->info.drawable = edata->pixmap.back;
if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
{
ERR("evas_engine_info_set() init engine '%s' failed.",
ee->driver);
}
}
# endif
}
else if (!strcmp(ee->driver, "opengl_x11"))
{
# ifdef BUILD_ECORE_EVAS_OPENGL_X11
Evas_Engine_Info_GL_X11 *einfo;
einfo = (Evas_Engine_Info_GL_X11 *)evas_engine_info_get(ee->evas);
if (einfo)
{
einfo->info.drawable = edata->pixmap.back;
if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
{
ERR("evas_engine_info_set() init engine '%s' failed.",
ee->driver);
}
}
# endif
}
}
}
static void
_ecore_evas_x_flush_post(void *data, Evas *e EINA_UNUSED, void *event_info EINA_UNUSED)
{
Ecore_Evas *ee = data;
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
if ((!ee->prop.window) && (edata->pixmap.back))
{
Ecore_X_Pixmap prev;
/* printf("Ecore_Evas Flush Post\n"); */
/* printf("\tBack Pixmap: %d\n", edata->pixmap.back); */
/* printf("\tFront Pixmap: %d\n", edata->pixmap.front); */
/* done drawing to the back buffer. flip it to the front so that
* any calls to "fetch pixmap" will return the front buffer already
* pre-rendered */
/* record the current front buffer */
prev = edata->pixmap.front;
/* flip them */
edata->pixmap.front = edata->pixmap.back;
/* reassign back buffer to be the old front one */
edata->pixmap.back = prev;
/* update evas drawable */
if (!strcmp(ee->driver, "software_x11"))
{
# ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
Evas_Engine_Info_Software_X11 *einfo;
einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas);
if (einfo)
{
einfo->info.drawable = edata->pixmap.back;
if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
{
ERR("evas_engine_info_set() init engine '%s' failed.",
ee->driver);
}
}
# endif
}
else if (!strcmp(ee->driver, "opengl_x11"))
{
# ifdef BUILD_ECORE_EVAS_OPENGL_X11
Evas_Engine_Info_GL_X11 *einfo;
einfo = (Evas_Engine_Info_GL_X11 *)evas_engine_info_get(ee->evas);
if (einfo)
{
einfo->info.drawable = edata->pixmap.back;
if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
{
ERR("evas_engine_info_set() init engine '%s' failed.",
ee->driver);
}
}
# endif
}
}
if (edata->netwm_sync_set)
{
ecore_x_sync_counter_2_set(edata->netwm_sync_counter,
edata->netwm_sync_val_hi,
edata->netwm_sync_val_lo);
edata->netwm_sync_set = 0;
}
if (edata->profile.done)
{
if (ee->prop.window)
{
ecore_x_e_window_profile_change_done_send
(edata->win_root, ee->prop.window, ee->prop.profile.name);
}
edata->profile.done = 0;
}
if ((ee->prop.wm_rot.supported) &&
(edata->wm_rot.done))
{
if (!ee->prop.wm_rot.manual_mode.set)
{
ecore_x_e_window_rotation_change_done_send
(edata->win_root, ee->prop.window, ee->rotation, ee->w, ee->h);
edata->wm_rot.done = 0;
}
}
}
#endif
#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
EAPI Ecore_Evas *
ecore_evas_software_x11_new_internal(const char *disp_name, Ecore_X_Window parent,
int x, int y, int w, int h)
{
Evas_Engine_Info_Software_X11 *einfo;
Ecore_Evas_Interface_X11 *iface;
Ecore_Evas_Interface_Software_X11 *siface;
Ecore_Evas_Engine_Data_X11 *edata;
Ecore_Evas *ee;
int argb = 0, rmethod;
static int redraw_debug = -1;
char *id = NULL;
rmethod = evas_render_method_lookup("software_x11");
if (!rmethod) return NULL;
if (!ecore_x_init(disp_name)) return NULL;
ee = calloc(1, sizeof(Ecore_Evas));
if (!ee) return NULL;
edata = calloc(1, sizeof(Ecore_Evas_Engine_Data_X11));
if (!edata)
{
free(ee);
return NULL;
}
ee->engine.data = edata;
iface = _ecore_evas_x_interface_x11_new();
siface = _ecore_evas_x_interface_software_x11_new();
ee->engine.ifaces = eina_list_append(ee->engine.ifaces, iface);
ee->engine.ifaces = eina_list_append(ee->engine.ifaces, siface);
ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
_ecore_evas_x_init();
ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_x_engine_func;
ee->driver = "software_x11";
if (disp_name) ee->name = strdup(disp_name);
if (w < 1) w = 1;
if (h < 1) h = 1;
ee->x = x;
ee->y = y;
ee->w = w;
ee->h = h;
ee->req.x = ee->x;
ee->req.y = ee->y;
ee->req.w = ee->w;
ee->req.h = ee->h;
ee->prop.max.w = 32767;
ee->prop.max.h = 32767;
ee->prop.layer = 4;
ee->prop.request_pos = EINA_FALSE;
ee->prop.sticky = 0;
ee->prop.withdrawn = EINA_TRUE;
edata->state.sticky = 0;
if (getenv("ECORE_EVAS_FORCE_SYNC_RENDER"))
ee->can_async_render = 0;
else
ee->can_async_render = 1;
/* init evas here */
if (!ecore_evas_evas_new(ee, w, h))
{
ERR("Can not create a Canvas.");
ecore_evas_free(ee);
return NULL;
}
evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_FLUSH_POST,
_ecore_evas_x_flush_post, ee);
if (ee->can_async_render)
evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_POST,
_ecore_evas_x_render_updates, ee);
evas_output_method_set(ee->evas, rmethod);
edata->win_root = parent;
edata->screen_num = 0;
if (parent != 0)
{
edata->screen_num = 1; /* FIXME: get real scren # */
/* FIXME: round trip in ecore_x_window_argb_get */
if (ecore_x_window_argb_get(parent))
{
ee->prop.window = ecore_x_window_argb_new(parent, x, y, w, h);
argb = 1;
}
else
ee->prop.window = ecore_x_window_new(parent, x, y, w, h);
}
else
ee->prop.window = ecore_x_window_new(parent, x, y, w, h);
ecore_x_vsync_animator_tick_source_set(ee->prop.window);
if ((id = getenv("DESKTOP_STARTUP_ID")))
{
ecore_x_netwm_startup_id_set(ee->prop.window, id);
/* NB: on linux this may simply empty the env as opposed to completely
* unset it to being empty - unsure as solartis libc crashes looking
* for the '=' char */
// putenv((char*)"DESKTOP_STARTUP_ID=");
}
einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas);
if (einfo)
{
Ecore_X_Screen *screen;
/* FIXME: this is inefficient as its 1 or more round trips */
screen = ecore_x_default_screen_get();
if (ecore_x_screen_count_get() > 1)
{
Ecore_X_Window *roots;
int num, i;
num = 0;
roots = ecore_x_window_root_list(&num);
if (roots)
{
Ecore_X_Window root;
root = ecore_x_window_root_get(parent);
for (i = 0; i < num; i++)
{
if (root == roots[i])
{
screen = ecore_x_screen_get(i);
break;
}
}
free(roots);
}
}
einfo->info.destination_alpha = argb;
if (redraw_debug < 0)
{
if (getenv("REDRAW_DEBUG"))
redraw_debug = atoi(getenv("REDRAW_DEBUG"));
else
redraw_debug = 0;
}
einfo->info.backend = EVAS_ENGINE_INFO_SOFTWARE_X11_BACKEND_XLIB;
einfo->info.connection = ecore_x_display_get();
einfo->info.screen = NULL;
einfo->info.drawable = ee->prop.window;
if (argb)
{
Ecore_X_Window_Attributes at;
ecore_x_window_attributes_get(ee->prop.window, &at);
einfo->info.visual = at.visual;
einfo->info.colormap = at.colormap;
einfo->info.depth = at.depth;
einfo->info.destination_alpha = 1;
}
else
{
einfo->info.visual =
ecore_x_default_visual_get(einfo->info.connection, screen);
einfo->info.colormap =
ecore_x_default_colormap_get(einfo->info.connection, screen);
einfo->info.depth =
ecore_x_default_depth_get(einfo->info.connection, screen);
einfo->info.destination_alpha = 0;
}
einfo->info.rotation = 0;
einfo->info.debug = redraw_debug;
if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
{
ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver);
ecore_evas_free(ee);
return NULL;
}
}
_ecore_evas_x_hints_update(ee);
_ecore_evas_x_group_leader_set(ee);
ecore_x_window_defaults_set(ee->prop.window);
_ecore_evas_x_protocols_set(ee);
_ecore_evas_x_window_profile_protocol_set(ee);
_ecore_evas_x_wm_rotation_protocol_set(ee);
_ecore_evas_x_aux_hints_supported_update(ee);
_ecore_evas_x_aux_hints_update(ee);
_ecore_evas_x_selection_window_init(ee);
ee->engine.func->fn_render = _ecore_evas_x_render;
ee->draw_block = EINA_TRUE;
if (!wm_exists) edata->configured = 1;
ecore_x_input_multi_select(ee->prop.window);
ecore_evas_done(ee, EINA_FALSE);
return ee;
}
EAPI Ecore_Evas *
ecore_evas_software_x11_pixmap_new_internal(const char *disp_name, Ecore_X_Window parent,
int x, int y, int w, int h)
{
Evas_Engine_Info_Software_X11 *einfo;
Ecore_Evas_Interface_X11 *iface;
Ecore_Evas_Interface_Software_X11 *siface;
Ecore_Evas_Engine_Data_X11 *edata;
Ecore_Evas *ee;
int argb = 0, rmethod;
static int redraw_debug = -1;
rmethod = evas_render_method_lookup("software_x11");
if (!rmethod) return NULL;
if (!ecore_x_init(disp_name)) return NULL;
ee = calloc(1, sizeof(Ecore_Evas));
if (!ee) return NULL;
edata = calloc(1, sizeof(Ecore_Evas_Engine_Data_X11));
if (!edata)
{
free(ee);
return NULL;
}
ee->engine.data = edata;
iface = _ecore_evas_x_interface_x11_new();
siface = _ecore_evas_x_interface_software_x11_new();
ee->engine.ifaces = eina_list_append(ee->engine.ifaces, iface);
ee->engine.ifaces = eina_list_append(ee->engine.ifaces, siface);
ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
_ecore_evas_x_init();
ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_x_engine_func;
ee->driver = "software_x11";
if (disp_name) ee->name = strdup(disp_name);
if (w < 1) w = 1;
if (h < 1) h = 1;
ee->x = x;
ee->y = y;
ee->w = w;
ee->h = h;
ee->req.x = ee->x;
ee->req.y = ee->y;
ee->req.w = ee->w;
ee->req.h = ee->h;
ee->prop.max.w = 32767;
ee->prop.max.h = 32767;
ee->prop.layer = 4;
ee->prop.request_pos = EINA_FALSE;
ee->prop.sticky = 0;
edata->state.sticky = 0;
if (getenv("ECORE_EVAS_FORCE_SYNC_RENDER"))
ee->can_async_render = 0;
else
ee->can_async_render = 1;
/* init evas here */
if (!ecore_evas_evas_new(ee, w, h))
{
ERR("Can not create Canvas.");
ecore_evas_free(ee);
return NULL;
}
evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_FLUSH_POST,
_ecore_evas_x_flush_post, ee);
evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_PRE,
_ecore_evas_x_render_pre, ee);
if (ee->can_async_render)
evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_POST,
_ecore_evas_x_render_updates, ee);
evas_output_method_set(ee->evas, rmethod);
edata->win_root = parent;
edata->screen_num = 0;
edata->direct_resize = 1;
if (parent != 0)
{
edata->screen_num = 1; /* FIXME: get real scren # */
/* FIXME: round trip in ecore_x_window_argb_get */
if (ecore_x_window_argb_get(parent))
argb = 1;
}
/* if ((id = getenv("DESKTOP_STARTUP_ID"))) */
/* { */
/* ecore_x_netwm_startup_id_set(ee->prop.window, id); */
/* NB: on linux this may simply empty the env as opposed to completely
* unset it to being empty - unsure as solartis libc crashes looking
* for the '=' char */
// putenv((char*)"DESKTOP_STARTUP_ID=");
/* } */
einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas);
if (einfo)
{
Ecore_X_Screen *screen;
/* FIXME: this is inefficient as its 1 or more round trips */
screen = ecore_x_default_screen_get();
if (ecore_x_screen_count_get() > 1)
{
Ecore_X_Window *roots;
int num, i;
num = 0;
roots = ecore_x_window_root_list(&num);
if (roots)
{
Ecore_X_Window root;
root = ecore_x_window_root_get(parent);
for (i = 0; i < num; i++)
{
if (root == roots[i])
{
screen = ecore_x_screen_get(i);
break;
}
}
free(roots);
}
}
einfo->info.destination_alpha = argb;
if (redraw_debug < 0)
{
if (getenv("REDRAW_DEBUG"))
redraw_debug = atoi(getenv("REDRAW_DEBUG"));
else
redraw_debug = 0;
}
einfo->info.backend = EVAS_ENGINE_INFO_SOFTWARE_X11_BACKEND_XLIB;
einfo->info.connection = ecore_x_display_get();
einfo->info.screen = NULL;
if ((argb) && (ee->prop.window))
{
Ecore_X_Window_Attributes at;
ecore_x_window_attributes_get(ee->prop.window, &at);
einfo->info.visual = at.visual;
einfo->info.colormap = at.colormap;
einfo->info.depth = at.depth;
einfo->info.destination_alpha = 1;
}
else
{
einfo->info.visual =
ecore_x_default_visual_get(einfo->info.connection, screen);
einfo->info.colormap =
ecore_x_default_colormap_get(einfo->info.connection, screen);
einfo->info.depth =
ecore_x_default_depth_get(einfo->info.connection, screen);
einfo->info.destination_alpha = 0;
}
einfo->info.rotation = 0;
einfo->info.debug = redraw_debug;
/* record pixmap size to save X roundtrips */
edata->pixmap.w = w;
edata->pixmap.h = h;
edata->pixmap.depth = einfo->info.depth;
edata->pixmap.visual = einfo->info.visual;
edata->pixmap.colormap = einfo->info.colormap;
/* create front and back pixmaps for double-buffer rendering */
edata->pixmap.front =
ecore_x_pixmap_new(parent, w, h, edata->pixmap.depth);
edata->pixmap.back =
ecore_x_pixmap_new(parent, w, h, edata->pixmap.depth);
einfo->info.drawable = edata->pixmap.back;
if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
{
ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver);
ecore_evas_free(ee);
return NULL;
}
}
/* FIXME: Allow of these set properties or do something with the
* ee->prop.window (x window), which we do not have in pixmap case */
/* _ecore_evas_x_hints_update(ee); */
/* _ecore_evas_x_group_leader_set(ee); */
/* ecore_x_window_defaults_set(ee->prop.window); */
/* _ecore_evas_x_protocols_set(ee); */
/* _ecore_evas_x_window_profile_protocol_set(ee); */
ee->engine.func->fn_render = _ecore_evas_x_render;
_ecore_evas_register(ee);
ee->draw_block = EINA_FALSE;
if (!wm_exists) edata->configured = 1;
/* ecore_x_input_multi_select(ee->prop.window); */
/* ecore_event_window_register(ee->prop.window, ee, ee->evas, */
/* (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, */
/* (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, */
/* (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, */
/* (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process); */
return ee;
}
static Ecore_X_Window
_ecore_evas_software_x11_window_get(const Ecore_Evas *ee)
{
if (!(!strcmp(ee->driver, "software_x11"))) return 0;
return (Ecore_X_Window) ecore_evas_window_get(ee);
}
static Ecore_X_Pixmap
_ecore_evas_software_x11_pixmap_get(const Ecore_Evas *ee)
{
if (!(!strcmp(ee->driver, "software_x11"))) return 0;
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
return (Ecore_X_Pixmap) edata->pixmap.front;
}
static void *
_ecore_evas_software_x11_pixmap_visual_get(const Ecore_Evas *ee)
{
if (!(!strcmp(ee->driver, "software_x11"))) return 0;
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
return edata->pixmap.visual;
}
static unsigned long
_ecore_evas_software_x11_pixmap_colormap_get(const Ecore_Evas *ee)
{
if (!(!strcmp(ee->driver, "software_x11"))) return 0;
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
return edata->pixmap.colormap;
}
static int
_ecore_evas_software_x11_pixmap_depth_get(const Ecore_Evas *ee)
{
if (!(!strcmp(ee->driver, "software_x11"))) return 0;
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
return edata->pixmap.depth;
}
static void
_ecore_evas_software_x11_direct_resize_set(Ecore_Evas *ee, Eina_Bool on)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
edata->direct_resize = on;
if (ee->prop.avoid_damage)
{
if (edata->direct_resize)
{
/* turn this off for now
ee->engine.x.using_bg_pixmap = 1;
ecore_x_window_pixmap_set(ee->prop.window, ee->engine.x.pmap);
*/
}
else
{
/* turn this off too- bg pixmap is controlled by avoid damage directly
ee->engine.x.using_bg_pixmap = 0;
ecore_x_window_pixmap_set(ee->prop.window, 0);
ecore_x_window_area_expose(ee->prop.window, 0, 0, ee->w, ee->h);
*/
}
}
}
static Eina_Bool
_ecore_evas_software_x11_direct_resize_get(const Ecore_Evas *ee)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
return edata->direct_resize;
}
static void
_ecore_evas_software_x11_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
Ecore_X_Window *winp;
winp = malloc(sizeof(Ecore_X_Window));
if (winp)
{
*winp = win;
edata->win_extra = eina_list_append(edata->win_extra, winp);
ecore_x_input_multi_select(win);
ecore_event_window_register(win, ee, ee->evas,
(Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process,
(Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process,
(Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process,
(Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process);
_ecore_event_window_direct_cb_set(win, _ecore_evas_input_direct_cb);
}
}
#endif
#ifdef BUILD_ECORE_EVAS_OPENGL_X11
EAPI Ecore_Evas *
ecore_evas_gl_x11_options_new_internal(const char *disp_name, Ecore_X_Window parent,
int x, int y, int w, int h, const int *opt)
{
Ecore_Evas *ee;
Ecore_Evas_Engine_Data_X11 *edata;
Ecore_Evas_Interface_X11 *iface;
Ecore_Evas_Interface_Gl_X11 *giface;
int rmethod;
char *id = NULL;
rmethod = evas_render_method_lookup("gl_x11");
if (!rmethod) return NULL;
if (!ecore_x_init(disp_name)) return NULL;
ee = calloc(1, sizeof(Ecore_Evas));
if (!ee) return NULL;
edata = calloc(1, sizeof(Ecore_Evas_Engine_Data_X11));
if (!edata)
{
free(ee);
return NULL;
}
iface = _ecore_evas_x_interface_x11_new();
giface = _ecore_evas_x_interface_gl_x11_new();
ee->engine.ifaces = eina_list_append(ee->engine.ifaces, iface);
ee->engine.ifaces = eina_list_append(ee->engine.ifaces, giface);
ee->engine.data = edata;
ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
_ecore_evas_x_init();
ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_x_engine_func;
ee->driver = "opengl_x11";
if (disp_name) ee->name = strdup(disp_name);
if (w < 1) w = 1;
if (h < 1) h = 1;
ee->x = x;
ee->y = y;
ee->w = w;
ee->h = h;
ee->req.x = ee->x;
ee->req.y = ee->y;
ee->req.w = ee->w;
ee->req.h = ee->h;
ee->prop.max.w = 32767;
ee->prop.max.h = 32767;
ee->prop.layer = 4;
ee->prop.request_pos = EINA_FALSE;
ee->prop.sticky = 0;
ee->prop.withdrawn = EINA_TRUE;
edata->state.sticky = 0;
/* init evas here */
if (!ecore_evas_evas_new(ee, w, h))
{
ERR("Can not create Canvas.");
ecore_evas_free(ee);
return NULL;
}
evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_FLUSH_POST, _ecore_evas_x_flush_post, ee);
evas_output_method_set(ee->evas, rmethod);
if (parent == 0) parent = ecore_x_window_root_first_get();
edata->win_root = parent;
if (edata->win_root != 0)
{
edata->screen_num = 1; /* FIXME: get real scren # */
/* FIXME: round trip in ecore_x_window_argb_get */
if (ecore_x_window_argb_get(edata->win_root))
{
ee->prop.window = _ecore_evas_x_gl_window_new
(ee, edata->win_root, x, y, w, h, 0, 1, opt);
}
else
ee->prop.window = _ecore_evas_x_gl_window_new
(ee, edata->win_root, x, y, w, h, 0, 0, opt);
}
else
ee->prop.window = _ecore_evas_x_gl_window_new
(ee, edata->win_root, x, y, w, h, 0, 0, opt);
if (!ee->prop.window)
{
ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver);
ecore_evas_free(ee);
return NULL;
}
if ((id = getenv("DESKTOP_STARTUP_ID")))
{
ecore_x_netwm_startup_id_set(ee->prop.window, id);
/* NB: on linux this may simply empty the env as opposed to completely
* unset it to being empty - unsure as solartis libc crashes looking
* for the '=' char */
// putenv((char*)"DESKTOP_STARTUP_ID=");
}
_ecore_evas_x_hints_update(ee);
_ecore_evas_x_group_leader_set(ee);
ecore_x_window_defaults_set(ee->prop.window);
_ecore_evas_x_protocols_set(ee);
_ecore_evas_x_window_profile_protocol_set(ee);
_ecore_evas_x_wm_rotation_protocol_set(ee);
_ecore_evas_x_aux_hints_supported_update(ee);
_ecore_evas_x_aux_hints_update(ee);
_ecore_evas_x_selection_window_init(ee);
ee->draw_block = 1;
if (!wm_exists) edata->configured = 1;
ee->engine.func->fn_render = _ecore_evas_x_render;
ecore_x_input_multi_select(ee->prop.window);
ecore_evas_done(ee, EINA_FALSE);
return ee;
}
EAPI Ecore_Evas *
ecore_evas_gl_x11_new_internal(const char *disp_name, Ecore_X_Window parent,
int x, int y, int w, int h)
{
return ecore_evas_gl_x11_options_new_internal(disp_name, parent, x, y, w, h, NULL);
}
EAPI Ecore_Evas *
ecore_evas_gl_x11_pixmap_new_internal(const char *disp_name, Ecore_X_Window parent,
int x, int y, int w, int h)
{
Ecore_Evas *ee;
Ecore_Evas_Engine_Data_X11 *edata;
Ecore_Evas_Interface_X11 *iface;
Ecore_Evas_Interface_Gl_X11 *giface;
Evas_Engine_Info_GL_X11 *einfo;
int rmethod, argb = 0;
static int redraw_debug = -1;
rmethod = evas_render_method_lookup("gl_x11");
if (!rmethod) return NULL;
if (!ecore_x_init(disp_name)) return NULL;
ee = calloc(1, sizeof(Ecore_Evas));
if (!ee) return NULL;
edata = calloc(1, sizeof(Ecore_Evas_Engine_Data_X11));
if (!edata)
{
free(ee);
return NULL;
}
iface = _ecore_evas_x_interface_x11_new();
giface = _ecore_evas_x_interface_gl_x11_new();
ee->engine.ifaces = eina_list_append(ee->engine.ifaces, iface);
ee->engine.ifaces = eina_list_append(ee->engine.ifaces, giface);
ee->engine.data = edata;
ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS);
_ecore_evas_x_init();
ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_x_engine_func;
ee->driver = "opengl_x11";
if (disp_name) ee->name = strdup(disp_name);
if (w < 1) w = 1;
if (h < 1) h = 1;
ee->x = x;
ee->y = y;
ee->w = w;
ee->h = h;
ee->req.x = ee->x;
ee->req.y = ee->y;
ee->req.w = ee->w;
ee->req.h = ee->h;
ee->prop.max.w = 32767;
ee->prop.max.h = 32767;
ee->prop.layer = 4;
ee->prop.request_pos = EINA_FALSE;
ee->prop.sticky = 0;
edata->state.sticky = 0;
/* init evas here */
if (!ecore_evas_evas_new(ee, w, h))
{
ERR("Can not create Canvas.");
ecore_evas_free(ee);
return NULL;
}
evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_FLUSH_POST,
_ecore_evas_x_flush_post, ee);
evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_PRE,
_ecore_evas_x_render_pre, ee);
evas_output_method_set(ee->evas, rmethod);
if (ee->can_async_render)
evas_event_callback_add(ee->evas, EVAS_CALLBACK_RENDER_POST,
_ecore_evas_x_render_updates, ee);
if (parent == 0) parent = ecore_x_window_root_first_get();
edata->win_root = parent;
if (parent != 0)
{
edata->screen_num = 1; /* FIXME: get real scren # */
/* FIXME: round trip in ecore_x_window_argb_get */
if (ecore_x_window_argb_get(parent))
argb = 1;
}
edata->direct_resize = 1;
einfo = (Evas_Engine_Info_GL_X11 *)evas_engine_info_get(ee->evas);
if (einfo)
{
int screen = 0;
/* FIXME: this is inefficient as its 1 or more round trips */
screen = ecore_x_screen_index_get(ecore_x_default_screen_get());
if (ecore_x_screen_count_get() > 1)
{
Ecore_X_Window *roots;
int num, i;
num = 0;
roots = ecore_x_window_root_list(&num);
if (roots)
{
Ecore_X_Window root;
root = ecore_x_window_root_get(parent);
for (i = 0; i < num; i++)
{
if (root == roots[i])
{
screen = i;
break;
}
}
free(roots);
}
}
einfo->info.display = ecore_x_display_get();
einfo->info.screen = screen;
einfo->info.destination_alpha = argb;
einfo->info.visual = einfo->func.best_visual_get(einfo);
einfo->info.colormap = einfo->func.best_colormap_get(einfo);
einfo->info.depth = einfo->func.best_depth_get(einfo);
if (redraw_debug < 0)
{
if (getenv("REDRAW_DEBUG"))
redraw_debug = atoi(getenv("REDRAW_DEBUG"));
else
redraw_debug = 0;
}
einfo->info.rotation = 0;
/* record pixmap size to save X roundtrips */
edata->pixmap.w = w;
edata->pixmap.h = h;
edata->pixmap.depth = einfo->info.depth;
edata->pixmap.visual = einfo->info.visual;
edata->pixmap.colormap = einfo->info.colormap;
/* create front and back pixmaps for double-buffer rendering */
edata->pixmap.front =
ecore_x_pixmap_new(parent, w, h, edata->pixmap.depth);
edata->pixmap.back =
ecore_x_pixmap_new(parent, w, h, edata->pixmap.depth);
einfo->info.drawable = edata->pixmap.back;
if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
{
ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver);
ecore_evas_free(ee);
return NULL;
}
}
/* _ecore_evas_x_hints_update(ee); */
/* _ecore_evas_x_group_leader_set(ee); */
/* ecore_x_window_defaults_set(ee->prop.window); */
/* _ecore_evas_x_protocols_set(ee); */
/* _ecore_evas_x_window_profile_protocol_set(ee); */
ee->engine.func->fn_render = _ecore_evas_x_render;
_ecore_evas_register(ee);
ee->draw_block = EINA_TRUE;
if (!wm_exists) edata->configured = 1;
/* ecore_x_input_multi_select(ee->prop.window); */
/* ecore_event_window_register(ee->prop.window, ee, ee->evas, */
/* (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, */
/* (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, */
/* (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, */
/* (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process); */
return ee;
}
static Ecore_X_Window
_ecore_evas_gl_x11_window_get(const Ecore_Evas *ee)
{
if (!(!strcmp(ee->driver, "opengl_x11"))) return 0;
return (Ecore_X_Window) ecore_evas_window_get(ee);
}
static Ecore_X_Pixmap
_ecore_evas_gl_x11_pixmap_get(const Ecore_Evas *ee)
{
if (!(!strcmp(ee->driver, "opengl_x11"))) return 0;
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
return (Ecore_X_Pixmap) edata->pixmap.front;
}
static void *
_ecore_evas_gl_x11_pixmap_visual_get(const Ecore_Evas *ee)
{
if (!(!strcmp(ee->driver, "opengl_x11"))) return 0;
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
return edata->pixmap.visual;
}
static unsigned long
_ecore_evas_gl_x11_pixmap_colormap_get(const Ecore_Evas *ee)
{
if (!(!strcmp(ee->driver, "opengl_x11"))) return 0;
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
return edata->pixmap.colormap;
}
static int
_ecore_evas_gl_x11_pixmap_depth_get(const Ecore_Evas *ee)
{
if (!(!strcmp(ee->driver, "opengl_x11"))) return 0;
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
return edata->pixmap.depth;
}
static void
_ecore_evas_gl_x11_direct_resize_set(Ecore_Evas *ee, Eina_Bool on)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
edata->direct_resize = on;
}
static Eina_Bool
_ecore_evas_gl_x11_direct_resize_get(const Ecore_Evas *ee)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
return edata->direct_resize;
}
static void
_ecore_evas_gl_x11_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win)
{
ecore_evas_software_x11_extra_event_window_add(ee, win);
}
static void
_ecore_evas_gl_x11_pre_post_swap_callback_set(const Ecore_Evas *ee, void *data, void (*pre_cb) (void *data, Evas *e), void (*post_cb) (void *data, Evas *e))
{
Evas_Engine_Info_GL_X11 *einfo;
if (!(!strcmp(ee->driver, "opengl_x11"))) return;
einfo = (Evas_Engine_Info_GL_X11 *)evas_engine_info_get(ee->evas);
if (einfo)
{
einfo->callback.pre_swap = pre_cb;
einfo->callback.post_swap = post_cb;
einfo->callback.data = data;
if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo))
{
ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver);
}
}
}
#endif /* ! BUILD_ECORE_EVAS_OPENGL_X11 */
static void
_ecore_evas_x11_leader_set(Ecore_Evas *ee, Ecore_X_Window win)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
_ecore_evas_x_group_leader_unset(ee);
edata->leader = win;
_ecore_evas_x_group_leader_update(ee);
}
static Ecore_X_Window
_ecore_evas_x11_leader_get(Ecore_Evas *ee)
{
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
return edata->leader;
}
static void
_ecore_evas_x11_leader_default_set(Ecore_Evas *ee)
{
_ecore_evas_x_group_leader_unset(ee);
_ecore_evas_x_group_leader_set(ee);
}
static Eina_Bool
_ecore_evas_x11_convert_rectangle_with_angle(Ecore_Evas *ee, Ecore_X_Rectangle *dst_rect, Ecore_X_Rectangle *src_rect)
{
if ((!src_rect) || (!dst_rect)) return 0;
if (ee->rotation == 0)
{
dst_rect->x = src_rect->x;
dst_rect->y = src_rect->y;
dst_rect->width = src_rect->width;
dst_rect->height = src_rect->height;
}
else if (ee->rotation == 90)
{
dst_rect->x = src_rect->y;
dst_rect->y = ee->req.h - src_rect->x - src_rect->width;
dst_rect->width = src_rect->height;
dst_rect->height = src_rect->width;
}
else if (ee->rotation == 180)
{
dst_rect->x = ee->req.w - src_rect->x - src_rect->width;
dst_rect->y = ee->req.h - src_rect->y - src_rect->height;
dst_rect->width = src_rect->width;
dst_rect->height = src_rect->height;
}
else if (ee->rotation == 270)
{
dst_rect->x = ee->req.w - src_rect->y - src_rect->height;
dst_rect->y = src_rect->x;
dst_rect->width = src_rect->height;
dst_rect->height = src_rect->width;
}
else
{
return 0;
}
return 1;
}
static void
_ecore_evas_x11_shape_input_rectangle_set(Ecore_Evas *ee, int x, int y, int w, int h)
{
Eina_Bool ret;
Ecore_X_Rectangle src_rect;
Ecore_X_Rectangle dst_rect;
Ecore_Evas_Engine_Data_X11 *edata;
if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
{
ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
"ecore_evas_x11_shape_input_rectangle_set");
return;
}
edata = ee->engine.data;
src_rect.x = x;
src_rect.y = y;
src_rect.width = w;
src_rect.height = h;
dst_rect.x = 0;
dst_rect.y = 0;
dst_rect.width = 0;
dst_rect.height = 0;
ret = _ecore_evas_x11_convert_rectangle_with_angle(ee, &dst_rect, &src_rect);
if (!edata->win_shaped_input)
edata->win_shaped_input = ecore_x_window_override_new(edata->win_root,
0, 0, 1, 1);
if (ret)
ecore_x_window_shape_input_rectangle_set(edata->win_shaped_input,
dst_rect.x, dst_rect.y,
dst_rect.width, dst_rect.height);
}
static void
_ecore_evas_x11_shape_input_rectangle_add(Ecore_Evas *ee, int x, int y, int w, int h)
{
Eina_Bool ret;
Ecore_X_Rectangle src_rect;
Ecore_X_Rectangle dst_rect;
Ecore_Evas_Engine_Data_X11 *edata;
if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
{
ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
"ecore_evas_x11_shape_input_rectangle_add");
return;
}
edata = ee->engine.data;
src_rect.x = x;
src_rect.y = y;
src_rect.width = w;
src_rect.height = h;
dst_rect.x = 0;
dst_rect.y = 0;
dst_rect.width = 0;
dst_rect.height = 0;
ret = _ecore_evas_x11_convert_rectangle_with_angle(ee, &dst_rect, &src_rect);
if (!edata->win_shaped_input)
edata->win_shaped_input = ecore_x_window_override_new(edata->win_root,
0, 0, 1, 1);
if (ret)
ecore_x_window_shape_input_rectangle_add(edata->win_shaped_input,
dst_rect.x, dst_rect.y,
dst_rect.width, dst_rect.height);
}
static void
_ecore_evas_x11_shape_input_rectangle_subtract(Ecore_Evas *ee, int x, int y, int w, int h)
{
Eina_Bool ret;
Ecore_X_Rectangle src_rect;
Ecore_X_Rectangle dst_rect;
Ecore_Evas_Engine_Data_X11 *edata;
if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
{
ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
"ecore_evas_x11_shape_input_rectangle_subtract");
return;
}
edata = ee->engine.data;
src_rect.x = x;
src_rect.y = y;
src_rect.width = w;
src_rect.height = h;
dst_rect.x = 0;
dst_rect.y = 0;
dst_rect.width = 0;
dst_rect.height = 0;
ret = _ecore_evas_x11_convert_rectangle_with_angle(ee, &dst_rect, &src_rect);
if (!edata->win_shaped_input)
edata->win_shaped_input = ecore_x_window_override_new(edata->win_root,
0, 0, 1, 1);
if (ret)
ecore_x_window_shape_input_rectangle_subtract(edata->win_shaped_input,
dst_rect.x, dst_rect.y,
dst_rect.width, dst_rect.height);
}
static void
_ecore_evas_x11_shape_input_empty(Ecore_Evas *ee)
{
Ecore_Evas_Engine_Data_X11 *edata;
if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
{
ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
"ecore_evas_x11_shape_input_empty");
return;
}
edata = ee->engine.data;
if (!edata->win_shaped_input)
edata->win_shaped_input = ecore_x_window_override_new(edata->win_root, 0, 0, 1, 1);
ecore_x_window_shape_input_rectangle_set(edata->win_shaped_input, 0, 0, 0, 0);
}
static void
_ecore_evas_x11_shape_input_reset(Ecore_Evas *ee)
{
Ecore_Evas_Engine_Data_X11 *edata;
if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
{
ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
"ecore_evas_x11_shape_input_reset");
return;
}
edata = ee->engine.data;
if (!edata->win_shaped_input)
edata->win_shaped_input = ecore_x_window_override_new(edata->win_root, 0, 0, 1, 1);
ecore_x_window_shape_input_rectangle_set(edata->win_shaped_input, 0, 0, 65535, 65535);
}
static void
_ecore_evas_x11_shape_input_apply(Ecore_Evas *ee)
{
Ecore_Evas_Engine_Data_X11 *edata;
if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS))
{
ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS,
"ecore_evas_x11_shape_input_apply");
return;
}
edata = ee->engine.data;
if (!edata->win_shaped_input) return;
ecore_x_window_shape_input_window_set(ee->prop.window, edata->win_shaped_input);
}
static Ecore_Evas_Interface_X11 *
_ecore_evas_x_interface_x11_new(void)
{
Ecore_Evas_Interface_X11 *iface;
iface = calloc(1, sizeof(Ecore_Evas_Interface_X11));
if (!iface) return NULL;
iface->base.name = interface_x11_name;
iface->base.version = interface_x11_version;
iface->leader_set = _ecore_evas_x11_leader_set;
iface->leader_get = _ecore_evas_x11_leader_get;
iface->leader_default_set = _ecore_evas_x11_leader_default_set;
iface->shape_input_rectangle_set = _ecore_evas_x11_shape_input_rectangle_set;
iface->shape_input_rectangle_add = _ecore_evas_x11_shape_input_rectangle_add;
iface->shape_input_rectangle_subtract = _ecore_evas_x11_shape_input_rectangle_subtract;
iface->shape_input_empty = _ecore_evas_x11_shape_input_empty;
iface->shape_input_reset = _ecore_evas_x11_shape_input_reset;
iface->shape_input_apply = _ecore_evas_x11_shape_input_apply;
return iface;
}
#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11
static Ecore_Evas_Interface_Software_X11 *
_ecore_evas_x_interface_software_x11_new(void)
{
Ecore_Evas_Interface_Software_X11 *iface;
iface = calloc(1, sizeof(Ecore_Evas_Interface_Software_X11));
if (!iface) return NULL;
iface->base.name = interface_software_x11_name;
iface->base.version = interface_software_x11_version;
iface->window_get = _ecore_evas_software_x11_window_get;
iface->pixmap_get = _ecore_evas_software_x11_pixmap_get;
iface->resize_set = _ecore_evas_software_x11_direct_resize_set;
iface->resize_get = _ecore_evas_software_x11_direct_resize_get;
iface->extra_event_window_add = _ecore_evas_software_x11_extra_event_window_add;
iface->pixmap_visual_get = _ecore_evas_software_x11_pixmap_visual_get;
iface->pixmap_colormap_get = _ecore_evas_software_x11_pixmap_colormap_get;
iface->pixmap_depth_get = _ecore_evas_software_x11_pixmap_depth_get;
return iface;
}
#endif
#ifdef BUILD_ECORE_EVAS_OPENGL_X11
static Ecore_Evas_Interface_Gl_X11 *
_ecore_evas_x_interface_gl_x11_new(void)
{
Ecore_Evas_Interface_Gl_X11 *iface;
iface = calloc(1, sizeof(Ecore_Evas_Interface_Gl_X11));
if (!iface) return NULL;
iface->base.name = interface_gl_x11_name;
iface->base.version = interface_gl_x11_version;
iface->window_get = _ecore_evas_gl_x11_window_get;
iface->pixmap_get = _ecore_evas_gl_x11_pixmap_get;
iface->resize_set = _ecore_evas_gl_x11_direct_resize_set;
iface->resize_get = _ecore_evas_gl_x11_direct_resize_get;
iface->extra_event_window_add = _ecore_evas_gl_x11_extra_event_window_add;
iface->pre_post_swap_callback_set = _ecore_evas_gl_x11_pre_post_swap_callback_set;
iface->pixmap_visual_get = _ecore_evas_gl_x11_pixmap_visual_get;
iface->pixmap_colormap_get = _ecore_evas_gl_x11_pixmap_colormap_get;
iface->pixmap_depth_get = _ecore_evas_gl_x11_pixmap_depth_get;
return iface;
}
#endif