#ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include "ecore_private.h" #include #include #include #include #include #ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 # include #endif #ifdef BUILD_ECORE_EVAS_OPENGL_X11 # include #endif #include #include "ecore_evas_private.h" #include "ecore_evas_x11.h" #ifdef _WIN32 # ifndef EFL_MODULE_STATIC # define EMODAPI __declspec(dllexport) # else # define EMODAPI # endif #else # ifdef __GNUC__ # if __GNUC__ >= 4 # define EMODAPI __attribute__ ((visibility("default"))) # endif # endif #endif /* ! _WIN32 */ #ifndef EMODAPI # define EMODAPI #endif #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, EVAS_DEVICE_CLASS_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 */ } EMODAPI 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, EVAS_DEVICE_CLASS_MOUSE); pointer = evas_device_parent_get(pointer); cursor = eina_hash_find(ee->prop.cursors, &pointer); EINA_SAFETY_ON_NULL_RETURN(cursor); rot_dif = ee->rotation - rotation; if (rot_dif < 0) rot_dif = -rot_dif; evas_output_framespace_get(ee->evas, NULL, NULL, &fw, &fh); if (rot_dif != 180) { int minw, minh, maxw, maxh, basew, baseh, stepw, steph; if (!evas_engine_info_set(ee->evas, einfo)) { ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); } if (!resize) { edata->configure_coming = 1; if (!ee->prop.fullscreen) { ecore_x_window_resize(ee->prop.window, ee->req.h + fw, ee->req.w + fh); ee->expecting_resize.w = ee->h; ee->expecting_resize.h = ee->w; evas_output_size_set(ee->evas, ee->req.h + fw, ee->req.w + fh); evas_output_viewport_set(ee->evas, 0, 0, ee->req.h + fw, ee->req.w + fh); } else { int w, h; ecore_x_window_size_get(ee->prop.window, &w, &h); ecore_x_window_resize(ee->prop.window, h, w); if (PORTRAIT_CHECK(rotation)) { evas_output_size_set(ee->evas, ee->req.w + fw, ee->req.h + fh); evas_output_viewport_set(ee->evas, 0, 0, ee->req.w + fw, ee->req.h + fh); } else { evas_output_size_set(ee->evas, ee->req.h + fw, ee->req.w + fh); evas_output_viewport_set(ee->evas, 0, 0, ee->req.h + fw, ee->req.w + fh); } if (ee->func.fn_resize) ee->func.fn_resize(ee); } if (PORTRAIT_CHECK(rotation)) evas_damage_rectangle_add(ee->evas, 0, 0, ee->req.w + fw, ee->req.h + fh); else evas_damage_rectangle_add(ee->evas, 0, 0, ee->req.h + fw, ee->req.w + fh); } else { /* int w, h; */ /* ecore_x_window_size_get(ee->prop.window, &w, &h); */ if (PORTRAIT_CHECK(rotation)) { evas_output_size_set(ee->evas, ee->w + fw, ee->h + fh); evas_output_viewport_set(ee->evas, 0, 0, ee->w + fw, ee->h + fh); } else { evas_output_size_set(ee->evas, ee->h + fw, ee->w + fh); evas_output_viewport_set(ee->evas, 0, 0, ee->h + fw, ee->w + fh); } if (ee->func.fn_resize) ee->func.fn_resize(ee); if (PORTRAIT_CHECK(rotation)) evas_damage_rectangle_add(ee->evas, 0, 0, ee->w + fw, ee->h + fh); else evas_damage_rectangle_add(ee->evas, 0, 0, ee->h + fw, ee->w + fh); } ecore_evas_size_min_get(ee, &minw, &minh); ecore_evas_size_max_get(ee, &maxw, &maxh); ecore_evas_size_base_get(ee, &basew, &baseh); ecore_evas_size_step_get(ee, &stepw, &steph); ee->rotation = rotation; ecore_evas_size_min_set(ee, minh, minw); ecore_evas_size_max_set(ee, maxh, maxw); ecore_evas_size_base_set(ee, baseh, basew); ecore_evas_size_step_set(ee, steph, stepw); _ecore_evas_mouse_move_process(ee, cursor->pos_x, cursor->pos_y, ecore_x_current_time_get()); } else { if (!evas_engine_info_set(ee->evas, einfo)) { ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); } ee->rotation = rotation; _ecore_evas_mouse_move_process(ee, cursor->pos_x, cursor->pos_y, ecore_x_current_time_get()); if (ee->func.fn_resize) ee->func.fn_resize(ee); if (ECORE_EVAS_PORTRAIT(ee)) evas_damage_rectangle_add(ee->evas, 0, 0, ee->w + fw, ee->h + fh); else evas_damage_rectangle_add(ee->evas, 0, 0, ee->h + fw, ee->w + fh); } } static Eina_Bool _ecore_evas_x_wm_rotation_check(Ecore_Evas *ee) { Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; if (ee->prop.wm_rot.supported) { if (ee->prop.wm_rot.app_set) { if (edata->wm_rot.request) { if (ee->prop.wm_rot.win_resize) { if (!((ee->w == ee->prop.wm_rot.w) && (ee->h == ee->prop.wm_rot.h))) { return EINA_FALSE; } else edata->wm_rot.configure_coming = 0; } } } } return EINA_TRUE; } static void _rotation_do(Ecore_Evas *ee, int rotation, int resize) { #ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 if (ee->prop.wm_rot.supported) if (!_ecore_evas_x_wm_rotation_check(ee)) return; Evas_Engine_Info_Software_X11 *einfo; Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas); if (!einfo) return; einfo->info.rotation = rotation; _ecore_evas_x_rotation_set_internal(ee, rotation, resize, (Evas_Engine_Info *)einfo); if (ee->prop.wm_rot.supported) { if (ee->prop.wm_rot.app_set) { if (edata->wm_rot.request) { if (ee->func.fn_state_change) ee->func.fn_state_change(ee); edata->wm_rot.request = 0; edata->wm_rot.done = 1; } } } int angles[2] = { rotation, rotation }; ecore_x_window_prop_property_set(ee->prop.window, ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE, ECORE_X_ATOM_CARDINAL, 32, &angles, 2); #endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 */ } static void _ecore_evas_x_rotation_set(Ecore_Evas *ee, int rotation, int resize) { Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; if (ee->rotation == rotation) { if (ee->prop.wm_rot.supported) { if (edata->wm_rot.request) { if (ee->prop.wm_rot.manual_mode.set) { ee->prop.wm_rot.manual_mode.wait_for_done = EINA_FALSE; if (ee->prop.wm_rot.manual_mode.timer) ecore_timer_del(ee->prop.wm_rot.manual_mode.timer); ee->prop.wm_rot.manual_mode.timer = NULL; } /* send rotation done message to wm, even if window is already rotated. * that's why wm must be wait for comming rotation done message * after sending rotation request. */ ecore_x_e_window_rotation_change_done_send (edata->win_root, ee->prop.window, ee->rotation, ee->w, ee->h); edata->wm_rot.request = 0; } } return; } if (ee->prop.wm_rot.supported) if (!_ecore_evas_x_wm_rotation_check(ee)) return; if (!strcmp(ee->driver, "opengl_x11")) { #ifdef BUILD_ECORE_EVAS_OPENGL_X11 Evas_Engine_Info_GL_X11 *einfo; einfo = (Evas_Engine_Info_GL_X11 *)evas_engine_info_get(ee->evas); if (!einfo) return; einfo->info.rotation = rotation; _ecore_evas_x_rotation_set_internal(ee, rotation, resize, (Evas_Engine_Info *)einfo); if (ee->prop.wm_rot.supported) { if (ee->prop.wm_rot.app_set) { if (edata->wm_rot.request) { if (ee->func.fn_state_change) ee->func.fn_state_change(ee); edata->wm_rot.request = 0; edata->wm_rot.done = 1; } } } int angles[2] = { rotation, rotation }; ecore_x_window_prop_property_set(ee->prop.window, ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE, ECORE_X_ATOM_CARDINAL, 32, &angles, 2); #endif /* BUILD_ECORE_EVAS_OPENGL_X11 */ } else if (!strcmp(ee->driver, "software_x11")) { if (ee->in_async_render) { ee->delayed.rotation = rotation; ee->delayed.rotation_resize = resize; ee->delayed.rotation_changed = EINA_TRUE; return; } _rotation_do(ee, rotation, resize); return; } } static void _shaped_do(Ecore_Evas *ee, int shaped) { #ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; Evas_Engine_Info_Software_X11 *einfo; if (ee->shaped == shaped) return; einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas); ee->shaped = shaped; if (einfo) { if (ee->shaped) { unsigned int foreground; Ecore_X_GC gc; if (!edata->mask) edata->mask = ecore_x_pixmap_new(ee->prop.window, ee->w, ee->h, 1); foreground = 0; gc = ecore_x_gc_new(edata->mask, ECORE_X_GC_VALUE_MASK_FOREGROUND, &foreground); ecore_x_drawable_rectangle_fill(edata->mask, gc, 0, 0, ee->w, ee->h); ecore_x_gc_free(gc); einfo->info.mask = edata->mask; if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) { ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); } evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); ecore_x_window_shape_input_mask_set(ee->prop.window, 0); } else { if (edata->mask) ecore_x_pixmap_free(edata->mask); edata->mask = 0; einfo->info.mask = 0; if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) { ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); } ecore_x_window_shape_mask_set(ee->prop.window, 0); ecore_x_window_shape_input_mask_set(ee->prop.window, 0); } } #endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 */ } static void _ecore_evas_x_shaped_set(Ecore_Evas *ee, int shaped) { if (!strcmp(ee->driver, "opengl_x11")) return; if (!strcmp(ee->driver, "software_x11")) { if (ee->in_async_render) { ee->delayed.shaped = shaped; ee->delayed.shaped_changed = EINA_TRUE; return; } _shaped_do(ee, shaped); } } static void _alpha_do(Ecore_Evas *ee, int alpha) { char *id = NULL; #ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 Ecore_X_Window_Attributes att; Evas_Engine_Info_Software_X11 *einfo; Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; if (ee->alpha == alpha) return; einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas); if (!einfo) return; if (!ecore_x_composite_query()) return; ee->shaped = 0; ee->alpha = alpha; ecore_x_window_free(ee->prop.window); ecore_event_window_unregister(ee->prop.window); if (ee->alpha) { if (ee->prop.override) ee->prop.window = ecore_x_window_override_argb_new(edata->win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); else ee->prop.window = ecore_x_window_argb_new(edata->win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); // if (!edata->mask) // edata->mask = ecore_x_pixmap_new(ee->prop.window, ee->req.w, ee->req.h, 1); } else { if (ee->prop.override) ee->prop.window = ecore_x_window_override_new(edata->win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); else ee->prop.window = ecore_x_window_new(edata->win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); if (edata->mask) ecore_x_pixmap_free(edata->mask); edata->mask = 0; ecore_x_window_shape_input_mask_set(ee->prop.window, 0); ecore_x_vsync_animator_tick_source_set(ee->prop.window); } einfo->info.destination_alpha = alpha; ecore_x_window_attributes_get(ee->prop.window, &att); einfo->info.visual = att.visual; einfo->info.colormap = att.colormap; einfo->info.depth = att.depth; // if (edata->mask) ecore_x_pixmap_free(edata->mask); // edata->mask = 0; einfo->info.mask = edata->mask; einfo->info.drawable = ee->prop.window; if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) { ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); } evas_damage_rectangle_add(ee->evas, 0, 0, ee->req.w, ee->req.h); ecore_x_window_shape_mask_set(ee->prop.window, 0); ecore_x_input_multi_select(ee->prop.window); ecore_event_window_register(ee->prop.window, ee, ee->evas, (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process); _ecore_event_window_direct_cb_set(ee->prop.window, _ecore_evas_input_direct_cb); if (ee->prop.borderless) ecore_x_mwm_borderless_set(ee->prop.window, ee->prop.borderless); if (ee->visible || ee->should_be_visible) ecore_x_window_show(ee->prop.window); if (ecore_evas_focus_device_get(ee, NULL)) ecore_x_window_focus(ee->prop.window); if (ee->prop.title) { ecore_x_icccm_title_set(ee->prop.window, ee->prop.title); ecore_x_netwm_name_set(ee->prop.window, ee->prop.title); } if (ee->prop.name) ecore_x_icccm_name_class_set(ee->prop.window, ee->prop.name, ee->prop.clas); _ecore_evas_x_hints_update(ee); _ecore_evas_x_group_leader_update(ee); ecore_x_window_defaults_set(ee->prop.window); _ecore_evas_x_protocols_set(ee); _ecore_evas_x_window_profile_protocol_set(ee); _ecore_evas_x_wm_rotation_protocol_set(ee); _ecore_evas_x_aux_hints_supported_update(ee); _ecore_evas_x_aux_hints_update(ee); _ecore_evas_x_size_pos_hints_update(ee); _ecore_evas_x_selection_window_init(ee); #endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 */ if ((id = getenv("DESKTOP_STARTUP_ID"))) { ecore_x_netwm_startup_id_set(ee->prop.window, id); /* NB: on linux this may simply empty the env as opposed to completely * unset it to being empty - unsure as solartis libc crashes looking * for the '=' char */ // putenv((char*)"DESKTOP_STARTUP_ID="); } } /* FIXME, round trip */ static void _ecore_evas_x_alpha_set(Ecore_Evas *ee, int alpha) { char *id = NULL; if (!strcmp(ee->driver, "software_x11")) { if (ee->in_async_render) { if (ee->visible) { ee->delayed.alpha = alpha; ee->delayed.alpha_changed = EINA_TRUE; return; } evas_sync(ee->evas); } _alpha_do(ee, alpha); } else if (!strcmp(ee->driver, "opengl_x11")) { #ifdef BUILD_ECORE_EVAS_OPENGL_X11 Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; Ecore_X_Window_Attributes att; if (ee->alpha == alpha) return; Evas_Engine_Info_GL_X11 *einfo; Ecore_Window prev_win; einfo = (Evas_Engine_Info_GL_X11 *)evas_engine_info_get(ee->evas); if (!einfo) return; if (!ecore_x_composite_query()) return; ee->shaped = 0; ee->alpha = alpha; prev_win = ee->prop.window; ee->prop.window = 0; einfo->info.destination_alpha = alpha; if (edata->win_root != 0) { /* FIXME: round trip in ecore_x_window_argb_get */ if (ecore_x_window_argb_get(edata->win_root)) { ee->prop.window = _ecore_evas_x_gl_window_new(ee, edata->win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h, ee->prop.override, 1, NULL); } else { ee->prop.window = _ecore_evas_x_gl_window_new(ee, edata->win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h, ee->prop.override, ee->alpha, NULL); } } else { ee->prop.window = _ecore_evas_x_gl_window_new(ee, edata->win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h, ee->prop.override, ee->alpha, NULL); } ecore_x_window_free(prev_win); ecore_event_window_unregister(prev_win); if (!ee->prop.window) return; /* if (ee->alpha) { if (ee->prop.override) ee->prop.window = ecore_x_window_override_argb_new(edata->win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); else ee->prop.window = ecore_x_window_argb_new(edata->win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); if (!edata->mask) edata->mask = ecore_x_pixmap_new(ee->prop.window, ee->req.w, ee->req.h, 1); } else { if (ee->prop.override) ee->prop.window = ecore_x_window_override_new(edata->win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); else ee->prop.window = ecore_x_window_new(edata->win_root, ee->req.x, ee->req.y, ee->req.w, ee->req.h); if (edata->mask) ecore_x_pixmap_free(edata->mask); edata->mask = 0; ecore_x_window_shape_input_mask_set(ee->prop.window, 0); } */ ecore_x_window_attributes_get(ee->prop.window, &att); einfo->info.visual = att.visual; einfo->info.colormap = att.colormap; einfo->info.depth = att.depth; // if (edata->mask) ecore_x_pixmap_free(edata->mask); // edata->mask = 0; // einfo->info.mask = edata->mask; einfo->info.drawable = ee->prop.window; if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) { ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); } evas_damage_rectangle_add(ee->evas, 0, 0, ee->req.w, ee->req.h); // ecore_x_window_shape_mask_set(ee->prop.window, 0); ecore_x_input_multi_select(ee->prop.window); ecore_event_window_register(ee->prop.window, ee, ee->evas, (Ecore_Event_Mouse_Move_Cb)_ecore_evas_mouse_move_process, (Ecore_Event_Multi_Move_Cb)_ecore_evas_mouse_multi_move_process, (Ecore_Event_Multi_Down_Cb)_ecore_evas_mouse_multi_down_process, (Ecore_Event_Multi_Up_Cb)_ecore_evas_mouse_multi_up_process); _ecore_event_window_direct_cb_set(ee->prop.window, _ecore_evas_input_direct_cb); if (ee->prop.borderless) ecore_x_mwm_borderless_set(ee->prop.window, ee->prop.borderless); if (ee->visible || ee->should_be_visible) ecore_x_window_show(ee->prop.window); if (ecore_evas_focus_device_get(ee, NULL)) ecore_x_window_focus(ee->prop.window); if (ee->prop.title) { ecore_x_icccm_title_set(ee->prop.window, ee->prop.title); ecore_x_netwm_name_set(ee->prop.window, ee->prop.title); } if (ee->prop.name) ecore_x_icccm_name_class_set(ee->prop.window, ee->prop.name, ee->prop.clas); _ecore_evas_x_hints_update(ee); _ecore_evas_x_group_leader_update(ee); ecore_x_window_defaults_set(ee->prop.window); _ecore_evas_x_protocols_set(ee); _ecore_evas_x_window_profile_protocol_set(ee); _ecore_evas_x_wm_rotation_protocol_set(ee); _ecore_evas_x_aux_hints_supported_update(ee); _ecore_evas_x_aux_hints_update(ee); _ecore_evas_x_size_pos_hints_update(ee); _ecore_evas_x_selection_window_init(ee); #endif /* BUILD_ECORE_EVAS_OPENGL_X11 */ if ((id = getenv("DESKTOP_STARTUP_ID"))) { ecore_x_netwm_startup_id_set(ee->prop.window, id); /* NB: on linux this may simply empty the env as opposed to completely * unset it to being empty - unsure as solartis libc crashes looking * for the '=' char */ // putenv((char*)"DESKTOP_STARTUP_ID="); } } } static void _transparent_do(Ecore_Evas *ee, int transparent) { #ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 if (ee->transparent == transparent) return; Evas_Engine_Info_Software_X11 *einfo; einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas); if (!einfo) return; ee->transparent = transparent; einfo->info.destination_alpha = transparent; if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) { ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); } evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); #endif } static void _ecore_evas_x_transparent_set(Ecore_Evas *ee, int transparent) { if (!strcmp(ee->driver, "software_x11")) { if (ee->in_async_render) { ee->delayed.transparent = transparent; ee->delayed.transparent_changed = EINA_TRUE; return; } _transparent_do(ee, transparent); } } static void _ecore_evas_x_window_group_set(Ecore_Evas *ee, const Ecore_Evas *group_ee) { if (ee->prop.group_ee == group_ee) return; ee->prop.group_ee = (Ecore_Evas *)group_ee; if (ee->prop.group_ee) ee->prop.group_ee_win = group_ee->prop.window; else ee->prop.group_ee_win = 0; _ecore_evas_x_hints_update(ee); } static void _ecore_evas_x_aspect_set(Ecore_Evas *ee, double aspect) { if (EINA_FLT_EQ(ee->prop.aspect, aspect)) return; ee->prop.aspect = aspect; _ecore_evas_x_size_pos_hints_update(ee); // netwm state // if (ee->should_be_visible) // ecore_x_netwm_state_request_send(ee->prop.window, ee->engine.x.win_root, // ECORE_X_WINDOW_STATE_STICKY, -1, sticky); // else // _ecore_evas_x_state_update(ee); } static void _ecore_evas_x_urgent_set(Ecore_Evas *ee, Eina_Bool on) { if (ee->prop.urgent == on) return; ee->prop.urgent = on; _ecore_evas_x_hints_update(ee); } static void _ecore_evas_x_modal_set(Ecore_Evas *ee, Eina_Bool on) { Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; if (ee->prop.modal == on) return; ee->prop.modal = on; if (ee->should_be_visible) ecore_x_netwm_state_request_send(ee->prop.window, edata->win_root, ECORE_X_WINDOW_STATE_MODAL, -1, on); else _ecore_evas_x_state_update(ee); } static void _ecore_evas_x_demand_attention_set(Ecore_Evas *ee, Eina_Bool on) { Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; if (ee->prop.demand_attention == on) return; ee->prop.demand_attention = on; if (ee->should_be_visible) ecore_x_netwm_state_request_send(ee->prop.window, edata->win_root, ECORE_X_WINDOW_STATE_DEMANDS_ATTENTION, -1, on); else _ecore_evas_x_state_update(ee); } static void _ecore_evas_x_focus_skip_set(Ecore_Evas *ee, Eina_Bool on) { Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; if (ee->prop.focus_skip == on) return; ee->prop.focus_skip = on; if (ee->should_be_visible) { ecore_x_netwm_state_request_send(ee->prop.window, edata->win_root, ECORE_X_WINDOW_STATE_SKIP_TASKBAR, -1, on); ecore_x_netwm_state_request_send(ee->prop.window, edata->win_root, ECORE_X_WINDOW_STATE_SKIP_PAGER, -1, on); } else _ecore_evas_x_state_update(ee); _ecore_evas_x_hints_update(ee); } static void _ecore_evas_x_show(Ecore_Evas *ee) { ee->should_be_visible = 1; if (ee->prop.avoid_damage) _ecore_evas_x_render(ee); _ecore_evas_x_window_profile_set(ee); if (!ee->prop.withdrawn) _ecore_evas_x_hints_update(ee); else { ee->prop.withdrawn = EINA_FALSE; _ecore_evas_x_hints_update(ee); ee->prop.withdrawn = EINA_TRUE; } ecore_x_window_show(ee->prop.window); if (ee->prop.fullscreen) ecore_x_window_focus(ee->prop.window); } static void _ecore_evas_x_hide(Ecore_Evas *ee) { ecore_x_window_hide(ee->prop.window); ee->should_be_visible = 0; } static void _ecore_evas_x_raise(Ecore_Evas *ee) { ecore_x_window_raise(ee->prop.window); } static void _ecore_evas_x_lower(Ecore_Evas *ee) { ecore_x_window_lower(ee->prop.window); } static void _ecore_evas_x_activate(Ecore_Evas *ee) { Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; ecore_evas_show(ee); ecore_x_netwm_client_active_request(edata->win_root, ee->prop.window, 2, 0); } static void _ecore_evas_x_title_set(Ecore_Evas *ee, const char *t) { if (eina_streq(ee->prop.title, t)) return; if (ee->prop.title) free(ee->prop.title); ee->prop.title = NULL; if (!t) return; ee->prop.title = strdup(t); ecore_x_icccm_title_set(ee->prop.window, ee->prop.title); ecore_x_netwm_name_set(ee->prop.window, ee->prop.title); } static void _ecore_evas_x_name_class_set(Ecore_Evas *ee, const char *n, const char *c) { if (!eina_streq(n, ee->prop.name)) { free(ee->prop.name); ee->prop.name = NULL; if (n) ee->prop.name = strdup(n); } if (!eina_streq(c, ee->prop.clas)) { free(ee->prop.clas); ee->prop.clas = NULL; if (c) ee->prop.clas = strdup(c); } ecore_x_icccm_name_class_set(ee->prop.window, ee->prop.name, ee->prop.clas); } static void _ecore_evas_x_size_min_set(Ecore_Evas *ee, int w, int h) { if (w < 0) w = 0; if (h < 0) h = 0; if ((ee->prop.min.w == w) && (ee->prop.min.h == h)) return; ee->prop.min.w = w; ee->prop.min.h = h; _ecore_evas_x_size_pos_hints_update(ee); } static void _ecore_evas_x_size_max_set(Ecore_Evas *ee, int w, int h) { if (w < 0) w = 0; if (h < 0) h = 0; if ((ee->prop.max.w == w) && (ee->prop.max.h == h)) return; ee->prop.max.w = w; ee->prop.max.h = h; _ecore_evas_x_size_pos_hints_update(ee); } static void _ecore_evas_x_size_base_set(Ecore_Evas *ee, int w, int h) { if (w < 0) w = 0; if (h < 0) h = 0; if ((ee->prop.base.w == w) && (ee->prop.base.h == h)) return; ee->prop.base.w = w; ee->prop.base.h = h; _ecore_evas_x_size_pos_hints_update(ee); } static void _ecore_evas_x_size_step_set(Ecore_Evas *ee, int w, int h) { if (w < 1) w = 1; if (h < 1) h = 1; if ((ee->prop.step.w == w) && (ee->prop.step.h == h)) return; ee->prop.step.w = w; ee->prop.step.h = h; _ecore_evas_x_size_pos_hints_update(ee); } static void _ecore_evas_x_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer EINA_UNUSED, int hot_x EINA_UNUSED, int hot_y EINA_UNUSED) { if (obj != _ecore_evas_default_cursor_image_get(ee)) ecore_x_window_cursor_show(ee->prop.window, 0); } static void _ecore_evas_x_object_cursor_unset(Ecore_Evas *ee) { ecore_x_window_cursor_show(ee->prop.window, 1); } /* * @param ee * @param layer If < 3, @a ee will be put below all other windows. * If > 5, @a ee will be "always-on-top" * If = 4, @a ee will be put in the default layer. * Acceptable values range from 1 to 255 (0 reserved for * desktop windows) */ static void _ecore_evas_x_layer_set(Ecore_Evas *ee, int layer) { if (ee->prop.layer == layer) return; /* FIXME: Should this logic be here? */ if (layer < 1) layer = 1; else if (layer > 255) layer = 255; ee->prop.layer = layer; _ecore_evas_x_layer_update(ee); } static void _ecore_evas_x_focus_set(Ecore_Evas *ee, Eina_Bool on EINA_UNUSED) { ecore_x_window_focus(ee->prop.window); } static void _ecore_evas_x_iconified_set(Ecore_Evas *ee, Eina_Bool on) { Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; if (ee->prop.iconified == on) return; ee->prop.iconified = on; _ecore_evas_x_hints_update(ee); if (on) ecore_x_icccm_iconic_request_send(ee->prop.window, edata->win_root); else ecore_evas_activate(ee); } static void _ecore_evas_x_borderless_set(Ecore_Evas *ee, Eina_Bool on) { if (ee->prop.borderless == on) return; ee->prop.borderless = on; ecore_x_mwm_borderless_set(ee->prop.window, ee->prop.borderless); } /* FIXME: This function changes the initial state of the ee * whilest the iconic function changes the current state! */ static void _ecore_evas_x_withdrawn_set(Ecore_Evas *ee, Eina_Bool on) { if (ee->prop.withdrawn == on) return; // ee->prop.withdrawn = on; if (on) ecore_evas_hide(ee); else ecore_evas_show(ee); } static void _ecore_evas_x_sticky_set(Ecore_Evas *ee, Eina_Bool on) { Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; if (ee->prop.sticky == on) return; /* We dont want to set prop.sticky here as it will cause * the sticky callback not to get called. Its set on the * property change event. * ee->prop.sticky = on; */ // edata->state.sticky = on; if (ee->should_be_visible) ecore_x_netwm_state_request_send(ee->prop.window, edata->win_root, ECORE_X_WINDOW_STATE_STICKY, -1, on); else _ecore_evas_x_state_update(ee); } static void _ecore_evas_x_ignore_events_set(Ecore_Evas *ee, int ignore) { if (ee->ignore_events == ignore) return; ee->ignore_events = ignore; if (ee->prop.window) ecore_x_window_ignore_set(ee->prop.window, ignore); } /* static void _ecore_evas_x_reinit_win(Ecore_Evas *ee) { if (!strcmp(ee->driver, "software_x11")) { #ifdef BUILD_ECORE_EVAS_X11 Evas_Engine_Info_Software_X11 *einfo; einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas); if (einfo) { einfo->info.drawable = ee->prop.window; if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) { ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); } } #endif } else if (!strcmp(ee->driver, "opengl_x11")) { #ifdef BUILD_ECORE_EVAS_OPENGL_X11 Evas_Engine_Info_GL_X11 *einfo; einfo = (Evas_Engine_Info_GL_X11 *)evas_engine_info_get(ee->evas); if (einfo) { einfo->info.drawable = ee->prop.window; if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) { ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); } } #endif } } */ static void _ecore_evas_x_override_set(Ecore_Evas *ee, Eina_Bool on) { if (ee->prop.override == on) return; if (ee->should_be_visible) ecore_x_window_hide(ee->prop.window); ecore_x_window_override_set(ee->prop.window, on); if (ee->should_be_visible) ecore_x_window_show(ee->prop.window); if (ecore_evas_focus_device_get(ee, NULL)) ecore_x_window_focus(ee->prop.window); ee->prop.override = on; } static void _ecore_evas_x_maximized_set(Ecore_Evas *ee, Eina_Bool on) { Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; if (ee->should_be_visible) { ecore_x_netwm_state_request_send(ee->prop.window, edata->win_root, ECORE_X_WINDOW_STATE_MAXIMIZED_VERT, ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ, on); } else { if (ee->prop.maximized == on) return; ee->prop.maximized = on; edata->state.maximized_h = on; edata->state.maximized_v = on; _ecore_evas_x_state_update(ee); } } static void _ecore_evas_x_fullscreen_set(Ecore_Evas *ee, Eina_Bool on) { Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; if (ee->prop.fullscreen == on) return; /* FIXME: Detect if WM is EWMH compliant and handle properly if not, * i.e. reposition, resize, and change borderless hint */ edata->state.fullscreen = on; if (ee->should_be_visible) ecore_x_netwm_state_request_send(ee->prop.window, edata->win_root, ECORE_X_WINDOW_STATE_FULLSCREEN, -1, on); else _ecore_evas_x_state_update(ee); } static void _ecore_evas_x_profile_set(Ecore_Evas *ee, const char *profile) { Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; _ecore_evas_window_profile_free(ee); ee->prop.profile.name = NULL; if (profile) ee->prop.profile.name = (char *)eina_stringshare_add(profile); edata->profile.change = 1; _ecore_evas_x_window_profile_set(ee); } static void _ecore_evas_x_profiles_set(Ecore_Evas *ee, const char **plist, int n) { int i; Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; _ecore_evas_window_available_profiles_free(ee); ee->prop.profile.available_list = NULL; if ((plist) && (n >= 1)) { ee->prop.profile.available_list = calloc(n, sizeof(char *)); if (ee->prop.profile.available_list) { for (i = 0; i < n; i++) ee->prop.profile.available_list[i] = (char *)eina_stringshare_add(plist[i]); ee->prop.profile.count = n; } } edata->profile.available = 1; _ecore_evas_x_window_profile_set(ee); } static void _avoid_damage_do(Ecore_Evas *ee, int on) { #ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 Evas_Engine_Info_Software_X11 *einfo; Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; ee->prop.avoid_damage = on; einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas); if (einfo) { if (ee->prop.avoid_damage) { edata->pmap = ecore_x_pixmap_new(ee->prop.window, ee->w, ee->h, einfo->info.depth); edata->gc = ecore_x_gc_new(edata->pmap, 0, NULL); einfo->info.drawable = edata->pmap; if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) { ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); } if (ECORE_EVAS_PORTRAIT(ee)) evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); else evas_damage_rectangle_add(ee->evas, 0, 0, ee->h, ee->w); if (ee->prop.avoid_damage == ECORE_EVAS_AVOID_DAMAGE_BUILT_IN) { edata->using_bg_pixmap = 1; ecore_x_window_pixmap_set(ee->prop.window, edata->pmap); ecore_x_window_area_expose(ee->prop.window, 0, 0, ee->w, ee->h); } if (edata->direct_resize) { /* Turn this off for now edata->using_bg_pixmap = 1; ecore_x_window_pixmap_set(ee->prop.window, edata->pmap); */ } } else { if (edata->pmap) ecore_x_pixmap_free(edata->pmap); if (edata->gc) ecore_x_gc_free(edata->gc); if (edata->using_bg_pixmap) { ecore_x_window_pixmap_set(ee->prop.window, 0); edata->using_bg_pixmap = 0; ecore_x_window_area_expose(ee->prop.window, 0, 0, ee->w, ee->h); } edata->pmap = 0; edata->gc = 0; einfo->info.drawable = ee->prop.window; if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) { ERR("evas_engine_info_set() for engine '%s' failed.", ee->driver); } } } #endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 */ } static void _ecore_evas_x_avoid_damage_set(Ecore_Evas *ee, int on) { if (ee->prop.avoid_damage == on) return; if (!strcmp(ee->driver, "opengl_x11")) return; if (!strcmp(ee->driver, "software_x11")) { if (ee->in_async_render) { ee->delayed.avoid_damage = on; return; } _avoid_damage_do(ee, on); } } static void _ecore_evas_x_screen_geometry_get(const Ecore_Evas *ee, int *x, int *y, int *w, int *h) { int outnum = 0, i; int px = 0, py = 0, pw = 0, ph = 0; Ecore_X_Window root; Ecore_X_Randr_Output *out = NULL; Ecore_X_Randr_Crtc crtc; unsigned int val[4] = { 0 }; Eina_Bool found = EINA_FALSE; if (ecore_x_window_prop_card32_get (ee->prop.window, ecore_x_atom_get("E_ZONE_GEOMETRY"), val, 4) == 4) { if (x) *x = (int)val[0]; if (y) *y = (int)val[1]; if (w) *w = (int)val[2]; if (h) *h = (int)val[3]; return; } root = ecore_x_window_root_get(ee->prop.window); out = ecore_x_randr_window_outputs_get(ee->prop.window, &outnum); if (!out) { norandr: if (x) *x = 0; if (y) *y = 0; ecore_x_window_size_get(root, w, h); return; } for (i = 0; i < outnum; i++) { Eina_Rectangle winrect, outrect; crtc = ecore_x_randr_output_crtc_get(root, out[i]); if (!crtc) continue; ecore_x_randr_crtc_geometry_get(root, crtc, &px, &py, &pw, &ph); if ((pw == 0) || (ph == 0)) continue; if ((i == 0) || (ecore_x_randr_primary_output_get(root) == out[i])) { found = EINA_TRUE; if (x) *x = px; if (y) *y = py; if (w) *w = pw; if (h) *h = ph; } winrect.x = ee->x + (ee->w / 2); winrect.y = ee->y + (ee->h / 2); winrect.w = 1; winrect.h = 1; outrect.x = px; outrect.y = py; outrect.w = pw; outrect.h = ph; if (eina_rectangles_intersect(&outrect, &winrect)) { if (x) *x = px; if (y) *y = py; if (w) *w = pw; if (h) *h = ph; free(out); return; } } free(out); if (!found) goto norandr; } static void _ecore_evas_x_screen_dpi_get(const Ecore_Evas *ee, int *xdpi, int *ydpi) { int scdpi, xmm = 0, ymm = 0, outnum = 0, w = 0, h = 0; int px = 0, py = 0, i; Ecore_X_Window root; Ecore_X_Randr_Output *out = NULL; Ecore_X_Randr_Crtc crtc; Eina_Bool found = EINA_FALSE; root = ecore_x_window_root_get(ee->prop.window); out = ecore_x_randr_window_outputs_get(ee->prop.window, &outnum); if (!out) { norandr: scdpi = ecore_x_dpi_get(); if (xdpi) *xdpi = scdpi; if (ydpi) *ydpi = scdpi; return; } for (i = 0; i < outnum; i++) { Eina_Rectangle winrect, outrect; crtc = ecore_x_randr_output_crtc_get(root, out[i]); if (!crtc) continue; ecore_x_randr_crtc_geometry_get(root, crtc, &px, &py, &w, &h); if ((w == 0) || (h == 0)) continue; ecore_x_randr_output_size_mm_get(root, out[i], &xmm, &ymm); if ((xmm == 0) || (ymm == 0)) continue; if ((i == 0) || (ecore_x_randr_primary_output_get(root) == out[i])) { found = EINA_TRUE; if (xdpi) *xdpi = (w * 254) / (xmm * 10); // 25.4mm / inch if (ydpi) *ydpi = (h * 254) / (ymm * 10); // 25.4mm / inch } winrect.x = ee->x + (ee->w / 2); winrect.y = ee->y + (ee->h / 2); winrect.w = 1; winrect.h = 1; outrect.x = px; outrect.y = py; outrect.w = w; outrect.h = h; if (eina_rectangles_intersect(&outrect, &winrect)) { if (xdpi) *xdpi = (w * 254) / (xmm * 10); // 25.4mm / inch if (ydpi) *ydpi = (h * 254) / (ymm * 10); // 25.4mm / inch free(out); return; } } free(out); if (!found) goto norandr; } static void _ecore_evas_x_pointer_xy_get(const Ecore_Evas *ee, Evas_Coord *x, Evas_Coord *y) { if (ee->prop.window) ecore_x_pointer_xy_get(ee->prop.window, x, y); } static Eina_Bool _ecore_evas_x_pointer_warp(const Ecore_Evas *ee, Evas_Coord x, Evas_Coord y) { return ecore_x_pointer_warp(ee->prop.window, x, y); } static void _ecore_evas_x_wm_rot_preferred_rotation_set(Ecore_Evas *ee, int rot) { if (ee->prop.wm_rot.supported) { if (!ee->prop.wm_rot.app_set) { ecore_x_e_window_rotation_app_set(ee->prop.window, EINA_TRUE); ee->prop.wm_rot.app_set = EINA_TRUE; } ecore_x_e_window_rotation_preferred_rotation_set(ee->prop.window, rot); ee->prop.wm_rot.preferred_rot = rot; } } static void _ecore_evas_x_wm_rot_available_rotations_set(Ecore_Evas *ee, const int *rots, unsigned int count) { if (ee->prop.wm_rot.supported) { if (!ee->prop.wm_rot.app_set) { ecore_x_e_window_rotation_app_set(ee->prop.window, EINA_TRUE); ee->prop.wm_rot.app_set = EINA_TRUE; } if (ee->prop.wm_rot.available_rots) { free(ee->prop.wm_rot.available_rots); ee->prop.wm_rot.available_rots = NULL; } ee->prop.wm_rot.count = 0; if (count > 0) { ee->prop.wm_rot.available_rots = calloc(count, sizeof(int)); if (!ee->prop.wm_rot.available_rots) return; memcpy(ee->prop.wm_rot.available_rots, rots, sizeof(int) * count); } ee->prop.wm_rot.count = count; ecore_x_e_window_rotation_available_rotations_set(ee->prop.window, rots, count); } } static void _ecore_evas_x_wm_rot_manual_rotation_done_set(Ecore_Evas *ee, Eina_Bool set) { ee->prop.wm_rot.manual_mode.set = set; } static void _ecore_evas_x_wm_rot_manual_rotation_done(Ecore_Evas *ee) { Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; if ((ee->prop.wm_rot.supported) && (ee->prop.wm_rot.app_set) && (ee->prop.wm_rot.manual_mode.set)) { if (ee->prop.wm_rot.manual_mode.wait_for_done) { if (ee->prop.wm_rot.manual_mode.timer) ecore_timer_del(ee->prop.wm_rot.manual_mode.timer); ee->prop.wm_rot.manual_mode.timer = NULL; if (edata->wm_rot.manual_mode_job) ecore_job_del(edata->wm_rot.manual_mode_job); edata->wm_rot.manual_mode_job = ecore_job_add (_ecore_evas_x_wm_rot_manual_rotation_done_job, ee); } } } static Eina_Bool _ecore_evas_x_wm_rot_manual_rotation_done_timeout(void *data) { Ecore_Evas *ee = data; ee->prop.wm_rot.manual_mode.timer = NULL; _ecore_evas_x_wm_rot_manual_rotation_done(ee); return ECORE_CALLBACK_CANCEL; } static void _ecore_evas_x_wm_rot_manual_rotation_done_timeout_update(Ecore_Evas *ee) { if (ee->prop.wm_rot.manual_mode.timer) ecore_timer_del(ee->prop.wm_rot.manual_mode.timer); ee->prop.wm_rot.manual_mode.timer = ecore_timer_add (4.0f, _ecore_evas_x_wm_rot_manual_rotation_done_timeout, ee); } static void _ecore_evas_x_aux_hints_set(Ecore_Evas *ee, const char *hints) { if (hints) ecore_x_window_prop_property_set (ee->prop.window, ECORE_X_ATOM_E_WINDOW_AUX_HINT, ECORE_X_ATOM_STRING, 8, (void *)hints, strlen(hints) + 1); else ecore_x_window_prop_property_del (ee->prop.window, ECORE_X_ATOM_E_WINDOW_AUX_HINT); } static Ecore_X_Atom ecore_evas_selection_to_atom[] = {0, 0, 0, 0}; static Ecore_Event_Handler *ecore_evas_selection_handlers[8]; static inline Ecore_Evas_Selection_Buffer _atom_to_selection(Ecore_X_Atom atom) { for (int i = 0; i < ECORE_EVAS_SELECTION_BUFFER_LAST; ++i) { if (ecore_evas_selection_to_atom[i] == atom) return i; } return ECORE_EVAS_SELECTION_BUFFER_LAST; } static Eina_Stringshare* _decrypt_type(const char *target) { // reference https://tronche.com/gui/x/icccm/sec-2.html if (eina_streq(target, "TEXT")) return eina_stringshare_add("text/plain"); //FIXME no support in eina_content for that so far if (eina_streq(target, "COMPOUND_TEXT")) return eina_stringshare_add("text/plain"); // reference https://tronche.com/gui/x/icccm/sec-2.html if (eina_streq(target, "STRING")) return eina_stringshare_add("text/plain;charset=iso-8859-1"); if (eina_streq(target, "UTF8_STRING")) return eina_stringshare_add("text/plain;charset=utf-8"); return eina_stringshare_add(target); } static Eina_Stringshare* _mime_to_xserver_type(const char *target) { // FIXME // reference https://tronche.com/gui/x/icccm/sec-2.html says it is in the owners choice of encoding, not sure what this means directly here if (eina_streq(target, "text/plain")) return eina_stringshare_add("TEXT"); // reference https://tronche.com/gui/x/icccm/sec-2.html if (eina_streq(target, "text/plain;charset=iso-8859-1")) return eina_stringshare_add("STRING"); if (eina_streq(target, "text/plain;charset=utf-8")) return eina_stringshare_add("UTF8_STRING"); return eina_stringshare_add(target); } static inline void _clear_selection(Ecore_Evas *ee, Ecore_Evas_Selection_Buffer selection) { Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; Ecore_Evas_Selection_Callbacks *cbs = &edata->selection_data[selection].callbacks; EINA_SAFETY_ON_FALSE_RETURN(cbs->cancel); cbs->cancel(ee, 1, selection); eina_array_free(cbs->available_types); cbs->delivery = NULL; cbs->cancel = NULL; cbs->available_types = NULL; } static void _clear_selection_delivery(Ecore_Evas *ee, Ecore_Evas_Selection_Buffer selection) { Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data; eina_stringshare_replace(&edata->selection_data[selection].requested_type, NULL); eina_stringshare_replace(&edata->selection_data[selection].later_conversion, NULL); edata->selection_data[selection].delivery = NULL; eina_array_free(edata->selection_data[selection].acceptable_type); edata->selection_data[selection].acceptable_type = NULL; } static void _ecore_x_selection_request(Ecore_X_Window win, Ecore_Evas_Selection_Buffer selection, const char *type) { if (selection == ECORE_EVAS_SELECTION_BUFFER_SELECTION_BUFFER) ecore_x_selection_primary_request(win, type); else if (selection == ECORE_EVAS_SELECTION_BUFFER_COPY_AND_PASTE_BUFFER) ecore_x_selection_clipboard_request(win, type); else ecore_x_selection_xdnd_request(win, type); } static void _search_fitting_type(Ecore_Evas *ee, Ecore_Evas_Engine_Data_X11 *edata, Ecore_Evas_Selection_Buffer selection, Eina_Array *arr) { Eina_Stringshare *mime_type; Eina_Bool found_conversion = EINA_FALSE; #define HANDLE_TYPE() \ { \ edata->selection_data[selection].requested_type = eina_stringshare_add(x11_name); \ edata->selection_data[selection].later_conversion = eina_stringshare_add(acceptable_type);\ found_conversion = EINA_TRUE; \ break; \ } EINA_SAFETY_ON_NULL_RETURN(edata->selection_data[selection].acceptable_type); // first pass - try find an EXACT mime type match 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() } } eina_stringshare_del(mime_type); } // second pass - exact match not found - look for conversions instead if (!found_conversion) { 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); const char *convertion_type = NULL; Eina_Iterator *iter = eina_content_converter_possible_conversions(mime_type); EINA_ITERATOR_FOREACH(iter, convertion_type) { if (convertion_type == acceptable_type) { HANDLE_TYPE() } } eina_iterator_free(iter); } eina_stringshare_del(mime_type); } } if (found_conversion) { _ecore_x_selection_request(ee->prop.window, selection, edata->selection_data[selection].requested_type); } else { eina_promise_resolve(edata->selection_data[selection].delivery, eina_value_error_init(ecore_evas_no_matching_type)); _clear_selection_delivery(ee, selection); } #undef HANDLE_TYPE } static void _search_fitting_type_from_event(Ecore_Evas *ee, Ecore_Evas_Engine_Data_X11 *edata, Ecore_Evas_Selection_Buffer selection, Ecore_X_Event_Selection_Notify *ev) { Ecore_X_Atom *available_atoms; Ecore_X_Selection_Data_Targets *targets; Eina_Array *tmp = eina_array_new(10); targets = ev->data; available_atoms = (Ecore_X_Atom *)targets->data.data; for (int i = 0; i < targets->data.length; ++i) { Ecore_X_Atom atom = available_atoms[i]; eina_array_push(tmp, ecore_x_atom_name_get(atom)); } _search_fitting_type(ee, edata, selection, tmp); eina_array_free(tmp); } static Eina_Content* _create_delivery_content(unsigned long int size, const void *mem, const char *mime_type) { Eina_Content *content; content = eina_content_new((Eina_Slice){.len = size, .mem = mem}, mime_type); return content; } static void _deliver_content(Ecore_Evas *ee, Ecore_Evas_Engine_Data_X11 *edata, Ecore_Evas_Selection_Buffer selection, Ecore_X_Event_Selection_Notify *ev) { Eina_Content *result = NULL; Eina_Stringshare *mime_type = _decrypt_type(edata->selection_data[selection].requested_type); EINA_SAFETY_ON_NULL_GOTO(ev->data, err); if (eina_streq(mime_type, "text/uri-list")) { Ecore_X_Selection_Data_Files *files = ev->data; Efreet_Uri *uri; Eina_Strbuf *strbuf; int i; strbuf = eina_strbuf_new(); for (i = 0; i < files->num_files ; i++) { uri = efreet_uri_decode(files->files[i]); if (uri) { eina_strbuf_append(strbuf, uri->path); efreet_uri_free(uri); } else { eina_strbuf_append(strbuf, files->files[i]); } if (i < (files->num_files - 1)) eina_strbuf_append(strbuf, "\n"); } result = _create_delivery_content(eina_strbuf_length_get(strbuf) + 1, eina_strbuf_string_get(strbuf), mime_type); eina_strbuf_free(strbuf); } else if (eina_str_has_prefix(mime_type,"text")) { Ecore_X_Selection_Data *x11_data = ev->data; //ensure that we always have a \0 at the end, there is no assertion that \0 is included here. void *null_terminated = eina_memdup(x11_data->data, x11_data->length, EINA_TRUE); result = _create_delivery_content(x11_data->length + 1, null_terminated, mime_type); free(null_terminated); } else if (eina_str_has_prefix(mime_type,"image")) { Ecore_X_Selection_Data *x11_data = ev->data; Eina_Content *tmp_container = eina_content_new((Eina_Slice){.len = x11_data->length, .mem = x11_data->data}, mime_type); const char *file = eina_content_as_file(tmp_container); result = _create_delivery_content(strlen(file), file, mime_type); eina_content_free(tmp_container); } else { Ecore_X_Selection_Data *x11_data = ev->data; result = _create_delivery_content(x11_data->length, x11_data->data, mime_type); } EINA_SAFETY_ON_NULL_GOTO(result, err); //ensure that we deliver the correct type, we might have choosen a convertion before if (edata->selection_data[selection].later_conversion != mime_type) { Eina_Content *tmp = eina_content_convert(result, edata->selection_data[selection].later_conversion); eina_content_free(result); result = tmp; } eina_promise_resolve(edata->selection_data[selection].delivery, eina_value_content_init(result)); eina_content_free(result); _clear_selection_delivery(ee, selection); if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER) ecore_x_dnd_send_finished(); return; err: eina_promise_reject(edata->selection_data[selection].delivery, ecore_evas_no_selection); if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER) ecore_x_dnd_send_finished(); } static Eina_Bool _ecore_evas_x_selection_notify(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event) { Ecore_X_Event_Selection_Notify *ev = event; Ecore_Evas_Selection_Buffer selection; Ecore_Evas_Engine_Data_X11 *edata; Ecore_Evas *ee; ee = ecore_event_window_match(ev->win); selection = _atom_to_selection(ev->atom); EINA_SAFETY_ON_FALSE_GOTO(!!ee, end); EINA_SAFETY_ON_FALSE_GOTO(selection != ECORE_EVAS_SELECTION_BUFFER_LAST, end); edata = ee->engine.data; //if dnd drops above us, and even if we did not request anything, we are getting notified, refuse to do anything if (selection == ECORE_EVAS_SELECTION_BUFFER_DRAG_AND_DROP_BUFFER && !edata->selection_data[selection].later_conversion) { ecore_x_dnd_send_finished(); } else { if (eina_streq(ev->target, "TARGETS") || eina_streq(ev->target, "ATOMS")) { //This will decide for a type, and will sent that via _ecore_x_selection_request EINA_SAFETY_ON_FALSE_RETURN_VAL(!edata->selection_data[selection].later_conversion, EINA_FALSE); EINA_SAFETY_ON_FALSE_RETURN_VAL(!edata->selection_data[selection].requested_type, EINA_FALSE); _search_fitting_type_from_event(ee, edata, selection, ev); } else { //This will read the data, fill it into a Eina_Content apply all conversions required. EINA_SAFETY_ON_FALSE_RETURN_VAL(edata->selection_data[selection].later_conversion, EINA_FALSE); EINA_SAFETY_ON_FALSE_RETURN_VAL(edata->selection_data[selection].requested_type, EINA_FALSE); _deliver_content(ee, edata, selection, ev); } } end: return ECORE_CALLBACK_PASS_ON; } static Eina_Bool _ecore_evas_x_selection_clear(void *udata EINA_UNUSED, int type EINA_UNUSED, void *event) { Ecore_X_Event_Selection_Clear *ev = event; Ecore_Evas_Selection_Callbacks *cbs; Ecore_Evas_Engine_Data_X11 *edata; Ecore_Evas_Selection_Buffer selection; Ecore_Evas *ee; ee = ecore_event_window_match(ev->win); selection = _atom_to_selection(ev->atom); EINA_SAFETY_ON_FALSE_GOTO(ee, end); EINA_SAFETY_ON_FALSE_GOTO(selection != ECORE_EVAS_SELECTION_BUFFER_LAST, end); edata = ee->engine.data; cbs = &edata->selection_data[selection].callbacks; //skip clean event if (edata->skip_clean_event) { edata->skip_clean_event --; goto end; } if (cbs->cancel) _clear_selection(ee, selection); end: return ECORE_CALLBACK_PASS_ON; } static void _force_stop_self_dnd(Ecore_Evas *ee) { Ecore_Evas_Engine_Data_X11 *edata; EINA_SAFETY_ON_NULL_RETURN(ee); edata = ee->engine.data; EINA_SAFETY_ON_NULL_RETURN(edata); //Never clear the buffer for selection here. //Selection buffer is freed as a response to the FINISHED event. ecore_x_pointer_ungrab(); ecore_x_dnd_self_drop(); if ((!ee->func.fn_dnd_drop) && (!ee->func.fn_dnd_state_change) && (!ee->func.fn_dnd_motion)) 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)); ecore_x_dnd_send_status(used, 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_Size2D offset; Eina_Rect rect; ecore_evas_geometry_get(ee->drag.rep, &rect.x, &rect.y, &rect.w, &rect.h); if (ee->drag.offset.w == INT_MAX) offset.w = rect.size.w / -2; else offset.w = ee->drag.offset.w; if (ee->drag.offset.h == INT_MAX) offset.h = rect.size.h / -2; else offset.h = ee->drag.offset.h; ecore_evas_move(ee->drag.rep, pos->position.x + offset.w, pos->position.y + offset.h); } 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 EMODAPI 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.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; } EMODAPI 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.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 EMODAPI 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; } EMODAPI 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); } EMODAPI 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