efl/src/lib/efl_canvas_wl/copiedfromweston.x

414 lines
13 KiB
Plaintext

/*
* 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