diff options
Diffstat (limited to 'src/lib/efl_canvas_wl/copiedfromweston.x')
-rw-r--r-- | src/lib/efl_canvas_wl/copiedfromweston.x | 413 |
1 files changed, 413 insertions, 0 deletions
diff --git a/src/lib/efl_canvas_wl/copiedfromweston.x b/src/lib/efl_canvas_wl/copiedfromweston.x new file mode 100644 index 0000000000..d5c35eee75 --- /dev/null +++ b/src/lib/efl_canvas_wl/copiedfromweston.x @@ -0,0 +1,413 @@ +/* + * Copyright © 2011 Kristian Høgsberg + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \ + WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \ + WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK) + +static uint32_t +data_offer_choose_action(Comp_Data_Device_Offer *offer) +{ + uint32_t available_actions, preferred_action = 0; + uint32_t source_actions, offer_actions; + + if (wl_resource_get_version(offer->res) >= + WL_DATA_OFFER_ACTION_SINCE_VERSION) + { + offer_actions = offer->dnd_actions; + preferred_action = offer->preferred_dnd_action; + } + else + { + offer_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; + } + + if (wl_resource_get_version(offer->source->res) >= + WL_DATA_SOURCE_ACTION_SINCE_VERSION) + source_actions = offer->source->dnd_actions; + else + source_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; + + available_actions = offer_actions & source_actions; + + if (!available_actions) + return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; + + if (offer->source->seat && + offer->source->compositor_action & available_actions) + return offer->source->compositor_action; + + /* If the dest side has a preferred DnD action, use it */ + if ((preferred_action & available_actions) != 0) + return preferred_action; + + /* Use the first found action, in bit order */ + return 1 << (ffs(available_actions) - 1); +} + +static void +data_offer_update_action(Comp_Data_Device_Offer *offer) +{ + uint32_t action; + + if (!offer->source) + return; + + action = data_offer_choose_action(offer); + + if (offer->source->current_dnd_action == action) + return; + + offer->source->current_dnd_action = action; + + if (offer->in_ask) + return; + + if (wl_resource_get_version(offer->source->res) >= + WL_DATA_SOURCE_ACTION_SINCE_VERSION) + wl_data_source_send_action(offer->source->res, action); + + if (wl_resource_get_version(offer->res) >= + WL_DATA_OFFER_ACTION_SINCE_VERSION) + wl_data_offer_send_action(offer->res, action); +} + +static void +data_device_offer_set_actions(struct wl_client *client, + struct wl_resource *resource, + uint32_t dnd_actions, uint32_t preferred_action) +{ + Comp_Data_Device_Offer *offer = wl_resource_get_user_data(resource); + + if (dnd_actions & ~ALL_ACTIONS) + { + wl_resource_post_error(offer->res, + WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK, + "invalid action mask %x", dnd_actions); + return; + } + + if (preferred_action && + (!(preferred_action & dnd_actions) || + __builtin_popcount(preferred_action) > 1)) + { + wl_resource_post_error(offer->res, + WL_DATA_OFFER_ERROR_INVALID_ACTION, + "invalid action %x", preferred_action); + return; + } + + offer->dnd_actions = dnd_actions; + offer->preferred_dnd_action = preferred_action; + data_offer_update_action(offer); +} + +#ifdef HAVE_ECORE_X +static Ecore_X_Atom +action_convert(uint32_t action) +{ + if (action == WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE) + return ECORE_X_ATOM_XDND_ACTION_MOVE; + if (action == WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK) + return ECORE_X_ATOM_XDND_ACTION_ASK; + return ECORE_X_ATOM_XDND_ACTION_COPY; +} +#endif +static void +data_device_offer_accept(struct wl_client *client, struct wl_resource *resource, + uint32_t serial, const char *mime_type) +{ + Comp_Data_Device_Offer *offer = wl_resource_get_user_data(resource); + Comp_Surface *cs; + + /* Protect against untimely calls from older data offers */ + if (!offer->source || offer != offer->source->offer) + return; + + switch (offer->type) + { + case COMP_DATA_DEVICE_OFFER_TYPE_DND: + cs = offer->source->seat->drag.enter; + if (!offer->source->seat->drag.res) return; + if ((!offer->source->seat->drag.source) && + (wl_resource_get_client(cs->res) != wl_resource_get_client(offer->source->seat->drag.res))) + return; +#ifdef HAVE_ECORE_X + if (offer->source->x11_owner) + { + Ecore_Window win = ecore_evas_window_get(ecore_evas_ecore_evas_get(offer->source->seat->c->evas)); + offer->source->accepted = mime_type != NULL; + ecore_x_client_message32_send(offer->source->x11_owner, + ECORE_X_ATOM_XDND_STATUS, ECORE_X_EVENT_MASK_NONE, + win, 2 | !!mime_type, 0, 0, + (!!mime_type) * action_convert(offer->source->current_dnd_action)); + return; + } +#endif + break; + + case COMP_DATA_DEVICE_OFFER_TYPE_CLIPBOARD: + break; + default: return; + } + if (offer->source->seat->client_offer) + ecore_wl2_offer_accept(offer->source->seat->client_offer, mime_type); + else + wl_data_source_send_target(offer->source->res, mime_type); + offer->source->accepted = mime_type != NULL; +} + +static void +data_device_offer_receive(struct wl_client *client, struct wl_resource *resource, + const char *mime_type, int32_t fd) +{ + Comp_Data_Device_Offer *offer = wl_resource_get_user_data(resource); + + if (offer->source && offer == offer->source->offer) + { + if (offer->proxy) + { + Ecore_Wl2_Offer *off; +#ifdef HAVE_ECORE_X + if (offer->source->x11_owner) + { + x11_send_send(offer->source, mime_type, fd, offer->type); + return; + } +#endif + if (offer->type == COMP_DATA_DEVICE_OFFER_TYPE_CLIPBOARD) + off = ecore_wl2_dnd_selection_get(offer->source->seat->seat); + else + { + off = offer->source->seat->client_offer; + offer->source->seat->client_offer = NULL; + } + ecore_wl2_offer_proxy_receive(off, mime_type, fd); + offer->proxy_offer = off; + } + else + wl_data_source_send_send(offer->source->res, mime_type, fd); + } + close(fd); +} + +static void +data_source_notify_finish(Comp_Data_Device_Source *source) +{ + if (!source->actions_set) + return; + + if (source->proxy && (!source->x11_owner)) + ecore_wl2_offer_finish(source->offer->proxy_offer); + + if (source->offer && source->offer->in_ask && + wl_resource_get_version(source->res) >= + WL_DATA_SOURCE_ACTION_SINCE_VERSION) + { + wl_data_source_send_action(source->res, + source->current_dnd_action); + } + + if (wl_resource_get_version(source->res) >= + WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) + { + wl_data_source_send_dnd_finished(source->res); + } + + source->offer = NULL; +} + +static void +data_device_offer_finish(struct wl_client *client, struct wl_resource *resource) +{ + Comp_Data_Device_Offer *offer = wl_resource_get_user_data(resource); + + if (!offer->source || offer->source->offer != offer) + return; + + /* Disallow finish while we have a grab driving drag-and-drop, or + * if the negotiation is not at the right stage + */ + if (((!offer->proxy) && offer->source->seat) || + !offer->source->accepted) + { + wl_resource_post_error(offer->res, + WL_DATA_OFFER_ERROR_INVALID_FINISH, + "premature finish request"); + return; + } + + switch (offer->source->current_dnd_action) + { + case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE: + case WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK: + wl_resource_post_error(offer->res, + WL_DATA_OFFER_ERROR_INVALID_OFFER, + "offer finished with an invalid action"); + return; + + default: + break; + } + + data_source_notify_finish(offer->source); +} + +static void +data_device_offer_impl_destroy(struct wl_resource *resource) +{ + Comp_Data_Device_Offer *offer = wl_resource_get_user_data(resource); + + if (!offer->source) + goto out; + + if (offer->source->offer != offer) + goto out; + + if (offer->type == COMP_DATA_DEVICE_OFFER_TYPE_DND) + { + /* If the drag destination has version < 3, wl_data_offer.finish + * won't be called, so do this here as a safety net, because + * we still want the version >=3 drag source to be happy. + */ + if (wl_resource_get_version(offer->res) < + WL_DATA_OFFER_ACTION_SINCE_VERSION) + { + data_source_notify_finish(offer->source); + } + else if (offer->source->res && + wl_resource_get_version(offer->source->res) >= + WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) + { + wl_data_source_send_cancelled(offer->source->res); + } + } + + offer->source->offer = NULL; + if (offer->proxy_offer && offer->proxy) + ecore_wl2_offer_proxy_receive_end(offer->proxy_offer); +out: + free(offer); +} + +static void +drag_grab_button(Comp_Seat *s, + uint32_t time, uint32_t button, uint32_t state_w) +{ + Comp_Data_Device_Source *data_source = s->drag.source; + enum wl_pointer_button_state state = state_w; + struct wl_resource *res; + + if (data_source && + s->drag.id == button && + state == WL_POINTER_BUTTON_STATE_RELEASED) + { + if ((s->drag.enter || (s->drag.x11_owner == ecore_evas_window_get(ecore_evas_ecore_evas_get(s->c->evas)))) && + data_source->accepted && + data_source->current_dnd_action) + { + if (s->drag.enter) + { + res = data_device_find(s, s->drag.enter->res); + if (!res) return; + + wl_data_device_send_drop(res); + } + if (wl_resource_get_version(data_source->res) >= + WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION) + wl_data_source_send_dnd_drop_performed(data_source->res); + + if (data_source->offer) + data_source->offer->in_ask = + data_source->current_dnd_action == + WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK; + + if (!data_source->proxy) + data_source->seat = NULL; + } + else if (wl_resource_get_version(data_source->res) >= + WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) + { + wl_data_source_send_cancelled(data_source->res); + } + seat_drag_end(s); + if (!data_source->x11_owner) + s->drag.source = NULL; +#ifdef HAVE_ECORE_X + if (ecore_x_display_get()) + ecore_x_pointer_ungrab(); +#endif + } +} + +#ifdef HAVE_ECORE_X +static xkb_mod_index_t x11_kbd_shift_mod; +static xkb_mod_index_t x11_kbd_caps_mod; +static xkb_mod_index_t x11_kbd_ctrl_mod; +static xkb_mod_index_t x11_kbd_alt_mod; +static xkb_mod_index_t x11_kbd_mod2_mod; +static xkb_mod_index_t x11_kbd_mod3_mod; +static xkb_mod_index_t x11_kbd_super_mod; +static xkb_mod_index_t x11_kbd_mod5_mod; + +static void +keymap_mods_init(struct xkb_keymap *keymap) +{ + x11_kbd_shift_mod = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT); + x11_kbd_caps_mod = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS); + x11_kbd_ctrl_mod = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL); + x11_kbd_alt_mod = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_ALT); + x11_kbd_mod2_mod = xkb_keymap_mod_get_index(keymap, "Mod2"); + x11_kbd_mod3_mod = xkb_keymap_mod_get_index(keymap, "Mod3"); + x11_kbd_super_mod = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_LOGO); + x11_kbd_mod5_mod = xkb_keymap_mod_get_index(keymap, "Mod5"); +} + +static uint32_t +get_xkb_mod_mask(uint32_t in) +{ + uint32_t ret = 0; + + if ((in & ECORE_X_MODIFIER_SHIFT) && x11_kbd_shift_mod != XKB_MOD_INVALID) + ret |= (1 << x11_kbd_shift_mod); + if ((in & ECORE_X_LOCK_CAPS) && x11_kbd_caps_mod != XKB_MOD_INVALID) + ret |= (1 << x11_kbd_caps_mod); + if ((in & ECORE_X_MODIFIER_CTRL) && x11_kbd_ctrl_mod != XKB_MOD_INVALID) + ret |= (1 << x11_kbd_ctrl_mod); + if ((in & ECORE_X_MODIFIER_ALT) && x11_kbd_alt_mod != XKB_MOD_INVALID) + ret |= (1 << x11_kbd_alt_mod); + if ((in & ECORE_X_LOCK_NUM) && x11_kbd_mod2_mod != XKB_MOD_INVALID) + ret |= (1 << x11_kbd_mod2_mod); + if ((in & ECORE_X_LOCK_SCROLL) && x11_kbd_mod3_mod != XKB_MOD_INVALID) + ret |= (1 << x11_kbd_mod3_mod); + if ((in & ECORE_X_MODIFIER_WIN) && x11_kbd_super_mod != XKB_MOD_INVALID) + ret |= (1 << x11_kbd_super_mod); + if ((in & ECORE_X_MODIFIER_ALTGR) && x11_kbd_mod5_mod != XKB_MOD_INVALID) + ret |= (1 << x11_kbd_mod5_mod); + + return ret; +} + +#endif |