5984 lines
194 KiB
C
5984 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->prop.maximized == on) return;
|
|
ee->prop.maximized = 1;
|
|
edata->state.maximized_h = 1;
|
|
edata->state.maximized_v = 1;
|
|
// ee->prop.maximized = on;
|
|
if (ee->should_be_visible)
|
|
{
|
|
ecore_x_netwm_state_request_send(ee->prop.window, edata->win_root,
|
|
ECORE_X_WINDOW_STATE_MAXIMIZED_VERT, -1, on);
|
|
ecore_x_netwm_state_request_send(ee->prop.window, edata->win_root,
|
|
ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ, -1, on);
|
|
}
|
|
else
|
|
_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_deliveriy_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_deliveriy_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_deliveriy_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_deliveriy_content(strlen(file), file, mime_type);
|
|
eina_content_free(tmp_container);
|
|
}
|
|
else
|
|
{
|
|
Ecore_X_Selection_Data *x11_data = ev->data;
|
|
result = _create_deliveriy_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
|
|
|