summaryrefslogtreecommitdiff
path: root/src/lib/efl_wl
diff options
context:
space:
mode:
authorMike Blumenkrantz <zmike@samsung.com>2020-03-12 12:16:14 -0400
committerMike Blumenkrantz <zmike@samsung.com>2020-03-12 12:17:07 -0400
commit42480c5ebf32be52c3d5c5e484d5e8d5eac92fcb (patch)
tree542827db310ea02cbfcc1224c090d0e4dc2caf99 /src/lib/efl_wl
parentd284d19429d482dd0636b1f1aab8b5502c572975 (diff)
efl-wl: rename to efl.canvas.wl
Summary: this is a canvas object so it needs to be in the canvas namespace Depends on D11475 Reviewers: segfaultxavi, bu5hm4n Reviewed By: bu5hm4n Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D11476
Diffstat (limited to 'src/lib/efl_wl')
-rw-r--r--src/lib/efl_wl/Efl_Wl.h246
-rw-r--r--src/lib/efl_wl/copiedfromweston.x413
-rw-r--r--src/lib/efl_wl/dmabuf.c589
-rw-r--r--src/lib/efl_wl/dmabuf.h95
-rw-r--r--src/lib/efl_wl/efl_wl.c5866
-rw-r--r--src/lib/efl_wl/efl_wl.eo123
-rw-r--r--src/lib/efl_wl/efl_wl_surface.eo28
-rw-r--r--src/lib/efl_wl/meson.build60
-rw-r--r--src/lib/efl_wl/x11.x712
9 files changed, 0 insertions, 8132 deletions
diff --git a/src/lib/efl_wl/Efl_Wl.h b/src/lib/efl_wl/Efl_Wl.h
deleted file mode 100644
index d24557dc1a..0000000000
--- a/src/lib/efl_wl/Efl_Wl.h
+++ /dev/null
@@ -1,246 +0,0 @@
1#ifndef EFL_WL_H
2# define EFL_WL_H
3#include <Evas.h>
4#include <Efl_Core.h>
5
6#ifdef EAPI
7# undef EAPI
8#endif
9#ifdef EAPI_WEAK
10# undef EAPI_WEAK
11#endif
12
13# ifdef __GNUC__
14# if __GNUC__ >= 4
15# define EAPI __attribute__ ((visibility("default")))
16# define EAPI_WEAK
17# else
18# define EAPI
19# define EAPI_WEAK
20# endif
21# endif
22
23#define EWAPI EAPI EAPI_WEAK
24
25
26typedef struct Efl_Wl_Wl_Surface Efl_Wl_Wl_Surface;
27typedef struct Efl_Wl_Wl_Global Efl_Wl_Wl_Global;
28typedef struct Efl_Wl_Wl_Interface Efl_Wl_Wl_Interface;
29typedef struct Efl_Wl_Wl_Array Efl_Wl_Wl_Array;
30typedef void * Efl_Wl_Wl_Interface_Data;
31typedef void * Efl_Wl_Wl_Interface_Bind_Cb;
32typedef struct Efl_Wl_Xkb_State Efl_Wl_Xkb_State;
33
34#include <efl_wl_surface.eo.h>
35#include <efl_wl.eo.h>
36/**
37 * @defgroup Efl_Wl_Group EFL Wayland
38 *
39 * A multiseat xdg-shell compliant Wayland compositor in an Evas object.
40 * All toplevel windows will be sized to the size of the compositor object.
41 * @since 1.20
42 * @{
43 */
44#if 0
45/**
46 * Add a compositor widget to the given canvas.
47 *
48 * The following smart callbacks will trigger on the compositor object:
49 * "toplevel_added" - A toplevel surface has been added; event info is Evas_Object *surface @since 1.24
50 * "child_added" - A toplevel surface with a parent has been added; event info is Evas_Object *surface
51 * "popup_added" - A popup surface has been added; event info is Evas_Object *surface
52 * "seat_added" - A compositor seat has been added; event info is Eo *dev
53 *
54 * @param e The canvas
55 * @return The compositor object, @c NULL on failure
56 */
57EAPI Evas_Object *efl_wl_add(Evas *e);
58
59/**
60 * Run a command in the compositor widget.
61 *
62 * @note If GL is available, the ELM_ACCEL environment variable will be
63 * set to "gl" while executing the command.
64 *
65 * @param obj The compositor widget
66 * @param cmd The command to run
67 * @return The Ecore_Exe from the executed process, @c NULL on failure
68 */
69EAPI Ecore_Exe *efl_wl_run(Evas_Object *obj, const char *cmd);
70
71/**
72 * Run a command in the compositor widget with specified flags.
73 *
74 * @note If GL is available, the ELM_ACCEL environment variable will be
75 * set to "gl" while executing the command.
76 *
77 * @param obj The compositor widget
78 * @param cmd The command to run
79 * @param flags The flags to use
80 * @return The Ecore_Exe from the executed process, @c NULL on failure
81 */
82Ecore_Exe *efl_wl_flags_run(Evas_Object *obj, const char *cmd, Ecore_Exe_Flags flags);
83
84/**
85 * Add a process to the list of allowed clients for the compositor widget
86 *
87 * @param obj The compositor widget
88 * @param pid The process to allow
89 * @since 1.21
90 */
91EAPI void efl_wl_pid_add(Evas_Object *obj, int32_t pid);
92
93/**
94 * Remove a process from the list of allowed clients for the compositor widget
95 *
96 * @param obj The compositor widget
97 * @param pid The process to deny
98 * @since 1.21
99 */
100EAPI void efl_wl_pid_del(Evas_Object *obj, int32_t pid);
101
102/**
103 * Put the bottom-most toplevel window on top and apply focus to it
104 *
105 * @param obj The compositor widget
106 * @return EINA_TRUE if the window stacking was changed
107 */
108EAPI Eina_Bool efl_wl_surface_next(Evas_Object *obj);
109
110/**
111 * Put the second top-most toplevel window on top and apply focus to it
112 *
113 * @param obj The compositor widget
114 * @return EINA_TRUE if the window stacking was changed
115 */
116EAPI Eina_Bool efl_wl_surface_prev(Evas_Object *obj);
117
118/**
119 * Set rotation and flip for the compositor's output
120 *
121 * @param obj The compositor widget
122 * @param rot The rotation to apply
123 * @param rtl If set, the output will apply a flip around the Y axis
124 * @note rtl is equivalent to WL_OUTPUT_TRANSFORM_FLIPPED and rotations are applied
125 * on top
126 */
127EAPI void efl_wl_rotate(Evas_Object *obj, Efl_Wl_Rotation rot, Eina_Bool rtl);
128
129/**
130 * Set the scale factor for the compositor's output
131 *
132 * @param obj The compositor widget
133 * @param scale The scale factor to set
134 */
135EAPI void efl_wl_scale_set(Evas_Object *obj, double scale);
136
137/**
138 * Transfer aspect hints from top-most surface onto the efl_wl object
139 *
140 * @param obj The compositor widget
141 * @param set Whether to enable aspect setting
142 * @since 1.21
143 */
144EAPI void efl_wl_aspect_set(Evas_Object *obj, Eina_Bool set);
145
146/**
147 * Transfer min/max hints from top-most surface onto the efl_wl object
148 *
149 * @param obj The compositor widget
150 * @param set Whether to enable min/max setting
151 * @since 1.21
152 */
153EAPI void efl_wl_minmax_set(Evas_Object *obj, Eina_Bool set);
154
155/**
156 * Add an externally-managed global to the compositor
157 * @note The external implementation is expected to restrict access to authorized
158 * clients
159 * @see wl_global_create() docs
160 *
161 * @param obj The compositor widget
162 * @param interface The Wayland protocol interface struct of the protocol's global
163 * @param version The version of the global to use
164 * @param data User data to use with this interface
165 * @param bind_cb The callback which should be triggered when the global is bound by a client
166 * @return The created global (struct wl_global), or NULL on failure
167 * @since 1.21
168 */
169EAPI void *efl_wl_global_add(Evas_Object *obj, const void *interface, uint32_t version, void *data, void *bind_cb);
170
171/**
172 * Extract a child surface from the compositor
173 *
174 * An extracted surface can be freely manipulated by external code.
175 * @note size hints must be respected, and the extracted object must not be externally deleted
176 *
177 * @param surface The surface to extract
178 * @return True if the surface was successfully extracted
179 * @since 1.21
180 */
181EAPI Eina_Bool efl_wl_surface_extract(Evas_Object *surface);
182
183/**
184 * Return the pid for the surface's client
185 *
186 * Get the pid of the underlying client that created the surface.
187 *
188 * @param surface The surface to extract
189 * @return The pid of the surface, or -1 on failure
190 * @since 1.24
191 */
192EAPI int32_t efl_wl_surface_pid_get(Evas_Object *surface);
193#endif
194/**
195 * Get the Evas_Object for an extracted wl_surface resource created by an efl_wl object
196 *
197 * @note Passing anything other than a valid wl_surface resource from an efl_wl object will guarantee a crash.
198 *
199 * @param surface_resource The wl_resource for a wl_surface
200 * @return The Evas_Object of the surface, NULL on failure
201 * @since 1.21
202 */
203EAPI Evas_Object *efl_wl_extracted_surface_object_find(void *surface_resource);
204#if 0
205/**
206 * Get the Evas_Object for an extracted surface's parent, or NULL if the parent is not extracted
207 *
208 * @note Passing anything other than a valid, extracted surface guarantees a crash.
209 *
210 * @param surface The extracted surface for a wl_surface
211 * @return The Evas_Object of the parent surface, NULL on failure or if there is no parent
212 * @since 1.21
213 */
214EAPI Evas_Object *efl_wl_extracted_surface_extracted_parent_get(Evas_Object *surface);
215
216/**
217 * Set external xkbcommon resources to be used read-only by the compositor object
218 *
219 * Use this function if you have available the necessary xkbcommon objects which are used
220 * to handle keyboard states in a compositor. The passed objects will not be modified or copied,
221 * so this function must be called again in the case that the compositor widget outlives the
222 * lifetime of any of the passed pointers.
223 *
224 * @param obj The compositor widget
225 * @param seat The seat to set the keymap for, NULL to set the keymap for all seats
226 * @param keymap The xkb_keymap object to use
227 * @param state The xkb_state object to use
228 * @param str The string containing the keymap
229 * @param wl_key_array A pointer to the wl_array in which keys are stored
230 * @since 1.21
231 */
232EAPI void efl_wl_seat_keymap_set(Evas_Object *obj, Eo *seat, void *state, char *str, void *wl_key_array);
233
234/**
235 * Set the key repeat rate for a seat in the compositor
236 *
237 * @param obj The compositor widget
238 * @since 1.21
239 */
240EAPI void efl_wl_seat_key_repeat_set(Evas_Object *obj, Eo *seat, int repeat_rate, int repeat_delay);
241#endif
242#undef EAPI
243#define EAPI
244#undef EAPI_WEAK
245#define EAPI_WEAK
246#endif
diff --git a/src/lib/efl_wl/copiedfromweston.x b/src/lib/efl_wl/copiedfromweston.x
deleted file mode 100644
index d5c35eee75..0000000000
--- a/src/lib/efl_wl/copiedfromweston.x
+++ /dev/null
@@ -1,413 +0,0 @@
1/*
2 * Copyright © 2011 Kristian Høgsberg
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
26#define ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \
27 WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \
28 WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
29
30static uint32_t
31data_offer_choose_action(Comp_Data_Device_Offer *offer)
32{
33 uint32_t available_actions, preferred_action = 0;
34 uint32_t source_actions, offer_actions;
35
36 if (wl_resource_get_version(offer->res) >=
37 WL_DATA_OFFER_ACTION_SINCE_VERSION)
38 {
39 offer_actions = offer->dnd_actions;
40 preferred_action = offer->preferred_dnd_action;
41 }
42 else
43 {
44 offer_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
45 }
46
47 if (wl_resource_get_version(offer->source->res) >=
48 WL_DATA_SOURCE_ACTION_SINCE_VERSION)
49 source_actions = offer->source->dnd_actions;
50 else
51 source_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
52
53 available_actions = offer_actions & source_actions;
54
55 if (!available_actions)
56 return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
57
58 if (offer->source->seat &&
59 offer->source->compositor_action & available_actions)
60 return offer->source->compositor_action;
61
62 /* If the dest side has a preferred DnD action, use it */
63 if ((preferred_action & available_actions) != 0)
64 return preferred_action;
65
66 /* Use the first found action, in bit order */
67 return 1 << (ffs(available_actions) - 1);
68}
69
70static void
71data_offer_update_action(Comp_Data_Device_Offer *offer)
72{
73 uint32_t action;
74
75 if (!offer->source)
76 return;
77
78 action = data_offer_choose_action(offer);
79
80 if (offer->source->current_dnd_action == action)
81 return;
82
83 offer->source->current_dnd_action = action;
84
85 if (offer->in_ask)
86 return;
87
88 if (wl_resource_get_version(offer->source->res) >=
89 WL_DATA_SOURCE_ACTION_SINCE_VERSION)
90 wl_data_source_send_action(offer->source->res, action);
91
92 if (wl_resource_get_version(offer->res) >=
93 WL_DATA_OFFER_ACTION_SINCE_VERSION)
94 wl_data_offer_send_action(offer->res, action);
95}
96
97static void
98data_device_offer_set_actions(struct wl_client *client,
99 struct wl_resource *resource,
100 uint32_t dnd_actions, uint32_t preferred_action)
101{
102 Comp_Data_Device_Offer *offer = wl_resource_get_user_data(resource);
103
104 if (dnd_actions & ~ALL_ACTIONS)
105 {
106 wl_resource_post_error(offer->res,
107 WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK,
108 "invalid action mask %x", dnd_actions);
109 return;
110 }
111
112 if (preferred_action &&
113 (!(preferred_action & dnd_actions) ||
114 __builtin_popcount(preferred_action) > 1))
115 {
116 wl_resource_post_error(offer->res,
117 WL_DATA_OFFER_ERROR_INVALID_ACTION,
118 "invalid action %x", preferred_action);
119 return;
120 }
121
122 offer->dnd_actions = dnd_actions;
123 offer->preferred_dnd_action = preferred_action;
124 data_offer_update_action(offer);
125}
126
127#ifdef HAVE_ECORE_X
128static Ecore_X_Atom
129action_convert(uint32_t action)
130{
131 if (action == WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
132 return ECORE_X_ATOM_XDND_ACTION_MOVE;
133 if (action == WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
134 return ECORE_X_ATOM_XDND_ACTION_ASK;
135 return ECORE_X_ATOM_XDND_ACTION_COPY;
136}
137#endif
138static void
139data_device_offer_accept(struct wl_client *client, struct wl_resource *resource,
140 uint32_t serial, const char *mime_type)
141{
142 Comp_Data_Device_Offer *offer = wl_resource_get_user_data(resource);
143 Comp_Surface *cs;
144
145 /* Protect against untimely calls from older data offers */
146 if (!offer->source || offer != offer->source->offer)
147 return;
148
149 switch (offer->type)
150 {
151 case COMP_DATA_DEVICE_OFFER_TYPE_DND:
152 cs = offer->source->seat->drag.enter;
153 if (!offer->source->seat->drag.res) return;
154 if ((!offer->source->seat->drag.source) &&
155 (wl_resource_get_client(cs->res) != wl_resource_get_client(offer->source->seat->drag.res)))
156 return;
157#ifdef HAVE_ECORE_X
158 if (offer->source->x11_owner)
159 {
160 Ecore_Window win = ecore_evas_window_get(ecore_evas_ecore_evas_get(offer->source->seat->c->evas));
161 offer->source->accepted = mime_type != NULL;
162 ecore_x_client_message32_send(offer->source->x11_owner,
163 ECORE_X_ATOM_XDND_STATUS, ECORE_X_EVENT_MASK_NONE,
164 win, 2 | !!mime_type, 0, 0,
165 (!!mime_type) * action_convert(offer->source->current_dnd_action));
166 return;
167 }
168#endif
169 break;
170
171 case COMP_DATA_DEVICE_OFFER_TYPE_CLIPBOARD:
172 break;
173 default: return;
174 }
175 if (offer->source->seat->client_offer)
176 ecore_wl2_offer_accept(offer->source->seat->client_offer, mime_type);
177 else
178 wl_data_source_send_target(offer->source->res, mime_type);
179 offer->source->accepted = mime_type != NULL;
180}
181
182static void
183data_device_offer_receive(struct wl_client *client, struct wl_resource *resource,
184 const char *mime_type, int32_t fd)
185{
186 Comp_Data_Device_Offer *offer = wl_resource_get_user_data(resource);
187
188 if (offer->source && offer == offer->source->offer)
189 {
190 if (offer->proxy)
191 {
192 Ecore_Wl2_Offer *off;
193#ifdef HAVE_ECORE_X
194 if (offer->source->x11_owner)
195 {
196 x11_send_send(offer->source, mime_type, fd, offer->type);
197 return;
198 }
199#endif
200 if (offer->type == COMP_DATA_DEVICE_OFFER_TYPE_CLIPBOARD)
201 off = ecore_wl2_dnd_selection_get(offer->source->seat->seat);
202 else
203 {
204 off = offer->source->seat->client_offer;
205 offer->source->seat->client_offer = NULL;
206 }
207 ecore_wl2_offer_proxy_receive(off, mime_type, fd);
208 offer->proxy_offer = off;
209 }
210 else
211 wl_data_source_send_send(offer->source->res, mime_type, fd);
212 }
213 close(fd);
214}
215
216static void
217data_source_notify_finish(Comp_Data_Device_Source *source)
218{
219 if (!source->actions_set)
220 return;
221
222 if (source->proxy && (!source->x11_owner))
223 ecore_wl2_offer_finish(source->offer->proxy_offer);
224
225 if (source->offer && source->offer->in_ask &&
226 wl_resource_get_version(source->res) >=
227 WL_DATA_SOURCE_ACTION_SINCE_VERSION)
228 {
229 wl_data_source_send_action(source->res,
230 source->current_dnd_action);
231 }
232
233 if (wl_resource_get_version(source->res) >=
234 WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION)
235 {
236 wl_data_source_send_dnd_finished(source->res);
237 }
238
239 source->offer = NULL;
240}
241
242static void
243data_device_offer_finish(struct wl_client *client, struct wl_resource *resource)
244{
245 Comp_Data_Device_Offer *offer = wl_resource_get_user_data(resource);
246
247 if (!offer->source || offer->source->offer != offer)
248 return;
249
250 /* Disallow finish while we have a grab driving drag-and-drop, or
251 * if the negotiation is not at the right stage
252 */
253 if (((!offer->proxy) && offer->source->seat) ||
254 !offer->source->accepted)
255 {
256 wl_resource_post_error(offer->res,
257 WL_DATA_OFFER_ERROR_INVALID_FINISH,
258 "premature finish request");
259 return;
260 }
261
262 switch (offer->source->current_dnd_action)
263 {
264 case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE:
265 case WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK:
266 wl_resource_post_error(offer->res,
267 WL_DATA_OFFER_ERROR_INVALID_OFFER,
268 "offer finished with an invalid action");
269 return;
270
271 default:
272 break;
273 }
274
275 data_source_notify_finish(offer->source);
276}
277
278static void
279data_device_offer_impl_destroy(struct wl_resource *resource)
280{
281 Comp_Data_Device_Offer *offer = wl_resource_get_user_data(resource);
282
283 if (!offer->source)
284 goto out;
285
286 if (offer->source->offer != offer)
287 goto out;
288
289 if (offer->type == COMP_DATA_DEVICE_OFFER_TYPE_DND)
290 {
291 /* If the drag destination has version < 3, wl_data_offer.finish
292 * won't be called, so do this here as a safety net, because
293 * we still want the version >=3 drag source to be happy.
294 */
295 if (wl_resource_get_version(offer->res) <
296 WL_DATA_OFFER_ACTION_SINCE_VERSION)
297 {
298 data_source_notify_finish(offer->source);
299 }
300 else if (offer->source->res &&
301 wl_resource_get_version(offer->source->res) >=
302 WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION)
303 {
304 wl_data_source_send_cancelled(offer->source->res);
305 }
306 }
307
308 offer->source->offer = NULL;
309 if (offer->proxy_offer && offer->proxy)
310 ecore_wl2_offer_proxy_receive_end(offer->proxy_offer);
311out:
312 free(offer);
313}
314
315static void
316drag_grab_button(Comp_Seat *s,
317 uint32_t time, uint32_t button, uint32_t state_w)
318{
319 Comp_Data_Device_Source *data_source = s->drag.source;
320 enum wl_pointer_button_state state = state_w;
321 struct wl_resource *res;
322
323 if (data_source &&
324 s->drag.id == button &&
325 state == WL_POINTER_BUTTON_STATE_RELEASED)
326 {
327 if ((s->drag.enter || (s->drag.x11_owner == ecore_evas_window_get(ecore_evas_ecore_evas_get(s->c->evas)))) &&
328 data_source->accepted &&
329 data_source->current_dnd_action)
330 {
331 if (s->drag.enter)
332 {
333 res = data_device_find(s, s->drag.enter->res);
334 if (!res) return;
335
336 wl_data_device_send_drop(res);
337 }
338 if (wl_resource_get_version(data_source->res) >=
339 WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION)
340 wl_data_source_send_dnd_drop_performed(data_source->res);
341
342 if (data_source->offer)
343 data_source->offer->in_ask =
344 data_source->current_dnd_action ==
345 WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
346
347 if (!data_source->proxy)
348 data_source->seat = NULL;
349 }
350 else if (wl_resource_get_version(data_source->res) >=
351 WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION)
352 {
353 wl_data_source_send_cancelled(data_source->res);
354 }
355 seat_drag_end(s);
356 if (!data_source->x11_owner)
357 s->drag.source = NULL;
358#ifdef HAVE_ECORE_X
359 if (ecore_x_display_get())
360 ecore_x_pointer_ungrab();
361#endif
362 }
363}
364
365#ifdef HAVE_ECORE_X
366static xkb_mod_index_t x11_kbd_shift_mod;
367static xkb_mod_index_t x11_kbd_caps_mod;
368static xkb_mod_index_t x11_kbd_ctrl_mod;
369static xkb_mod_index_t x11_kbd_alt_mod;
370static xkb_mod_index_t x11_kbd_mod2_mod;
371static xkb_mod_index_t x11_kbd_mod3_mod;
372static xkb_mod_index_t x11_kbd_super_mod;
373static xkb_mod_index_t x11_kbd_mod5_mod;
374
375static void
376keymap_mods_init(struct xkb_keymap *keymap)
377{
378 x11_kbd_shift_mod = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT);
379 x11_kbd_caps_mod = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS);
380 x11_kbd_ctrl_mod = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL);
381 x11_kbd_alt_mod = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_ALT);
382 x11_kbd_mod2_mod = xkb_keymap_mod_get_index(keymap, "Mod2");
383 x11_kbd_mod3_mod = xkb_keymap_mod_get_index(keymap, "Mod3");
384 x11_kbd_super_mod = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_LOGO);
385 x11_kbd_mod5_mod = xkb_keymap_mod_get_index(keymap, "Mod5");
386}
387
388static uint32_t
389get_xkb_mod_mask(uint32_t in)
390{
391 uint32_t ret = 0;
392
393 if ((in & ECORE_X_MODIFIER_SHIFT) && x11_kbd_shift_mod != XKB_MOD_INVALID)
394 ret |= (1 << x11_kbd_shift_mod);
395 if ((in & ECORE_X_LOCK_CAPS) && x11_kbd_caps_mod != XKB_MOD_INVALID)
396 ret |= (1 << x11_kbd_caps_mod);
397 if ((in & ECORE_X_MODIFIER_CTRL) && x11_kbd_ctrl_mod != XKB_MOD_INVALID)
398 ret |= (1 << x11_kbd_ctrl_mod);
399 if ((in & ECORE_X_MODIFIER_ALT) && x11_kbd_alt_mod != XKB_MOD_INVALID)
400 ret |= (1 << x11_kbd_alt_mod);
401 if ((in & ECORE_X_LOCK_NUM) && x11_kbd_mod2_mod != XKB_MOD_INVALID)
402 ret |= (1 << x11_kbd_mod2_mod);
403 if ((in & ECORE_X_LOCK_SCROLL) && x11_kbd_mod3_mod != XKB_MOD_INVALID)
404 ret |= (1 << x11_kbd_mod3_mod);
405 if ((in & ECORE_X_MODIFIER_WIN) && x11_kbd_super_mod != XKB_MOD_INVALID)
406 ret |= (1 << x11_kbd_super_mod);
407 if ((in & ECORE_X_MODIFIER_ALTGR) && x11_kbd_mod5_mod != XKB_MOD_INVALID)
408 ret |= (1 << x11_kbd_mod5_mod);
409
410 return ret;
411}
412
413#endif
diff --git a/src/lib/efl_wl/dmabuf.c b/src/lib/efl_wl/dmabuf.c
deleted file mode 100644
index 273d141b05..0000000000
--- a/src/lib/efl_wl/dmabuf.c
+++ /dev/null
@@ -1,589 +0,0 @@
1/* Shamelessly stolen from weston and modified, original license boiler plate
2 * follows.
3 */
4
5#if defined(__clang__)
6# pragma clang diagnostic ignored "-Wunused-parameter"
7#elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4
8# pragma GCC diagnostic ignored "-Wunused-parameter"
9#endif
10
11
12/*
13 * Copyright © 2014, 2015 Collabora, Ltd.
14 *
15 * Permission to use, copy, modify, distribute, and sell this software and
16 * its documentation for any purpose is hereby granted without fee, provided
17 * that the above copyright notice appear in all copies and that both that
18 * copyright notice and this permission notice appear in supporting
19 * documentation, and that the name of the copyright holders not be used in
20 * advertising or publicity pertaining to distribution of the software
21 * without specific, written prior permission. The copyright holders make
22 * no representations about the suitability of this software for any
23 * purpose. It is provided "as is" without express or implied warranty.
24 *
25 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
26 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
27 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
28 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
29 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
30 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
31 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
32 */
33
34#include <sys/mman.h>
35
36#include <assert.h>
37
38#include "linux-dmabuf-unstable-v1-server-protocol.h"
39#include <stdlib.h>
40#include <stdio.h>
41#include <unistd.h>
42#include "dmabuf.h"
43#include <Eina.h>
44
45__attribute__ ((visibility("hidden"))) Eina_Bool comp_dmabuf_test(struct linux_dmabuf_buffer *dmabuf);
46__attribute__ ((visibility("hidden"))) void comp_dmabuf_formats_query(void *c, int **formats, int *num_formats);
47__attribute__ ((visibility("hidden"))) void comp_dmabuf_modifiers_query(void *c, int format, uint64_t **modifiers, int *num_modifiers);
48
49static void
50linux_dmabuf_buffer_destroy(struct linux_dmabuf_buffer *buffer)
51{
52 int i;
53
54 for (i = 0; i < buffer->attributes.n_planes; i++) {
55 close(buffer->attributes.fd[i]);
56 buffer->attributes.fd[i] = -1;
57 }
58
59 buffer->attributes.n_planes = 0;
60 free(buffer);
61}
62
63static void
64destroy_params(struct wl_resource *params_resource)
65{
66 struct linux_dmabuf_buffer *buffer;
67
68 buffer = wl_resource_get_user_data(params_resource);
69
70 if (!buffer)
71 return;
72
73 linux_dmabuf_buffer_destroy(buffer);
74}
75
76static void
77params_destroy(struct wl_client *client, struct wl_resource *resource)
78{
79 wl_resource_destroy(resource);
80}
81
82static void
83params_add(struct wl_client *client,
84 struct wl_resource *params_resource,
85 int32_t name_fd,
86 uint32_t plane_idx,
87 uint32_t offset,
88 uint32_t stride,
89 uint32_t modifier_hi,
90 uint32_t modifier_lo)
91{
92 struct linux_dmabuf_buffer *buffer;
93
94 buffer = wl_resource_get_user_data(params_resource);
95 if (!buffer) {
96 wl_resource_post_error(params_resource,
97 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
98 "params was already used to create a wl_buffer");
99 close(name_fd);
100 return;
101 }
102
103 assert(buffer->params_resource == params_resource);
104 assert(!buffer->buffer_resource);
105
106 if (plane_idx >= MAX_DMABUF_PLANES) {
107 wl_resource_post_error(params_resource,
108 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX,
109 "plane index %u is too high", plane_idx);
110 close(name_fd);
111 return;
112 }
113
114 if (buffer->attributes.fd[plane_idx] != -1) {
115 wl_resource_post_error(params_resource,
116 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET,
117 "a dmabuf has already been added for plane %u",
118 plane_idx);
119 close(name_fd);
120 return;
121 }
122
123 buffer->attributes.fd[plane_idx] = name_fd;
124 buffer->attributes.offset[plane_idx] = offset;
125 buffer->attributes.stride[plane_idx] = stride;
126 buffer->attributes.modifier[plane_idx] = ((uint64_t)modifier_hi << 32) |
127 modifier_lo;
128 buffer->attributes.n_planes++;
129}
130
131static void
132linux_dmabuf_wl_buffer_destroy(struct wl_client *client,
133 struct wl_resource *resource)
134{
135 wl_resource_destroy(resource);
136}
137
138static const struct wl_buffer_interface linux_dmabuf_buffer_implementation = {
139 linux_dmabuf_wl_buffer_destroy
140};
141
142static void
143destroy_linux_dmabuf_wl_buffer(struct wl_resource *resource)
144{
145 struct linux_dmabuf_buffer *buffer;
146
147 buffer = wl_resource_get_user_data(resource);
148 assert(buffer->buffer_resource == resource);
149 assert(!buffer->params_resource);
150
151 if (buffer->user_data_destroy_func)
152 buffer->user_data_destroy_func(buffer);
153
154 linux_dmabuf_buffer_destroy(buffer);
155}
156
157static void
158params_create_common(struct wl_client *client,
159 struct wl_resource *params_resource,
160 uint32_t buffer_id,
161 int32_t width,
162 int32_t height,
163 uint32_t format,
164 uint32_t flags)
165{
166 struct linux_dmabuf_buffer *buffer;
167 int i;
168
169 buffer = wl_resource_get_user_data(params_resource);
170
171 if (!buffer) {
172 wl_resource_post_error(params_resource,
173 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
174 "params was already used to create a wl_buffer");
175 return;
176 }
177
178 assert(buffer->params_resource == params_resource);
179 assert(!buffer->buffer_resource);
180
181 /* Switch the linux_dmabuf_buffer object from params resource to
182 * eventually wl_buffer resource.
183 */
184 wl_resource_set_user_data(buffer->params_resource, NULL);
185 buffer->params_resource = NULL;
186
187 if (!buffer->attributes.n_planes) {
188 wl_resource_post_error(params_resource,
189 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
190 "no dmabuf has been added to the params");
191 goto err_out;
192 }
193
194 /* Check for holes in the dmabufs set (e.g. [0, 1, 3]) */
195 for (i = 0; i < buffer->attributes.n_planes; i++) {
196 if (buffer->attributes.fd[i] == -1) {
197 wl_resource_post_error(params_resource,
198 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
199 "no dmabuf has been added for plane %i", i);
200 goto err_out;
201 }
202 }
203
204 buffer->attributes.version = 1;
205 buffer->attributes.width = width;
206 buffer->attributes.height = height;
207 buffer->attributes.format = format;
208 buffer->attributes.flags = flags;
209
210 if (width < 1 || height < 1) {
211 wl_resource_post_error(params_resource,
212 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS,
213 "invalid width %d or height %d", width, height);
214 goto err_out;
215 }
216
217 for (i = 0; i < buffer->attributes.n_planes; i++) {
218 off_t size;
219
220 if ((uint64_t) buffer->attributes.offset[i] + buffer->attributes.stride[i] > UINT32_MAX) {
221 wl_resource_post_error(params_resource,
222 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
223 "size overflow for plane %i", i);
224 goto err_out;
225 }
226
227 if (i == 0 &&
228 (uint64_t) buffer->attributes.offset[i] +
229 (uint64_t) buffer->attributes.stride[i] * height > UINT32_MAX) {
230 wl_resource_post_error(params_resource,
231 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
232 "size overflow for plane %i", i);
233 goto err_out;
234 }
235
236 /* Don't report an error as it might be caused
237 * by the kernel not supporting seeking on dmabuf */
238 size = lseek(buffer->attributes.fd[i], 0, SEEK_END);
239 if (size == -1)
240 continue;
241
242 if (buffer->attributes.offset[i] >= size) {
243 wl_resource_post_error(params_resource,
244 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
245 "invalid offset %i for plane %i",
246 buffer->attributes.offset[i], i);
247 goto err_out;
248 }
249
250 if (buffer->attributes.offset[i] + buffer->attributes.stride[i] > size) {
251 wl_resource_post_error(params_resource,
252 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
253 "invalid stride %i for plane %i",
254 buffer->attributes.stride[i], i);
255 goto err_out;
256 }
257
258 /* Only valid for first plane as other planes might be
259 * sub-sampled according to fourcc format */
260 if (i == 0 &&
261 buffer->attributes.offset[i] + buffer->attributes.stride[i] * height > size) {
262 wl_resource_post_error(params_resource,
263 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
264 "invalid buffer stride or height for plane %i", i);
265 goto err_out;
266 }
267 }
268
269 /* XXX: Some additional sanity checks could be done with respect
270 * to the fourcc format. A centralized collection (kernel or
271 * libdrm) would be useful to avoid code duplication for these
272 * checks (e.g. drm_format_num_planes).
273 */
274
275 if (!comp_dmabuf_test(buffer))
276 goto err_failed;
277
278 buffer->buffer_resource = wl_resource_create(client,
279 &wl_buffer_interface,
280 1, buffer_id);
281 if (!buffer->buffer_resource) {
282 wl_resource_post_no_memory(params_resource);
283 goto err_buffer;
284 }
285
286 wl_resource_set_implementation(buffer->buffer_resource,
287 &linux_dmabuf_buffer_implementation,
288 buffer, destroy_linux_dmabuf_wl_buffer);
289
290 /* send 'created' event when the request is not for an immediate
291 * import, ie buffer_id is zero */
292 if (buffer_id == 0)
293 zwp_linux_buffer_params_v1_send_created(params_resource,
294 buffer->buffer_resource);
295
296 return;
297
298err_buffer:
299 if (buffer->user_data_destroy_func)
300 buffer->user_data_destroy_func(buffer);
301
302err_failed:
303 if (buffer_id == 0)
304 zwp_linux_buffer_params_v1_send_failed(params_resource);
305 else
306 /* since the behavior is left implementation defined by the
307 * protocol in case of create_immed failure due to an unknown cause,
308 * we choose to treat it as a fatal error and immediately kill the
309 * client instead of creating an invalid handle and waiting for it
310 * to be used.
311 */
312 wl_resource_post_error(params_resource,
313 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER,
314 "importing the supplied dmabufs failed");
315
316err_out:
317 linux_dmabuf_buffer_destroy(buffer);
318}
319
320static void
321params_create(struct wl_client *client,
322 struct wl_resource *params_resource,
323 int32_t width,
324 int32_t height,
325 uint32_t format,
326 uint32_t flags)
327{
328 params_create_common(client, params_resource, 0, width, height, format,
329 flags);
330}
331
332static void
333params_create_immed(struct wl_client *client,
334 struct wl_resource *params_resource,
335 uint32_t buffer_id,
336 int32_t width,
337 int32_t height,
338 uint32_t format,
339 uint32_t flags)
340{
341 params_create_common(client, params_resource, buffer_id, width, height,
342 format, flags);
343}
344
345static const struct zwp_linux_buffer_params_v1_interface
346zwp_linux_buffer_params_implementation = {
347 params_destroy,
348 params_add,
349 params_create,
350 params_create_immed
351};
352
353static void
354linux_dmabuf_destroy(struct wl_client *client, struct wl_resource *resource)
355{
356 wl_resource_destroy(resource);
357}
358
359static void
360linux_dmabuf_create_params(struct wl_client *client,
361 struct wl_resource *linux_dmabuf_resource,
362 uint32_t params_id)
363{
364 void *compositor;
365 struct linux_dmabuf_buffer *buffer;
366 uint32_t version;
367 int i;
368
369 version = wl_resource_get_version(linux_dmabuf_resource);
370 compositor = wl_resource_get_user_data(linux_dmabuf_resource);
371
372 buffer = calloc(1, sizeof *buffer);
373 if (!buffer)
374 goto err_out;
375
376 for (i = 0; i < MAX_DMABUF_PLANES; i++)
377 buffer->attributes.fd[i] = -1;
378
379 buffer->compositor = compositor;
380 buffer->params_resource =
381 wl_resource_create(client,
382 &zwp_linux_buffer_params_v1_interface,
383 version, params_id);
384 if (!buffer->params_resource)
385 goto err_dealloc;
386
387 wl_resource_set_implementation(buffer->params_resource,
388 &zwp_linux_buffer_params_implementation,
389 buffer, destroy_params);
390
391 return;
392
393err_dealloc:
394 free(buffer);
395
396err_out:
397 wl_resource_post_no_memory(linux_dmabuf_resource);
398}
399
400/** Get the linux_dmabuf_buffer from a wl_buffer resource
401 *
402 * If the given wl_buffer resource was created through the linux_dmabuf
403 * protocol interface, returns the linux_dmabuf_buffer object. This can
404 * be used as a type check for a wl_buffer.
405 *
406 * \param resource A wl_buffer resource.
407 * \return The linux_dmabuf_buffer if it exists, or NULL otherwise.
408 */
409struct linux_dmabuf_buffer *
410linux_dmabuf_buffer_get(struct wl_resource *resource)
411{
412 struct linux_dmabuf_buffer *buffer;
413
414 if (!resource)
415 return NULL;
416
417 if (!wl_resource_instance_of(resource, &wl_buffer_interface,
418 &linux_dmabuf_buffer_implementation))
419 return NULL;
420
421 buffer = wl_resource_get_user_data(resource);
422 assert(buffer);
423 assert(!buffer->params_resource);
424 assert(buffer->buffer_resource == resource);
425
426 return buffer;
427}
428
429/** Set renderer-private data
430 *
431 * Set the user data for the linux_dmabuf_buffer. It is invalid to overwrite
432 * a non-NULL user data with a new non-NULL pointer. This is meant to
433 * protect against renderers fighting over linux_dmabuf_buffer user data
434 * ownership.
435 *
436 * The renderer-private data is usually set from the
437 * weston_renderer::import_dmabuf hook.
438 *
439 * \param buffer The linux_dmabuf_buffer object to set for.
440 * \param data The new renderer-private data pointer.
441 * \param func Destructor function to be called for the renderer-private
442 * data when the linux_dmabuf_buffer gets destroyed.
443 *
444 * \sa weston_compositor_import_dmabuf
445 */
446void
447linux_dmabuf_buffer_set_user_data(struct linux_dmabuf_buffer *buffer,
448 void *data,
449 dmabuf_user_data_destroy_func func)
450{
451 assert(data == NULL || buffer->user_data == NULL);
452
453 buffer->user_data = data;
454 buffer->user_data_destroy_func = func;
455}
456
457/** Get renderer-private data
458 *
459 * Get the user data from the linux_dmabuf_buffer.
460 *
461 * \param buffer The linux_dmabuf_buffer to query.
462 * \return Renderer-private data pointer.
463 *
464 * \sa linux_dmabuf_buffer_set_user_data
465 */
466void *
467linux_dmabuf_buffer_get_user_data(struct linux_dmabuf_buffer *buffer)
468{
469 return buffer->user_data;
470}
471
472static const struct zwp_linux_dmabuf_v1_interface linux_dmabuf_implementation = {
473 linux_dmabuf_destroy,
474 linux_dmabuf_create_params
475};
476
477static void
478bind_linux_dmabuf(struct wl_client *client,
479 void *data, uint32_t version, uint32_t id)
480{
481 void *compositor = data;
482 struct wl_resource *resource;
483 int *formats = NULL;
484 uint64_t *modifiers = NULL;
485 int num_formats, num_modifiers;
486 uint64_t modifier_invalid = DRM_FORMAT_MOD_INVALID;
487 int i, j;
488
489 resource = wl_resource_create(client, &zwp_linux_dmabuf_v1_interface,
490 version, id);
491 if (resource == NULL) {
492 wl_client_post_no_memory(client);
493 return;
494 }
495
496 wl_resource_set_implementation(resource, &linux_dmabuf_implementation,
497 compositor, NULL);
498
499 if (version < ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION)
500 return;
501 /*
502 * Use EGL_EXT_image_dma_buf_import_modifiers to query and advertise
503 * format/modifier codes.
504 */
505 comp_dmabuf_formats_query(compositor, &formats,
506 &num_formats);
507
508 for (i = 0; i < num_formats; i++) {
509 comp_dmabuf_modifiers_query(compositor,
510 formats[i],
511 &modifiers,
512 &num_modifiers);
513
514 /* send DRM_FORMAT_MOD_INVALID token when no modifiers are supported
515 * for this format */
516 if (num_modifiers == 0) {
517 num_modifiers = 1;
518 modifiers = &modifier_invalid;
519 }
520 for (j = 0; j < num_modifiers; j++) {
521 uint32_t modifier_lo = modifiers[j] & 0xFFFFFFFF;
522 uint32_t modifier_hi = modifiers[j] >> 32;
523 zwp_linux_dmabuf_v1_send_modifier(resource, formats[i],
524 modifier_hi,
525 modifier_lo);
526 }
527 if (modifiers != &modifier_invalid)
528 free(modifiers);
529 }
530 free(formats);
531}
532
533/** Advertise linux_dmabuf support
534 *
535 * Calling this initializes the zwp_linux_dmabuf protocol support, so that
536 * the interface will be advertised to clients. Essentially it creates a
537 * global. Do not call this function multiple times in the compositor's
538 * lifetime. There is no way to deinit explicitly, globals will be reaped
539 * when the wl_display gets destroyed.
540 *
541 * \param compositor The compositor to init for.
542 * \return Zero on success, -1 on failure.
543 */
544int
545linux_dmabuf_setup(struct wl_display *display, void *comp)
546{
547 if (!wl_global_create(display,
548 &zwp_linux_dmabuf_v1_interface, 3,
549 comp, bind_linux_dmabuf))
550 return -1;
551
552 return 0;
553}
554
555/** Resolve an internal compositor error by disconnecting the client.
556 *
557 * This function is used in cases when the dmabuf-based wl_buffer
558 * turns out unusable and there is no fallback path. This is used by
559 * renderers which are the fallback path in the first place.
560 *
561 * It is possible the fault is caused by a compositor bug, the underlying
562 * graphics stack bug or normal behaviour, or perhaps a client mistake.
563 * In any case, the options are to either composite garbage or nothing,
564 * or disconnect the client. This is a helper function for the latter.
565 *
566 * The error is sent as an INVALID_OBJECT error on the client's wl_display.
567 *
568 * \param buffer The linux_dmabuf_buffer that is unusable.
569 * \param msg A custom error message attached to the protocol error.
570 */
571void
572linux_dmabuf_buffer_send_server_error(struct linux_dmabuf_buffer *buffer,
573 const char *msg)
574{
575 struct wl_client *client;
576 struct wl_resource *display_resource;
577 uint32_t id;
578
579 assert(buffer->buffer_resource);
580 id = wl_resource_get_id(buffer->buffer_resource);
581 client = wl_resource_get_client(buffer->buffer_resource);
582 display_resource = wl_client_get_object(client, 1);
583
584 assert(display_resource);
585 wl_resource_post_error(display_resource,
586 WL_DISPLAY_ERROR_INVALID_OBJECT,
587 "linux_dmabuf server error with "
588 "wl_buffer@%u: %s", id, msg);
589}
diff --git a/src/lib/efl_wl/dmabuf.h b/src/lib/efl_wl/dmabuf.h
deleted file mode 100644
index 72f42816a3..0000000000
--- a/src/lib/efl_wl/dmabuf.h
+++ /dev/null
@@ -1,95 +0,0 @@
1/* Shamelessly stolen from weston and modified, original license boiler plate
2 * follows.
3 */
4/*
5 * Copyright © 2014, 2015 Collabora, Ltd.
6 *
7 * Permission to use, copy, modify, distribute, and sell this software and
8 * its documentation for any purpose is hereby granted without fee, provided
9 * that the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation, and that the name of the copyright holders not be used in
12 * advertising or publicity pertaining to distribution of the software
13 * without specific, written prior permission. The copyright holders make
14 * no representations about the suitability of this software for any
15 * purpose. It is provided "as is" without express or implied warranty.
16 *
17 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
18 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
19 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
21 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
22 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
23 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 */
25
26#ifndef WESTON_LINUX_DMABUF_H
27#define WESTON_LINUX_DMABUF_H
28
29#include <stdint.h>
30
31#define MAX_DMABUF_PLANES 4
32#ifndef DRM_FORMAT_MOD_INVALID
33#define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1)
34#endif
35
36struct linux_dmabuf_buffer;
37typedef void (*dmabuf_user_data_destroy_func)(
38 struct linux_dmabuf_buffer *buffer);
39
40struct dmabuf_attributes {
41 int version;
42 int32_t width;
43 int32_t height;
44 uint32_t format;
45 uint32_t flags; /* enum zlinux_buffer_params_flags */
46 int n_planes;
47 int fd[MAX_DMABUF_PLANES];
48 uint32_t offset[MAX_DMABUF_PLANES];
49 uint32_t stride[MAX_DMABUF_PLANES];
50 uint64_t modifier[MAX_DMABUF_PLANES];
51};
52
53struct linux_dmabuf_buffer {
54 struct wl_resource *buffer_resource;
55 struct wl_resource *params_resource;
56 void *compositor;
57 struct dmabuf_attributes attributes;
58
59 void *user_data;
60 dmabuf_user_data_destroy_func user_data_destroy_func;
61
62 /* XXX:
63 *
64 * Add backend private data. This would be for the backend
65 * to do all additional imports it might ever use in advance.
66 * The basic principle, even if not implemented in drivers today,
67 * is that dmabufs are first attached, but the actual allocation
68 * is deferred to first use. This would allow the exporter and all
69 * attachers to agree on how to allocate.
70 *
71 * The DRM backend would use this to create drmFBs for each
72 * dmabuf_buffer, just in case at some point it would become
73 * feasible to scan it out directly. This would improve the
74 * possibilities to successfully scan out, avoiding compositing.
75 */
76};
77
78int
79linux_dmabuf_setup(struct wl_display *display, void *comp);
80
81struct linux_dmabuf_buffer *
82linux_dmabuf_buffer_get(struct wl_resource *resource);
83
84void
85linux_dmabuf_buffer_set_user_data(struct linux_dmabuf_buffer *buffer,
86 void *data,
87 dmabuf_user_data_destroy_func func);
88void *
89linux_dmabuf_buffer_get_user_data(struct linux_dmabuf_buffer *buffer);
90
91void
92linux_dmabuf_buffer_send_server_error(struct linux_dmabuf_buffer *buffer,
93 const char *msg);
94
95#endif /* WESTON_LINUX_DMABUF_H */
diff --git a/src/lib/efl_wl/efl_wl.c b/src/lib/efl_wl/efl_wl.c
deleted file mode 100644
index 060c3837aa..0000000000
--- a/src/lib/efl_wl/efl_wl.c
+++ /dev/null
@@ -1,5866 +0,0 @@
1#define EFL_INTERNAL_UNSTABLE
2#define EFL_CANVAS_GROUP_PROTECTED
3
4#ifdef HAVE_CONFIG_H
5# include "config.h"
6#endif
7
8#if defined(__clang__)
9# pragma clang diagnostic ignored "-Wunused-parameter"
10#elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4
11# pragma GCC diagnostic ignored "-Wunused-parameter"
12#endif
13
14#include <unistd.h>
15#include <sys/mman.h>
16#include <sys/socket.h>
17#include <fcntl.h>
18#include <dlfcn.h>
19
20#include "Ecore_Evas.h"
21#include "Ecore_Wl2.h"
22#include "ecore_wl2_internal.h"
23#include "Ecore_Input.h"
24#include "Evas_GL.h"
25
26/* We have to include the wayland server stuff after any wayland client stuff
27 * like Ecore_Wl2.h or we'll get complaints about struct wl_buffer being
28 * deprecated.
29 * That's because its deprecated in server code - it's still the name of
30 * the opaque struct client side.
31 */
32#include <wayland-server.h>
33#include "xdg-shell-server-protocol.h"
34#include "efl-hints-server-protocol.h"
35#include "dmabuf.h"
36
37# ifdef HAVE_ECORE_X
38#include "Ecore_X.h"
39#endif
40#include "Evas_Internal.h"
41#include "canvas/evas_canvas_eo.h"
42#include "Efl_Wl.h"
43
44#undef COORDS_INSIDE
45#define COORDS_INSIDE(x, y, xx, yy, ww, hh) \
46 (((x) < ((xx) + (ww))) && ((y) < ((yy) + (hh))) && ((x) >= (xx)) && ((y) >= (yy)))
47
48#ifdef __linux__
49# include <linux/input.h>
50#else
51# define BTN_LEFT 0x110
52# define BTN_RIGHT 0x111
53# define BTN_MIDDLE 0x112
54# define BTN_SIDE 0x113
55# define BTN_EXTRA 0x114
56# define BTN_FORWARD 0x115
57# define BTN_BACK 0x116
58#endif
59
60#undef container_of
61# define container_of(ptr, type, member) \
62 ({ \
63 const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \
64 (type *)(void *)( (char *)__mptr - offsetof(type,member) ); \
65 })
66
67#ifndef EGL_HEIGHT
68# define EGL_HEIGHT 0x3056
69#endif
70#ifndef EGL_WIDTH
71# define EGL_WIDTH 0x3057
72#endif
73
74#ifndef EGL_TEXTURE_FORMAT
75# define EGL_TEXTURE_FORMAT 0x3080
76#endif
77#ifndef EGL_TEXTURE_RGBA
78# define EGL_TEXTURE_RGBA 0x305E
79#endif
80#ifndef DRM_FORMAT_ARGB8888
81# define DRM_FORMAT_ARGB8888 0x34325241
82#endif
83#ifndef DRM_FORMAT_XRGB8888
84# define DRM_FORMAT_XRGB8888 0x34325258
85#endif
86
87#define ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \
88 WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \
89 WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
90
91#define MY_CLASS EFL_WL_CLASS
92
93typedef struct Input_Sequence
94{
95 EINA_INLIST;
96 uint32_t id;
97 uint32_t down_serial;
98 uint32_t down_time;
99 uint32_t up_serial;
100 uint32_t up_time;
101 Eina_Bool pass : 1;
102} Input_Sequence;
103
104typedef struct Comp_Subsurface Comp_Subsurface;
105typedef struct Comp_Surface Comp_Surface;
106
107typedef struct Comp_Buffer
108{
109 struct wl_resource *res;
110 Comp_Surface *cs;
111 Eina_List *renders;
112 Eina_List *post_renders;
113 int x, y, w, h;
114 struct wl_listener destroy_listener;
115 struct wl_shm_buffer *shm_buffer;
116 struct wl_shm_pool *pool;
117 struct linux_dmabuf_buffer *dmabuf_buffer;
118 Eina_Bool dbg : 1;
119} Comp_Buffer;
120
121typedef struct Comp
122{
123 Efl_Wl_Rotation rotation;
124 double scale;
125 char *env;
126 Efl_Exe_Flags flags;
127 Ecore_Wl2_Display *disp;
128 Ecore_Wl2_Display *parent_disp;
129 Ecore_Wl2_Display *client_disp;
130 struct wl_display *display;
131
132 double wayland_time_base;
133 Eo *obj;
134 Eo *clip;
135 Eo *events;
136
137 Eina_Hash *exes;
138
139 Eina_Inlist *surfaces;
140 unsigned int surfaces_count;
141 Eina_Hash *client_surfaces;
142 Comp_Surface *active_surface;
143
144 Eina_Inlist *shells;
145 Eina_List *render_queue;
146 Eina_List *post_render_queue;
147 Evas *evas;
148 Evas_GL *gl;
149 Evas_GL_Config *glcfg;
150 Evas_GL_Context *glctx;
151 Evas_GL_Surface *glsfc;
152 Evas_GL_API *glapi;
153 Eina_List *output_resources;
154 Eina_Inlist *seats;
155 Eina_Bool rendering : 1;
156 Eina_Bool data_device_proxy : 1;
157 Eina_Bool x11_selection : 1;
158 Eina_Bool rtl : 1;
159 Eina_Bool aspect : 1;
160 Eina_Bool minmax : 1;
161} Comp;
162
163typedef struct Comp_Data_Device_Source Comp_Data_Device_Source;
164
165typedef struct Comp_Seat
166{
167 EINA_INLIST;
168 Comp *c;
169 Eina_Stringshare *name;
170 struct wl_global *global;
171
172 Ecore_Wl2_Input *seat;
173 Ecore_Wl2_Input *client_seat;
174 Ecore_Wl2_Offer *client_offer;
175 uint32_t client_selection_serial;
176 Eo *dev;
177 Eina_List *resources;
178
179 Eina_Hash *data_devices;
180 struct
181 {
182 struct wl_resource *res;
183 Comp_Data_Device_Source *source;
184 Comp_Surface *surface;
185 Comp_Surface *enter;
186 uint32_t id;
187 Ecore_Evas *proxy_win;
188 Ecore_Window x11_owner;
189 Eina_List *x11_types;
190 Eina_Bool tch : 1;
191 } drag;
192 Comp_Data_Device_Source *selection_source;
193 uint32_t selection_serial;
194 Ecore_Window x11_selection_owner;
195
196 struct wl_client *active_client;
197 Comp_Surface *grab;
198
199 struct
200 {
201 struct wl_array keys;
202 struct wl_array *keys_external;
203 struct
204 {
205 xkb_mod_mask_t depressed;
206 xkb_mod_mask_t latched;
207 xkb_mod_mask_t locked;
208 xkb_layout_index_t group;
209 Eina_Bool changed : 1;
210 } mods;
211 struct xkb_context *context;
212 struct xkb_keymap *keymap;
213 struct xkb_state *state;
214 const char *keymap_str;
215 int keymap_str_size;
216 int repeat_rate;
217 int repeat_delay;
218 Eina_Hash *resources;
219 Comp_Surface *enter;
220 Eina_Bool external : 1;
221 } kbd;
222
223 struct
224 {
225 Eina_Hash *resources;
226 uint32_t button_mask;
227 uint32_t enter_serial;
228 Eina_Inlist *events;
229 Comp_Surface *enter;
230 struct
231 {
232 Comp_Surface *surface;
233 int x, y;
234 } cursor;
235 struct
236 {
237 Eo *obj;
238 int layer;
239 int x, y;
240 } efl;
241 Evas_Point pos;
242 Eina_Bool in : 1;
243 } ptr;
244
245 struct
246 {
247 Eina_Hash *resources;
248 Eina_Inlist *events;
249 Comp_Surface *enter;
250 Evas_Point pos;
251 } tch;
252
253 Eina_Bool pointer : 1;
254 Eina_Bool keyboard : 1;
255 Eina_Bool touch : 1;
256 Eina_Bool focused : 1;
257 Eina_Bool selection_changed : 1;
258 Eina_Bool selection_exists : 1;
259 Eina_Bool event_propagate : 1;
260} Comp_Seat;
261
262typedef struct Comp_Buffer_State
263{
264 Comp_Buffer *buffer;
265 Eina_Tiler *opaque;
266 Eina_Tiler *damages;
267 Eina_Tiler *input;
268 Eina_List *frames;
269 Eina_Bool attach : 1;
270 Eina_Bool set_opaque : 1;
271 Eina_Bool set_input : 1;
272} Comp_Buffer_State;
273
274typedef struct Shell_Data
275{
276 EINA_INLIST;
277 Comp *c;
278 struct wl_resource *res;
279 Eina_List *surfaces;
280 Eina_Inlist *positioners;
281 Eina_Bool ping : 1;
282} Shell_Data;
283
284
285typedef struct Shell_Positioner
286{
287 EINA_INLIST;
288 Shell_Data *sd;
289 struct wl_resource *res;
290 Evas_Coord_Size size;
291 Eina_Rectangle anchor_rect;
292 enum xdg_positioner_anchor anchor;
293 enum xdg_positioner_gravity gravity;
294 enum xdg_positioner_constraint_adjustment constrain;
295 Evas_Coord_Point offset;
296} Shell_Positioner;
297
298struct Comp_Surface
299{
300 EINA_INLIST;
301 Comp *c;
302 Eo *obj;
303 Eo *clip;
304 Eo *img;
305 Eina_Array *input_rects;
306 Eina_Array *opaque_rects;
307 Eina_List *proxies;
308 struct wl_resource *res;
309 struct wl_resource *role;
310 Comp_Seat *drag; //drag surface
311 Comp_Buffer *buffer[2]; // new, prev
312 /* subsurface stacking order */
313 Eina_List *subsurfaces;
314 Eina_List *pending_subsurfaces;
315 /* any child surface (xdg or subsurface */
316 Eina_Inlist *children;
317 Comp_Surface *parent;
318
319 Eina_Tiler *opaque;
320 Eina_Tiler *input;
321 Eina_List *frames;
322 Comp_Subsurface *subsurface;
323 Comp_Buffer_State pending;
324 struct
325 {
326 struct wl_resource *surface;
327 Eina_Rectangle geom;
328 Shell_Data *data;
329 Eina_Stringshare *title;
330 Eina_Stringshare *app_id;
331 Shell_Positioner *positioner;
332 Eina_List *grabs;
333 Eina_Bool popup : 1;
334 Eina_Bool new : 1;
335 Eina_Bool activated : 1;
336 } shell;
337 Eina_Bool mapped : 1;
338 Eina_Bool cursor : 1;
339 Eina_Bool render_queue : 1;
340 Eina_Bool post_render_queue : 1;
341 Eina_Bool dead : 1;
342 Eina_Bool commit : 1;
343 Eina_Bool extracted : 1;
344 Eina_Bool hint_set_weight : 1;
345};
346
347struct Comp_Subsurface
348{
349 Comp_Surface *surface;
350 Comp_Buffer_State cache;
351 Evas_Point offset;
352 Evas_Point pending_offset;
353 Eina_Bool set_offset : 1;
354 Eina_Bool sync : 1;
355 Eina_Bool cached : 1;
356};
357
358typedef enum Comp_Data_Device_Offer_Type
359{
360 COMP_DATA_DEVICE_OFFER_TYPE_DND,
361 COMP_DATA_DEVICE_OFFER_TYPE_CLIPBOARD,
362} Comp_Data_Device_Offer_Type;
363
364typedef struct Comp_Data_Device_Offer
365{
366 Comp_Data_Device_Offer_Type type;
367 struct wl_resource *res;
368 Comp_Data_Device_Source *source;
369 Ecore_Wl2_Offer *proxy_offer;
370 uint32_t dnd_actions;
371 uint32_t preferred_dnd_action;
372 Eina_Bool in_ask : 1;
373 Eina_Bool proxy : 1;
374} Comp_Data_Device_Offer;
375
376typedef struct Comp_Data_Device_Source
377{
378 struct wl_resource *res;
379 Comp_Seat *seat;
380 Comp_Data_Device_Offer *offer;
381 Ecore_Window x11_owner;
382 Eina_Inlist *transfers;
383 Eina_Binbuf *reader_data;
384 Ecore_Fd_Handler *reader;
385 Eina_List *mime_types;
386 uint32_t dnd_actions;
387 uint32_t current_dnd_action;
388 uint32_t compositor_action;
389 Ecore_Event_Handler *proxy_send_handler;
390 uint32_t proxy_serial;
391 Eina_Bool actions_set : 1;
392 Eina_Bool accepted : 1;
393 Eina_Bool proxy : 1;
394} Comp_Data_Device_Source;
395
396typedef struct Comp_Data_Device_Transfer
397{
398 EINA_INLIST;
399 Comp_Data_Device_Offer_Type type;
400 Ecore_Fd_Handler *fdh;
401 size_t offset;
402 Eina_Stringshare *mime_type;
403 Comp_Data_Device_Source *source;
404} Comp_Data_Device_Transfer;
405
406static Eina_List *comps;
407static Eina_List *handlers;
408
409static inline Eina_Tiler *
410tiler_new(void)
411{
412 Eina_Tiler *t;
413
414 t = eina_tiler_new(65535, 65535);
415 eina_tiler_tile_size_set(t, 1, 1);
416 return t;
417}
418
419static inline void
420fdh_del(Ecore_Fd_Handler *fdh)
421{
422 int fd;
423 if (!fdh) return;
424 fd = ecore_main_fd_handler_fd_get(fdh);
425 if (fd >= 0)
426 close(fd);
427 ecore_main_fd_handler_del(fdh);
428}
429
430#define PTR_SWAP(A, B) ptr_swap((void**)A, (void**)B)
431
432static inline void
433ptr_swap(void **a, void **b)
434{
435 void *c;
436
437 c = *a;
438 *a = *b;
439 *b = c;
440}
441
442static inline void
443array_clear(Eina_Array **arr)
444{
445 Eina_Array *a = *arr;
446
447 if (!a) return;
448 while (eina_array_count(a))
449 evas_object_del(eina_array_pop(a));
450 eina_array_free(a);
451 *arr = NULL;
452}
453
454static inline Eina_Bool
455client_allowed_check(Comp *c, struct wl_client *client)
456{
457 pid_t p;
458 int32_t pid;
459 Eina_Bool err;
460
461 wl_client_get_credentials(client, &p, NULL, NULL);
462 if (p == getpid()) return EINA_TRUE;
463 pid = p;
464 err = (!c->exes) || !eina_hash_find(c->exes, &pid);
465 if (err)
466 wl_client_post_no_memory(client);
467 return !err;
468}
469
470static inline void
471comp_data_device_source_reader_clear(Comp_Data_Device_Source *ds)
472{
473 fdh_del(ds->reader);
474 ds->reader = NULL;
475 eina_binbuf_free(ds->reader_data);
476 ds->reader_data = NULL;
477}
478
479static inline void
480comp_surface_reparent(Comp_Surface *cs, Comp_Surface *pcs)
481{
482 if (cs->parent == pcs) return;
483 if (!cs->extracted)
484 evas_object_smart_member_del(cs->obj);
485 if (cs->parent)
486 cs->parent->children = eina_inlist_remove(cs->parent->children, EINA_INLIST_GET(cs));
487 if (pcs)
488 {
489 cs->c->surfaces = eina_inlist_remove(cs->c->surfaces, EINA_INLIST_GET(cs));
490 cs->c->surfaces_count--;
491 if (!cs->extracted)
492 evas_object_smart_member_add(cs->obj, pcs->obj);
493 pcs->children = eina_inlist_append(pcs->children, EINA_INLIST_GET(cs));
494 }
495 else
496 {
497 if (!cs->extracted)
498 evas_object_smart_member_add(cs->obj, cs->c->obj);
499 cs->c->surfaces = eina_inlist_append(cs->c->surfaces, EINA_INLIST_GET(cs));
500 cs->c->surfaces_count++;
501 }
502 cs->parent = pcs;
503}
504
505static inline struct wl_resource *
506data_device_find(Comp_Seat *s, struct wl_resource *resource)
507{
508 struct wl_client *client = wl_resource_get_client(resource);
509 return eina_hash_find(s->data_devices, &client);
510}
511
512static inline void
513seat_drag_end(Comp_Seat *s)
514{
515 s->drag.tch = 0;
516 s->drag.id = 0;
517 s->drag.surface = NULL;
518 s->drag.res = NULL;
519 s->drag.enter = NULL;
520}
521
522static inline Comp_Seat *
523seat_find(Comp_Surface *cs, const Eo *dev)
524{
525 const Eo *seat = dev;
526 Comp_Seat *s;
527
528 if (!cs->c->parent_disp) return EINA_INLIST_CONTAINER_GET(cs->c->seats, Comp_Seat);
529 if (evas_device_class_get(seat) != EVAS_DEVICE_CLASS_SEAT)
530 seat = evas_device_parent_get(seat);
531 EINA_INLIST_FOREACH(cs->c->seats, s)
532 if (s->dev == seat) return s;
533 return NULL;
534}
535
536static inline Comp_Seat *
537comp_seat_find(Comp *c, const Eo *dev)
538{
539 const Eo *seat = dev;
540 Comp_Seat *s;
541
542 if (!c->parent_disp) return EINA_INLIST_CONTAINER_GET(c->seats, Comp_Seat);
543 if (evas_device_class_get(seat) != EVAS_DEVICE_CLASS_SEAT)
544 seat = evas_device_parent_get(seat);
545 EINA_INLIST_FOREACH(c->seats, s)
546 if (s->dev == seat) return s;
547 return NULL;
548}
549
550static inline Eina_List *
551seat_kbd_active_resources_get(Comp_Seat *s)
552{
553 Eina_List *l, *lcs, *llcs;
554 Comp_Surface *cs;
555
556 if (!s->active_client) return NULL;
557 if (!s->kbd.resources) return NULL;
558 l = eina_hash_find(s->kbd.resources, &s->active_client);
559 if (!l) return NULL;
560 lcs = eina_hash_find(s->c->client_surfaces, &s->active_client);
561 if (!lcs) return NULL;
562 EINA_LIST_REVERSE_FOREACH(lcs, llcs, cs)
563 if (cs->role && (!cs->shell.popup)) return l;
564 return NULL;
565}
566
567static inline Eina_List *
568seat_ptr_resources_get(Comp_Seat *s, struct wl_client *client)
569{
570 return s->ptr.resources ? eina_hash_find(s->ptr.resources, &client) : NULL;
571}
572
573static inline Eina_List *
574seat_tch_resources_get(Comp_Seat *s, struct wl_client *client)
575{
576 return s->tch.resources ? eina_hash_find(s->tch.resources, &client) : NULL;
577}
578
579static void comp_render_pre_proxied(Eo *o, Evas *e, void *event_info);
580static void comp_render_post_proxied(Comp_Surface *cs, Evas *e, void *event_info);
581static void comp_surface_commit_image_state(Comp_Surface *cs, Comp_Buffer *buffer, Eo *o);
582
583static void
584comp_surface_proxy_del(void *data, Evas *e, Eo *obj, void *event_info EINA_UNUSED)
585{
586 Comp_Surface *cs = data;
587 int i;
588
589 cs->proxies = eina_list_remove(cs->proxies, obj);
590 for (i = 0; i < 2; i++)
591 {
592 Comp_Buffer *buffer = cs->buffer[i];
593 if (!buffer) continue;
594 if (buffer->renders) buffer->renders = eina_list_remove(buffer->renders, e);
595 if (buffer->post_renders) buffer->post_renders = eina_list_remove(buffer->post_renders, e);
596 }
597 evas_event_callback_del_full(e, EVAS_CALLBACK_RENDER_PRE, (Evas_Event_Cb)comp_render_pre_proxied, obj);
598 evas_event_callback_del_full(e, EVAS_CALLBACK_RENDER_POST, (Evas_Event_Cb)comp_render_post_proxied, cs);
599#ifdef HAVE_ECORE_X
600 if (ecore_x_display_get())
601 ecore_x_dnd_callback_pos_update_set(NULL, NULL);
602#endif
603}
604
605static void
606comp_surface_proxy_resize(void *data, Evas *e EINA_UNUSED, Eo *obj, void *event_info EINA_UNUSED)
607{
608 int w, h;
609
610 evas_object_geometry_get(obj, NULL, NULL, &w, &h);
611 ecore_evas_resize(data, w, h);
612}
613
614static Eina_Bool
615comp_surface_is_alpha(Comp_Surface *cs, Comp_Buffer *buffer)
616{
617 int format;
618 if (buffer->shm_buffer)
619 format = wl_shm_buffer_get_format(buffer->shm_buffer);
620 else if (buffer->dmabuf_buffer)
621 format = buffer->dmabuf_buffer->attributes.format;
622 else if (cs->c->gl)
623 cs->c->glapi->evasglQueryWaylandBuffer(cs->c->gl, buffer->res, EGL_TEXTURE_FORMAT, &format);
624 else return EINA_FALSE; //not a real case
625
626 switch (format)
627 {
628 case DRM_FORMAT_ARGB8888:
629 case WL_SHM_FORMAT_ARGB8888:
630 case EGL_TEXTURE_RGBA:
631 return EINA_TRUE;
632 default:
633 break;
634 }
635 return EINA_FALSE;
636}
637
638static void
639comp_surface_proxy_win_del(Ecore_Evas *ee)
640{
641 Comp_Seat *s = ecore_evas_data_get(ee, "comp_seat");
642 if (!s) return;
643
644 s->drag.proxy_win = NULL;
645 //fprintf(stderr, "PROXY WIN DEL\n");
646}
647
648static void
649seat_drag_proxy_win_add(Comp_Seat *s)
650{
651 Eo *o;
652
653 if (s->drag.proxy_win) abort();
654 evas_object_hide(s->drag.surface->obj);
655 s->drag.proxy_win = ecore_evas_new(NULL, 0, 0, 1, 1, NULL);
656 ecore_evas_data_set(s->drag.proxy_win, "comp_seat", s);
657 ecore_evas_callback_destroy_set(s->drag.proxy_win, comp_surface_proxy_win_del);
658 ecore_evas_alpha_set(s->drag.proxy_win, 1);
659 ecore_evas_borderless_set(s->drag.proxy_win, 1);
660 ecore_evas_override_set(s->drag.proxy_win, 1);
661 ecore_evas_show(s->drag.proxy_win);
662 o = evas_object_image_filled_add(ecore_evas_get(s->drag.proxy_win));
663 evas_object_data_set(o, "comp_surface", s->drag.surface);
664 evas_event_callback_add(ecore_evas_get(s->drag.proxy_win),
665 EVAS_CALLBACK_RENDER_PRE, (Evas_Event_Cb)comp_render_pre_proxied, o);
666 evas_event_callback_add(ecore_evas_get(s->drag.proxy_win),
667 EVAS_CALLBACK_RENDER_POST, (Evas_Event_Cb)comp_render_post_proxied, s->drag.surface);
668 evas_object_image_border_center_fill_set(o, EVAS_BORDER_FILL_SOLID);
669 evas_object_image_colorspace_set(o, EVAS_COLORSPACE_ARGB8888);
670 if (!s->drag.surface->render_queue)
671 {
672 comp_surface_commit_image_state(s->drag.surface, s->drag.surface->buffer[1], o);
673 evas_object_image_alpha_set(o,
674 comp_surface_is_alpha(s->drag.surface, s->drag.surface->buffer[1]));
675 evas_object_image_data_update_add(o, 0, 0, 9999, 9999);
676 }
677 evas_object_show(o);
678 evas_object_event_callback_add(o, EVAS_CALLBACK_DEL,
679 comp_surface_proxy_del, s->drag.surface);
680 evas_object_event_callback_add(o, EVAS_CALLBACK_RESIZE,
681 comp_surface_proxy_resize, s->drag.proxy_win);
682 evas_object_resize(o,
683 s->drag.surface->buffer[!s->drag.surface->render_queue]->w,
684 s->drag.surface->buffer[!s->drag.surface->render_queue]->h);
685 s->drag.surface->proxies = eina_list_append(s->drag.surface->proxies, o);
686}
687
688static void comp_surface_send_data_device_leave(Comp_Surface *cs, Comp_Seat *s);
689static void comp_surface_send_data_device_enter(Comp_Surface *cs, Comp_Seat *s);
690
691static void
692dnd_motion(Comp_Seat *s, int ex, int ey)
693{
694 struct wl_resource *res;
695 Eina_List *l, *lcs;
696 Comp_Surface *cs;
697
698 s->ptr.pos.x = ex;
699 s->ptr.pos.y = ey;
700 if (!s->active_client) return;
701 l = eina_hash_find(s->c->client_surfaces, &s->active_client);
702 EINA_LIST_REVERSE_FOREACH(l, lcs, cs)
703 {
704 int x, y, w, h;
705 if ((!cs->mapped) || (!cs->role)) continue;
706 evas_object_geometry_get(cs->obj, &x, &y, &w, &h);
707 if (!COORDS_INSIDE(ex, ey, x, y, w, h)) continue;
708 if (s->drag.enter != cs)
709 {
710 if (s->drag.enter)
711 comp_surface_send_data_device_leave(s->drag.enter, s);
712 s->drag.enter = cs;
713 if (s->drag.source)
714 comp_surface_send_data_device_enter(cs, s);
715 }
716 if (!s->drag.source) break;
717 res = eina_hash_find(s->data_devices, &s->active_client);
718 wl_data_device_send_motion(res,
719 (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff),
720 wl_fixed_from_int(ex - x), wl_fixed_from_int(ey - y));
721 break;
722 }
723}
724#ifdef HAVE_ECORE_X
725static void x11_send_send(Comp_Data_Device_Source *source, const char* mime_type, int32_t fd, Comp_Data_Device_Offer_Type type);
726#endif
727#include "copiedfromweston.x"
728#ifdef HAVE_ECORE_X
729# include "x11.x"
730#endif
731
732static void
733resource_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
734{
735 wl_resource_destroy(resource);
736}
737
738#define CONTAINS(x, y, w, h, xx, yy, ww, hh) \
739 (((xx) >= (x)) && (((x) + (w)) >= ((xx) + (ww))) && ((yy) >= (y)) && (((y) + (h)) >= ((yy) + (hh))))
740#define CONSTRAINED(W, H, X, Y) \
741 !CONTAINS(zx, zy, zw, zh, (X), (Y), (W), (H))
742
743static int
744_apply_positioner_x(int x, Shell_Positioner *sp, Eina_Bool invert)
745{
746 enum xdg_positioner_anchor an = XDG_POSITIONER_ANCHOR_NONE;
747 enum xdg_positioner_gravity grav = XDG_POSITIONER_GRAVITY_NONE;
748
749 if (invert)
750 {
751 if (sp->anchor == XDG_POSITIONER_ANCHOR_LEFT)
752 an = XDG_POSITIONER_ANCHOR_RIGHT;
753 else if (sp->anchor == XDG_POSITIONER_ANCHOR_RIGHT)
754 an = XDG_POSITIONER_ANCHOR_LEFT;
755 if (sp->gravity & XDG_POSITIONER_GRAVITY_LEFT)
756 grav |= XDG_POSITIONER_GRAVITY_RIGHT;
757 else if (sp->gravity & XDG_POSITIONER_GRAVITY_RIGHT)
758 grav |= XDG_POSITIONER_GRAVITY_LEFT;
759 }
760 else
761 {
762 an = sp->anchor;
763 grav = sp->gravity;
764 }
765
766 /* left edge */
767 if (an == XDG_POSITIONER_ANCHOR_LEFT)
768 x += sp->anchor_rect.x;
769 /* right edge */
770 else if (an == XDG_POSITIONER_ANCHOR_RIGHT)
771 x += sp->anchor_rect.x + sp->anchor_rect.w;
772 /* center */
773 else
774 x += sp->anchor_rect.x + (sp->anchor_rect.w / 2);
775
776 /* flip left over anchor */
777 if (grav & XDG_POSITIONER_GRAVITY_LEFT)
778 x -= sp->size.w;
779 /* center on anchor */
780 else if (!(grav & XDG_POSITIONER_GRAVITY_RIGHT))
781 x -= sp->size.w / 2;
782 return x;
783}
784
785static int
786_apply_positioner_y(int y, Shell_Positioner *sp, Eina_Bool invert)
787{
788 enum xdg_positioner_anchor an = XDG_POSITIONER_ANCHOR_NONE;
789 enum xdg_positioner_gravity grav = XDG_POSITIONER_GRAVITY_NONE;
790
791 if (invert)
792 {
793 if (sp->anchor == XDG_POSITIONER_ANCHOR_TOP)
794 an = XDG_POSITIONER_ANCHOR_BOTTOM;
795 else if (sp->anchor == XDG_POSITIONER_ANCHOR_BOTTOM)
796 an = XDG_POSITIONER_ANCHOR_TOP;
797 if (sp->gravity & XDG_POSITIONER_GRAVITY_TOP)
798 grav |= XDG_POSITIONER_GRAVITY_BOTTOM;
799 else if (sp->gravity & XDG_POSITIONER_GRAVITY_BOTTOM)
800 grav |= XDG_POSITIONER_GRAVITY_TOP;
801 }
802 else
803 {
804 an = sp->anchor;
805 grav = sp->gravity;
806 }
807
808 /* up edge */
809 if (an == XDG_POSITIONER_ANCHOR_TOP)
810 y += sp->anchor_rect.y;
811 /* bottom edge */
812 else if (an == XDG_POSITIONER_ANCHOR_BOTTOM)
813 y += sp->anchor_rect.y + sp->anchor_rect.h;
814 /* center */
815 else
816 y += sp->anchor_rect.y + (sp->anchor_rect.h / 2);
817
818 /* flip up over anchor */
819 if (grav & XDG_POSITIONER_GRAVITY_TOP)
820 y -= sp->size.h;
821 /* center on anchor */
822 else if (!(grav & XDG_POSITIONER_GRAVITY_BOTTOM))
823 y -= sp->size.h / 2;
824 return y;
825}
826
827static Eina_Bool
828_apply_positioner_slide(Comp_Surface *cs, Shell_Positioner *sp, int *x, int *y, int *w, int *h, int zx, int zy, int zw, int zh)
829{
830 int px, py, cx, cy;
831
832 evas_object_geometry_get(cs->parent->obj, &px, &py, NULL, NULL);
833 evas_object_geometry_get(cs->c->obj, &cx, &cy, NULL, NULL);
834 px -= cx, py -= cy;
835 if ((sp->constrain & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X) &&
836 (!CONTAINS(zx, zy, zw, zh, *x, zy, *w, 1)))
837 {
838 int sx = *x;
839
840 if (sp->gravity & XDG_POSITIONER_GRAVITY_LEFT)
841 {
842 if (*x + *w > zx + zw)
843 sx = MAX(zx + zw - *w, px + sp->anchor_rect.x - *w);
844 else if (*x < zx)
845 sx = MIN(zx, px + sp->anchor_rect.x + sp->anchor_rect.w);
846 }
847 else if (sp->gravity & XDG_POSITIONER_GRAVITY_RIGHT)
848 {
849 if (*x < zx)
850 sx = MIN(zx, *x + sp->anchor_rect.x + sp->anchor_rect.w);
851 else if (*x + *w > zx + zw)
852 sx = MAX(zx + zw - *w, px + sp->anchor_rect.x - *w);
853 }
854 if (CONTAINS(zx, zy, zw, zh, sx, zy, *w, 1))
855 *x = sx;
856 }
857 if (!CONSTRAINED(*w, *h, *x, *y)) return EINA_TRUE;
858 if ((sp->constrain & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y) &&
859 (!CONTAINS(zx, zy, zw, zh, zx, *y, 1, *h)))
860 {
861 int sy = *y;
862
863 if (sp->gravity & XDG_POSITIONER_GRAVITY_TOP)
864 {
865 if (*y + *h > zy + zh)
866 sy = MAX(zy + zh - *h, py + sp->anchor_rect.y - *h);
867 else if (*y < zy)
868 sy = MIN(zy, py + sp->anchor_rect.y + sp->anchor_rect.h);
869 }
870 else if (sp->gravity & XDG_POSITIONER_GRAVITY_BOTTOM)
871 {
872 if (*y < zy)
873 sy = MIN(zy, py + sp->anchor_rect.y + sp->anchor_rect.h);
874 else if (*y + *h > zy + zh)
875 sy = MAX(zy + zh - *h, py + sp->anchor_rect.y - *h);
876 }
877 if (CONTAINS(zx, zy, zw, zh, zx, sy, 1, *h))
878 *y = sy;
879 }
880 return !CONSTRAINED(*w, *h, *x, *y);
881}
882
883static void
884_apply_positioner(Comp_Surface *cs, Shell_Positioner *sp)
885{
886 int ix, iy, x, y, w = -1, h = -1, px, py, cx, cy;
887 int zx, zy, zw, zh;
888 /* apply base geometry:
889 * coords are relative to parent
890 */
891 evas_object_geometry_get(cs->parent->obj, &px, &py, NULL, NULL);
892 evas_object_geometry_get(cs->c->obj, &cx, &cy, NULL, NULL);
893 px -= cx, py -= cy;
894 ix = x = px + sp->offset.x;
895 iy = y = py + sp->offset.y;
896
897 if (sp->size.w && sp->size.h)
898 {
899 w = sp->size.w;
900 h = sp->size.h;
901 }
902
903 /* apply policies in order:
904 - anchor (add anchor_rect using anchor point)
905 - gravity (perform flips if gravity is not right|bottom)
906 - constrain (adjust if popup does not fit)
907 */
908 x = _apply_positioner_x(x, sp, 0);
909 y = _apply_positioner_y(y, sp, 0);
910
911 evas_object_geometry_get(cs->c->obj, &zx, &zy, &zw, &zh);
912
913 if (!CONSTRAINED(w, h, x, y))
914 {
915 evas_object_move(cs->obj, zx + x, zy + y);
916 if (w > 0) evas_object_resize(cs->obj, w, h);
917 return;
918 }
919
920 /* assume smart placement:
921 - flip
922 - slide
923 - resize
924 */
925 if ((sp->constrain & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X) &&
926 (!CONTAINS(zx, zy, zw, zh, x, zy, w, 1)))
927 {
928 int fx;
929
930 fx = _apply_positioner_x(ix, sp, 1);
931 if (CONTAINS(zx, zy, zw, zh, fx, zy, w, 1))
932 x = fx;
933 }
934 if (!CONSTRAINED(w, h, x, y))
935 {
936 evas_object_move(cs->obj, zx + x, zy + y);
937 if (w > 0) evas_object_resize(cs->obj, w, h);
938 return;
939 }
940 if ((sp->constrain & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y) &&
941 (!CONTAINS(zx, zy, zw, zh, zx, y, 1, h)))
942 {
943 int fy;
944
945 fy = _apply_positioner_y(iy, sp, 1);
946 if (CONTAINS(zx, zy, zw, zh, zx, fy, 1, h))
947 y = fy;
948 }
949 if (!CONSTRAINED(w, h, x, y))
950 {
951 evas_object_move(cs->obj, zx + x, zy + y);
952 if (w > 0) evas_object_resize(cs->obj, w, h);
953 return;
954 }
955 if (_apply_positioner_slide(cs, sp, &x, &y, &w, &h, zx, zy, zw, zh))
956 {
957 evas_object_move(cs->obj, zx + x, zy + y);
958 if (w > 0) evas_object_resize(cs->obj, w, h);
959 return;
960 }
961
962 if (!CONSTRAINED(w, h, x, y))
963 {
964 evas_object_move(cs->obj, zx + x, zy + y);
965 if (w > 0) evas_object_resize(cs->obj, w, h);
966 return;
967 }
968
969 if ((sp->constrain & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X) &&
970 (!CONTAINS(zx, zy, zw, zh, x, zy, w, 1)))
971 {
972 w = zx + zw - x;
973 if (!CONSTRAINED(w, h, x, y))
974 {
975 evas_object_move(cs->obj, zx + x, zy + y);
976 if (w > 0) evas_object_resize(cs->obj, w, h);
977 return;
978 }
979 }
980 if ((sp->constrain & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y) &&
981 (!CONTAINS(zx, zy, zw, zh, zx, y, 1, h)))
982 {
983 h = zy + zh - y;
984 }
985 evas_object_move(cs->obj, zx + x, zy + y);
986 if (w > 0) evas_object_resize(cs->obj, w, h);
987}
988
989static const struct wl_data_offer_interface data_device_offer_interface =
990{
991 data_device_offer_accept,
992 data_device_offer_receive,
993 resource_destroy,
994 data_device_offer_finish,
995 data_device_offer_set_actions,
996};
997
998static void
999data_device_offer_create(Comp_Data_Device_Source *source, struct wl_resource *resource)
1000{
1001 Comp_Data_Device_Offer *off;
1002 Eina_List *l;
1003 Eina_Stringshare *type;
1004
1005 off = calloc(1, sizeof(Comp_Data_Device_Offer));
1006 off->res = wl_resource_create(wl_resource_get_client(resource), &wl_data_offer_interface,
1007 wl_resource_get_version(resource), 0);
1008 wl_resource_set_implementation(off->res, &data_device_offer_interface, off, data_device_offer_impl_destroy);
1009 off->source = source;
1010 source->offer = off;
1011 off->proxy = source->proxy;
1012 wl_data_device_send_data_offer(resource, off->res);
1013 EINA_LIST_FOREACH(source->mime_types, l, type)
1014 wl_data_offer_send_offer(off->res, type);
1015}
1016
1017static void
1018comp_buffer_state_alloc(Comp_Buffer_State *cbs)
1019{
1020 cbs->damages = tiler_new();
1021 cbs->opaque = tiler_new();
1022 cbs->input = tiler_new();
1023}
1024
1025static void
1026comp_buffer_state_clear(Comp_Buffer_State *cbs)
1027{
1028 eina_tiler_free(cbs->damages);
1029 eina_tiler_free(cbs->opaque);
1030 eina_tiler_free(cbs->input);
1031 while (cbs->frames)
1032 wl_resource_destroy(eina_list_data_get(cbs->frames));
1033}
1034
1035static void
1036comp_seat_send_modifiers(Comp_Seat *s, struct wl_resource *res, uint32_t serial)
1037{
1038 wl_keyboard_send_modifiers(res, serial, s->kbd.mods.depressed,
1039 s->kbd.mods.latched,
1040 s->kbd.mods.locked,
1041 s->kbd.mods.group);
1042 s->kbd.mods.changed = 0;
1043}
1044
1045static Eina_Bool
1046data_device_selection_read(void *d, Ecore_Fd_Handler *fdh)
1047{
1048 Comp_Data_Device_Source *ds = d;
1049 int len = -1;
1050
1051 do
1052 {
1053 unsigned char buf[2048];
1054 int fd;
1055
1056 fd = ecore_main_fd_handler_fd_get(fdh);
1057 if (fd < 0) break;
1058 len = read(fd, buf, sizeof(buf));
1059 if (len > 0)
1060 {
1061 if (!ds->reader_data)
1062 ds->reader_data = eina_binbuf_new();
1063 eina_binbuf_append_length(ds->reader_data, buf, len);
1064 return ECORE_CALLBACK_RENEW;
1065 }
1066 } while (0);
1067 fdh_del(fdh);
1068 ds->reader = NULL;
1069 if (len < 0)
1070 {
1071 eina_binbuf_free(ds->reader_data);
1072 ds->reader_data = NULL;
1073 }
1074 return ECORE_CALLBACK_RENEW;
1075}
1076
1077static void
1078comp_seat_kbd_data_device_enter(Comp_Seat *s)
1079{
1080 struct wl_resource *res;
1081 Comp_Data_Device_Source *ds = s->selection_source;
1082 int fd[2];
1083
1084 if (!s->kbd.enter) return;
1085 res = data_device_find(s, s->kbd.enter->res);
1086 if (!res) return;
1087 if (ds)
1088 {
1089 data_device_offer_create(ds, res);
1090 ds->offer->type = COMP_DATA_DEVICE_OFFER_TYPE_CLIPBOARD;
1091 }
1092 if (ds)
1093 wl_data_device_send_selection(res, ds->offer ? ds->offer->res : NULL);
1094 if ((!ds) || (!ds->mime_types)) return;
1095 EINA_SAFETY_ON_TRUE_RETURN(pipe2(fd, O_CLOEXEC) < 0);
1096 wl_data_source_send_send(ds->res, eina_list_data_get(ds->mime_types), fd[1]);
1097 close(fd[1]);
1098 ds->reader = ecore_main_fd_handler_file_add(fd[0], ECORE_FD_READ | ECORE_FD_ERROR,
1099 data_device_selection_read, ds, NULL, NULL);
1100}
1101
1102static void
1103comp_seats_redo_enter(Comp *c, Comp_Surface *cs)
1104{
1105 Comp_Seat *s;
1106 uint32_t serial;
1107 struct wl_client *client = NULL;
1108
1109 serial = wl_display_next_serial(c->display);
1110 if (cs)
1111 client = wl_resource_get_client(cs->res);
1112 EINA_INLIST_FOREACH(c->seats, s)
1113 {
1114 Eina_List *l, *ll;
1115 struct wl_resource *res;
1116 Eina_Bool same = s->kbd.enter == cs;
1117
1118 if (c->active_surface && s->kbd.enter && (!same))
1119 {
1120 l = seat_kbd_active_resources_get(s);
1121 EINA_LIST_FOREACH(l, ll, res)
1122 wl_keyboard_send_leave(res, serial, s->kbd.enter->res);
1123 }
1124 s->active_client = client;
1125 if (cs)
1126 {
1127 l = seat_kbd_active_resources_get(s);
1128 EINA_LIST_FOREACH(l, ll, res)
1129 {
1130 if (!same)
1131 wl_keyboard_send_enter(res, serial, cs->res, &s->kbd.keys);
1132 comp_seat_send_modifiers(s, res, serial);
1133 }
1134 }
1135 s->kbd.enter = cs;
1136 if (s->kbd.enter && s->selection_source && (!same))
1137 comp_seat_kbd_data_device_enter(s);
1138 }
1139 c->active_surface = cs;
1140}
1141
1142static void shell_surface_send_configure(Comp_Surface *cs);
1143
1144static void
1145shell_surface_deactivate_recurse(Comp_Surface *cs)
1146{
1147 Comp_Surface *ccs;
1148
1149 EINA_INLIST_FOREACH(cs->children, ccs)
1150 {
1151 if (!ccs->shell.popup) continue;
1152 shell_surface_deactivate_recurse(ccs);
1153 if (ccs->shell.grabs) evas_object_hide(ccs->obj);
1154 }
1155}
1156
1157static void
1158shell_surface_activate_recurse(Comp_Surface *cs)
1159{
1160 Comp_Surface *lcs, *parent = cs->parent;
1161 Eina_List *parents = NULL;
1162 Eina_Inlist *i;
1163
1164 if (parent)
1165 {
1166 /* remove focus from parents */
1167 while (parent)
1168 {
1169 parents = eina_list_append(parents, parent);
1170 if (!parent->shell.popup) break;
1171 parent = parent->parent;
1172 }
1173 }
1174 EINA_INLIST_FOREACH_SAFE(cs->c->surfaces, i, lcs)
1175 if (lcs->shell.activated && (lcs != cs))
1176 {
1177 if ((!parents) || (!eina_list_data_find(parents, lcs)))
1178 {
1179 lcs->shell.activated = 0;
1180 shell_surface_send_configure(lcs);
1181 cs->c->surfaces = eina_inlist_promote(cs->c->surfaces, EINA_INLIST_GET(lcs));
1182 }
1183 }
1184 eina_list_free(parents);
1185}
1186
1187static void
1188shell_surface_minmax_update(Comp_Surface *cs)
1189{
1190 int w, h;
1191
1192 if (!cs) return;
1193 if (!cs->c->minmax) return;
1194 if (cs->extracted) return;
1195 if (cs->parent) return;
1196 evas_object_size_hint_min_get(cs->obj, &w, &h);
1197 evas_object_size_hint_min_set(cs->c->obj, w, h);
1198 evas_object_size_hint_max_get(cs->obj, &w, &h);
1199 if (!w) w = -1;
1200 if (!h) h = -1;
1201 evas_object_size_hint_max_set(cs->c->obj, w, h);
1202}
1203
1204static void
1205shell_surface_aspect_update(Comp_Surface *cs)
1206{
1207 Evas_Aspect_Control aspect;
1208 int w, h;
1209
1210 if (!cs) return;
1211 if (!cs->c->aspect) return;
1212 if (cs->extracted) return;
1213 if (cs->parent) return;
1214 evas_object_size_hint_aspect_get(cs->obj, &aspect, &w, &h);
1215 evas_object_size_hint_aspect_set(cs->c->obj, aspect, w, h);
1216}
1217
1218static void
1219shell_surface_send_configure(Comp_Surface *cs)
1220{
1221 uint32_t serial, *s;
1222 struct wl_array states;
1223 int w, h;
1224
1225 cs->shell.new = 0;
1226 if (cs->shell.popup)
1227 {
1228 int x, y, px, py;
1229 evas_object_geometry_get(cs->obj, &x, &y, &w, &h);
1230 evas_object_geometry_get(cs->parent->obj, &px, &py, NULL, NULL);
1231 serial = wl_display_next_serial(cs->c->display);
1232 xdg_popup_send_configure(cs->role, x - px, y - py, w, h);
1233 xdg_surface_send_configure(cs->shell.surface, serial);
1234 return;
1235 }
1236 wl_array_init(&states);
1237 s = wl_array_add(&states, sizeof(uint32_t));
1238 *s = XDG_TOPLEVEL_STATE_FULLSCREEN;
1239 if (cs->shell.activated)
1240 {
1241 s = wl_array_add(&states, sizeof(uint32_t));
1242 *s = XDG_TOPLEVEL_STATE_ACTIVATED;
1243 if (!cs->extracted)
1244 evas_object_raise(cs->obj);
1245 if (cs->parent)
1246 cs->parent->children = eina_inlist_demote(cs->parent->children, EINA_INLIST_GET(cs));
1247 else
1248 cs->c->surfaces = eina_inlist_demote(cs->c->surfaces, EINA_INLIST_GET(cs));
1249 shell_surface_activate_recurse(cs);
1250 }
1251 serial = wl_display_next_serial(cs->c->display);
1252 if (cs->extracted)
1253 evas_object_geometry_get(cs->obj, NULL, NULL, &w, &h);
1254 else
1255 evas_object_geometry_get(cs->c->clip, NULL, NULL, &w, &h);
1256 xdg_toplevel_send_configure(cs->role, w, h, &states);
1257 xdg_surface_send_configure(cs->shell.surface, serial);
1258 wl_array_release(&states);
1259 if (cs->shell.activated)
1260 {
1261 Comp_Surface *ccs;
1262
1263 /* apply activation to already-mapped surface */
1264 if (cs->mapped)
1265 {
1266 comp_seats_redo_enter(cs->c, cs);
1267 shell_surface_aspect_update(cs);
1268 shell_surface_minmax_update(cs);
1269 }
1270 EINA_INLIST_FOREACH(cs->children, ccs)
1271 if (ccs->shell.surface && ccs->role && ccs->shell.popup)
1272 ccs->shell.activated = cs->shell.activated;
1273 }
1274 else
1275 shell_surface_deactivate_recurse(cs);
1276}
1277
1278static void
1279shell_surface_init(Comp_Surface *cs)
1280{
1281 /* update activate status: newest window is always activated */
1282 Comp_Surface *parent = cs->parent;
1283
1284 if (cs->c->active_surface && parent && (!parent->shell.activated))
1285 {
1286 /* child windows/popups cannot steal focus from toplevel */
1287 shell_surface_send_configure(cs);
1288 return;
1289 }
1290
1291 cs->shell.activated = 1;
1292 shell_surface_send_configure(cs);
1293}
1294
1295static void
1296comp_surface_output_leave(Comp_Surface *cs)
1297{
1298 Eina_List *l;
1299 struct wl_resource *res;
1300
1301 EINA_LIST_FOREACH(cs->c->output_resources, l, res)
1302 if (wl_resource_get_client(res) == wl_resource_get_client(cs->res))
1303 wl_surface_send_leave(cs->res, res);
1304}
1305
1306static void
1307comp_surface_output_enter(Comp_Surface *cs)
1308{
1309 Eina_List *l;
1310 struct wl_resource *res;
1311
1312 EINA_LIST_FOREACH(cs->c->output_resources, l, res)
1313 if (wl_resource_get_client(res) == wl_resource_get_client(cs->res))
1314 wl_surface_send_enter(cs->res, res);
1315}
1316
1317static void
1318comp_surface_buffer_detach(Comp_Buffer **pbuffer)
1319{
1320 Comp_Buffer *buffer;
1321
1322 buffer = *pbuffer;
1323 if (!buffer) return;
1324 if (buffer->post_renders)
1325 fprintf(stderr, "CRASH %u\n", wl_resource_get_id(buffer->res));
1326 eina_list_free(buffer->renders);
1327 wl_list_remove(&buffer->destroy_listener.link);
1328 //if (buffer->dbg) fprintf(stderr, "BUFFER(%d) RELEASE\n", wl_resource_get_id(buffer->res));
1329 if (buffer->pool) wl_shm_pool_unref(buffer->pool);
1330 wl_buffer_send_release(buffer->res);
1331 free(buffer);
1332 *pbuffer = NULL;
1333}
1334
1335static void
1336comp_surface_buffer_post_render(Comp_Surface *cs)
1337{
1338 double t = ecore_loop_time_get() - cs->c->wayland_time_base;
1339
1340 //if (cs->subsurface)
1341 //fprintf(stderr, "FRAME(%d)\n", wl_resource_get_id(cs->res));
1342 while (cs->frames)
1343 {
1344 struct wl_resource *frame = eina_list_data_get(cs->frames);
1345
1346 wl_callback_send_done(frame, t * 1000);
1347 wl_resource_destroy(frame);
1348 }
1349}
1350
1351static void
1352comp_surface_pixels_get(void *data, Eo *obj)
1353{
1354 Comp_Surface *cs = data;
1355 Comp_Buffer *buffer;
1356
1357 evas_object_image_pixels_dirty_set(obj, 0);
1358 evas_object_image_pixels_get_callback_set(obj, NULL, NULL);
1359 buffer = cs->buffer[!cs->render_queue];
1360 //if (cs->cursor || (buffer->w == 32)) fprintf(stderr, "RENDER(%d) %dx%d\n", wl_resource_get_id(buffer->res), buffer->w, buffer->h);
1361 evas_object_image_size_set(obj, buffer->w, buffer->h);
1362 evas_object_image_data_set(obj, wl_shm_buffer_get_data(buffer->shm_buffer));
1363}
1364
1365static void
1366comp_surface_commit_image_state(Comp_Surface *cs, Comp_Buffer *buffer, Eo *o)
1367{
1368 if ((!buffer->renders) || (!eina_list_data_find(buffer->renders, evas_object_evas_get(o))))
1369 buffer->renders = eina_list_append(buffer->renders, evas_object_evas_get(o));
1370 evas_object_image_pixels_dirty_set(o, 1);
1371
1372 if (buffer->shm_buffer)
1373 {
1374 //if (cs->subsurface)
1375 //fprintf(stderr, "SET CB\n");
1376 evas_object_image_pixels_get_callback_set(o, comp_surface_pixels_get, cs);
1377 buffer->pool = wl_shm_buffer_ref_pool(buffer->shm_buffer);
1378 }
1379 else
1380 {
1381 Evas_Native_Surface ns;
1382
1383 evas_object_image_pixels_get_callback_set(o, NULL, NULL);
1384 if (buffer->dmabuf_buffer)
1385 {
1386 ns.type = EVAS_NATIVE_SURFACE_WL_DMABUF;
1387 ns.version = EVAS_NATIVE_SURFACE_VERSION;
1388
1389 ns.data.wl_dmabuf.attr = &buffer->dmabuf_buffer->attributes;
1390 ns.data.wl_dmabuf.resource = buffer->res;
1391 ns.data.wl_dmabuf.scanout.handler = NULL;
1392 ns.data.wl_dmabuf.scanout.data = NULL;
1393 }
1394 else
1395 {
1396 ns.type = EVAS_NATIVE_SURFACE_WL;
1397 ns.version = EVAS_NATIVE_SURFACE_VERSION;
1398 ns.data.wl.legacy_buffer = buffer->res;
1399 }
1400 evas_object_image_native_surface_set(o, &ns);
1401 }
1402}
1403
1404static void
1405shell_surface_reset(Comp_Surface *cs)
1406{
1407 EINA_RECTANGLE_SET(&cs->shell.geom, 0, 0, 0, 0);
1408 eina_stringshare_replace(&cs->shell.title, NULL);
1409 eina_stringshare_replace(&cs->shell.app_id, NULL);
1410 cs->shell.activated = 0;
1411}
1412
1413static void
1414comp_surface_commit_state(Comp_Surface *cs, Comp_Buffer_State *state)
1415{
1416 int x, y;
1417 Eina_List *l;
1418 Eo *o;
1419 Comp_Buffer *buffer = NULL;
1420 Eina_Bool newly_new = EINA_FALSE;
1421
1422 if (state->attach)
1423 {
1424 comp_surface_buffer_detach(&cs->buffer[0]);
1425 buffer = cs->buffer[0] = state->buffer;
1426
1427 if (buffer)
1428 {
1429 //if (cs->subsurface)
1430 //fprintf(stderr, "BUFFER(%d) COMMIT %d\n", wl_resource_get_id(buffer->res), wl_resource_get_id(cs->res));
1431 if ((!cs->c->rendering) && (!cs->post_render_queue) &&
1432 ((!cs->buffer[1]) || (!cs->buffer[1]->post_renders)))
1433 comp_surface_buffer_detach(&cs->buffer[1]);
1434 }
1435 else
1436 {
1437 if (!cs->extracted)
1438 evas_object_hide(cs->obj);
1439 EINA_LIST_FOREACH(cs->proxies, l, o)
1440 evas_object_hide(o);
1441 if (cs->shell.surface)
1442 {
1443 cs->shell.new = 1;
1444 newly_new = EINA_TRUE;
1445 shell_surface_reset(cs);
1446 }
1447 }
1448 }
1449 evas_object_geometry_get(cs->obj, &x, &y, NULL, NULL);
1450
1451 if (buffer && (!cs->mapped))
1452 {
1453 if (cs->role && (!cs->extracted))
1454 evas_object_show(cs->obj);
1455 /* apply activation to activated surface on map */
1456 if (cs->role && cs->shell.surface && cs->shell.activated && (!cs->shell.popup))
1457 {
1458 comp_seats_redo_enter(cs->c, cs);
1459 shell_surface_aspect_update(cs);
1460 shell_surface_minmax_update(cs);
1461 }
1462 }
1463
1464 if (state->attach && state->buffer)
1465 {
1466 evas_object_move(cs->img, x + buffer->x, y + buffer->y);
1467 evas_object_resize(cs->obj, buffer->w, buffer->h);
1468 }
1469 else if (cs->shell.new && (!newly_new))
1470 shell_surface_init(cs);
1471
1472 state->attach = 0;
1473 state->buffer = NULL;
1474
1475 cs->frames = eina_list_merge(cs->frames, state->frames);
1476 state->frames = NULL;
1477
1478 if (eina_tiler_empty(state->damages))
1479 {
1480 comp_surface_buffer_detach(&buffer);
1481 comp_surface_buffer_post_render(cs);
1482 if (!cs->post_render_queue)
1483 {
1484 evas_object_image_pixels_dirty_set(cs->img, 0);
1485 EINA_LIST_FOREACH(cs->proxies, l, o)
1486 evas_object_image_pixels_dirty_set(o, 0);
1487 }
1488 }
1489 else if (buffer)
1490 {
1491 Eina_Iterator *it;
1492 Eina_Rectangle *rect;
1493
1494 comp_surface_commit_image_state(cs, buffer, cs->img);
1495 EINA_LIST_FOREACH(cs->proxies, l, o)
1496 comp_surface_commit_image_state(cs, buffer, o);
1497
1498 it = eina_tiler_iterator_new(state->damages);
1499 EINA_ITERATOR_FOREACH(it, rect)
1500 {
1501 //if (cs->subsurface) fprintf(stderr, "BUFFER(%d) DAMAGE %d\n", wl_resource_get_id(buffer->res), wl_resource_get_id(cs->res));
1502 evas_object_image_data_update_add(cs->img, rect->x, rect->y, rect->w, rect->h);
1503 EINA_LIST_FOREACH(cs->proxies, l, o)
1504 evas_object_image_data_update_add(o, rect->x, rect->y, rect->w, rect->h);
1505 }
1506 eina_iterator_free(it);
1507 if (!cs->render_queue)
1508 cs->c->render_queue = eina_list_append(cs->c->render_queue, cs);
1509 cs->render_queue = 1;
1510 }
1511 eina_tiler_clear(state->damages);
1512
1513 if (state->set_opaque && (!eina_tiler_equal(cs->opaque, state->opaque)))
1514 {
1515 array_clear(&cs->opaque_rects);
1516 if (!eina_tiler_empty(state->opaque))
1517 /* FIXME: proxied opaque regions */
1518 {
1519 Eina_Iterator *it;
1520 Eina_Rectangle *rect;
1521 Eo *r;
1522
1523 it = eina_tiler_iterator_new(state->opaque);
1524 cs->opaque_rects = eina_array_new(1);
1525 EINA_ITERATOR_FOREACH(it, rect)
1526 {
1527 r = evas_object_rectangle_add(cs->c->evas);
1528 evas_object_name_set(r, "opaque_rect");
1529 evas_object_pass_events_set(r, 1);
1530 evas_object_color_set(r, 0, 0, 0, 255);
1531 evas_object_smart_member_add(r, cs->obj);
1532 evas_object_geometry_set(r, x + rect->x, y + rect->y, rect->w, rect->h);
1533 evas_object_stack_below(r, cs->img);
1534 evas_object_show(r);
1535 eina_array_push(cs->opaque_rects, r);
1536 }
1537 /* FIXME: maybe use image border here */
1538
1539 eina_iterator_free(it);
1540 }
1541 PTR_SWAP(&cs->opaque, &state->opaque);
1542 }
1543 eina_tiler_clear(state->opaque);
1544 state->set_opaque = 0;
1545
1546 if (state->set_input)
1547 {
1548 if (eina_tiler_empty(state->input))
1549 {
1550 array_clear(&cs->input_rects);
1551 evas_object_pass_events_set(cs->img, 0);
1552 evas_object_pointer_mode_set(cs->img, EVAS_OBJECT_POINTER_MODE_NOGRAB);
1553 }
1554 else if (!eina_tiler_equal(cs->input, state->input))
1555 {
1556 Eina_Iterator *it;
1557 Eina_Rectangle *rect;
1558 Eo *r;
1559
1560 array_clear(&cs->input_rects);
1561 it = eina_tiler_iterator_new(state->input);
1562 cs->input_rects = eina_array_new(1);
1563 EINA_ITERATOR_FOREACH(it, rect)
1564 {
1565 r = evas_object_rectangle_add(cs->c->evas);
1566 evas_object_name_set(r, "input_rect");
1567 evas_object_color_set(r, 0, 0, 0, 0);
1568 evas_object_smart_member_add(r, cs->obj);
1569 evas_object_geometry_set(r, x + rect->x, y + rect->y, rect->w, rect->h);
1570 evas_object_stack_above(r, cs->img);
1571 evas_object_pointer_mode_set(r, EVAS_OBJECT_POINTER_MODE_NOGRAB);
1572 evas_object_show(r);
1573 evas_object_show(r);
1574 eina_array_push(cs->input_rects, r);
1575 }
1576 evas_object_pass_events_set(cs->img, 1);
1577 eina_iterator_free(it);
1578 }
1579 PTR_SWAP(&cs->input, &state->input);
1580 }
1581 eina_tiler_clear(state->input);
1582 state->set_input = 0;
1583
1584 if (cs->pending_subsurfaces)
1585 {
1586 cs->subsurfaces = eina_list_free(cs->subsurfaces);
1587 PTR_SWAP(&cs->subsurfaces, &cs->pending_subsurfaces);
1588 }
1589 if (cs->subsurface)
1590 {
1591 if (cs->subsurface->set_offset)
1592 {
1593 cs->subsurface->offset.x = cs->subsurface->pending_offset.x;
1594 cs->subsurface->offset.y = cs->subsurface->pending_offset.y;
1595 cs->subsurface->pending_offset.x = cs->subsurface->pending_offset.y = 0;
1596 cs->subsurface->set_offset = 0;
1597 evas_object_geometry_get(cs->parent->obj, &x, &y, NULL, NULL);
1598 evas_object_move(cs->obj, x + cs->subsurface->offset.x, y + cs->subsurface->offset.y);
1599 }
1600 }
1601}
1602
1603static void
1604comp_surface_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
1605{
1606 Comp_Surface *cs = wl_resource_get_user_data(resource);
1607 if (cs)
1608 {
1609 if (cs->post_render_queue)
1610 {
1611 cs->dead = 1;
1612 evas_object_pass_events_set(cs->obj, 1);
1613 return;
1614 }
1615 cs->res = NULL;
1616 }
1617 wl_resource_destroy(resource);
1618}
1619
1620static void
1621comp_surface_buffer_destroy(struct wl_listener *listener, void *data EINA_UNUSED)
1622{
1623 Comp_Buffer *buffer;
1624 Comp_Surface *cs;
1625
1626 buffer = container_of(listener, Comp_Buffer, destroy_listener);
1627 cs = buffer->cs;
1628 if (cs)
1629 {
1630 if (cs->buffer[0] == buffer) cs->buffer[0] = NULL;
1631 else if (cs->buffer[1] == buffer) cs->buffer[1] = NULL;
1632 else if (cs->pending.buffer == buffer) cs->pending.buffer = NULL;
1633 else if (cs->subsurface)
1634 {
1635 if (cs->subsurface->cache.buffer == buffer) cs->subsurface->cache.buffer = NULL;
1636 }
1637 }
1638 free(buffer);
1639}
1640
1641static void
1642comp_surface_attach(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *buffer_resource, int32_t x, int32_t y)
1643{
1644 Comp_Surface *cs = wl_resource_get_user_data(resource);
1645 Comp_Buffer *buffer;
1646 struct wl_shm_buffer *shmbuff;
1647 struct linux_dmabuf_buffer *dmabuf;
1648
1649 if (cs->shell.new)
1650 {
1651 wl_resource_post_error(cs->shell.surface, XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER,
1652 "buffer attached/committed before configure");
1653 return;
1654 }
1655
1656 comp_surface_buffer_detach(&cs->pending.buffer);
1657 cs->pending.attach = 1;
1658 if (!buffer_resource) return;
1659
1660 buffer = calloc(1, sizeof(Comp_Buffer));
1661 if (cs->subsurface)
1662 {
1663 //fprintf(stderr, "BUFFER(%d) HELD BY %d\n", wl_resource_get_id(buffer_resource), wl_resource_get_id(resource));
1664 buffer->dbg = 1;
1665 }
1666 buffer->cs = cs;
1667 buffer->x = x;
1668 buffer->y = y;
1669 shmbuff = wl_shm_buffer_get(buffer_resource);
1670 dmabuf = linux_dmabuf_buffer_get(buffer_resource);
1671 if (shmbuff)
1672 {
1673 buffer->w = wl_shm_buffer_get_width(shmbuff);
1674 buffer->h = wl_shm_buffer_get_height(shmbuff);
1675 }
1676 else if (dmabuf)
1677 {
1678 buffer->w = dmabuf->attributes.width;
1679 buffer->h = dmabuf->attributes.height;
1680 }
1681 else if (cs->c->gl)
1682 {
1683 cs->c->glapi->evasglQueryWaylandBuffer(cs->c->gl, buffer_resource, EGL_WIDTH, &buffer->w);
1684 cs->c->glapi->evasglQueryWaylandBuffer(cs->c->gl, buffer_resource, EGL_HEIGHT, &buffer->h);
1685 }
1686 buffer->shm_buffer = shmbuff;
1687 buffer->dmabuf_buffer = dmabuf;
1688
1689 buffer->res = buffer_resource;
1690 buffer->destroy_listener.notify = comp_surface_buffer_destroy;
1691 wl_resource_add_destroy_listener(buffer_resource, &buffer->destroy_listener);
1692 cs->pending.buffer = buffer;
1693}
1694
1695static void
1696comp_surface_damage_buffer(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, int32_t x, int32_t y, int32_t w, int32_t h)
1697{
1698 Comp_Surface *cs = wl_resource_get_user_data(resource);
1699 eina_tiler_rect_add(cs->pending.damages, &(Eina_Rectangle){x, y, w, h});
1700}
1701
1702/*
1703 * Currently damage and damage_buffer are the same because we don't support
1704 * buffer_scale, transform, or viewport. Once we support those we'll have
1705 * to make surface_cb_damage handle damage in surface co-ordinates.
1706 */
1707static void
1708comp_surface_damage(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t w, int32_t h)
1709{
1710 comp_surface_damage_buffer(client, resource, x, y, w, h);
1711}
1712
1713static void
1714comp_surface_frame_impl_destroy(struct wl_resource *resource)
1715{
1716 Comp_Surface *cs = wl_resource_get_user_data(resource);
1717
1718 if (!cs) return;
1719 if (cs->frames)
1720 cs->frames = eina_list_remove(cs->frames, resource);
1721 if (cs->pending.frames)
1722 cs->pending.frames = eina_list_remove(cs->pending.frames, resource);
1723
1724 if (cs->subsurface && cs->subsurface->cached)
1725 cs->subsurface->cache.frames = eina_list_remove(cs->subsurface->cache.frames, resource);
1726}
1727
1728static void
1729comp_surface_frame(struct wl_client *client, struct wl_resource *resource, uint32_t callback)
1730{
1731 Comp_Surface *cs = wl_resource_get_user_data(resource);
1732 struct wl_resource *res;
1733
1734 res = wl_resource_create(client, &wl_callback_interface, 1, callback);
1735 wl_resource_set_implementation(res, NULL, cs, comp_surface_frame_impl_destroy);
1736 cs->pending.frames = eina_list_append(cs->pending.frames, res);
1737}
1738
1739static void
1740comp_surface_set_opaque_region(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *region_resource)
1741{
1742 Comp_Surface *cs = wl_resource_get_user_data(resource);
1743
1744 cs->pending.set_opaque = 1;
1745 eina_tiler_clear(cs->pending.opaque);
1746 if (region_resource)
1747 eina_tiler_union(cs->pending.opaque, wl_resource_get_user_data(region_resource));
1748}
1749
1750static void
1751comp_surface_set_input_region(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *region_resource)
1752{
1753 Comp_Surface *cs = wl_resource_get_user_data(resource);
1754
1755 if (cs->cursor) return;
1756
1757 cs->pending.set_input = 1;
1758 eina_tiler_clear(cs->pending.input);
1759 if (region_resource)
1760 eina_tiler_union(cs->pending.input, wl_resource_get_user_data(region_resource));
1761}
1762
1763static void
1764subcomp_subsurface_cache_merge(Comp_Subsurface *css)
1765{
1766 //fprintf(stderr, "CACHE MERGE\n");
1767 css->cached = 1;
1768 if (css->cache.frames || css->surface->pending.frames)
1769 css->cache.frames = eina_list_merge(css->cache.frames, css->surface->pending.frames);
1770 css->surface->pending.frames = NULL;
1771 eina_tiler_union(css->cache.damages, css->surface->pending.damages);
1772 eina_tiler_clear(css->surface->pending.damages);
1773 css->cache.set_input = css->surface->pending.set_input;
1774 if (css->surface->pending.set_input)
1775 {
1776 eina_tiler_clear(css->cache.input);
1777 PTR_SWAP(&css->cache.input, &css->surface->pending.input);
1778 }
1779 css->cache.set_opaque = css->surface->pending.set_opaque;
1780 if (css->surface->pending.set_opaque)
1781 {
1782 eina_tiler_clear(css->cache.opaque);
1783 PTR_SWAP(&css->cache.opaque, &css->surface->pending.opaque);
1784 }
1785 css->surface->pending.set_input = 0;
1786 css->surface->pending.set_opaque = 0;
1787 if (!css->surface->pending.attach) return;
1788 css->cache.attach = 1;
1789 comp_surface_buffer_detach(&css->cache.buffer);
1790 PTR_SWAP(&css->cache.buffer, &css->surface->pending.buffer);
1791 css->surface->pending.attach = 0;
1792}
1793
1794static void
1795comp_surface_commit(struct wl_client *client, struct wl_resource *resource)
1796{
1797 Comp_Surface *cs = wl_resource_get_user_data(resource);
1798 Comp_Subsurface *css;
1799 Eina_List *l;
1800 Comp_Buffer_State *cbs = &cs->pending;
1801
1802 if (cs->shell.popup && (!cs->parent))
1803 {
1804 wl_resource_post_error(cs->shell.surface, XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT,
1805 "popup surface has no parent");
1806 return;
1807 }
1808
1809 cs->commit = 1;
1810 if (cs->subsurface)
1811 {
1812 Comp_Surface *parent;
1813
1814 css = cs->subsurface;
1815 parent = cs->parent;
1816 if ((!parent->commit) && css->sync)
1817 {
1818 subcomp_subsurface_cache_merge(css);
1819 return;
1820 }
1821 while (parent && (!parent->commit) && parent->subsurface)
1822 {
1823 Comp_Subsurface *pss = parent->subsurface;
1824
1825 if (pss->sync)
1826 {
1827 subcomp_subsurface_cache_merge(css);
1828 return;
1829 }
1830 parent = parent->parent;
1831 }
1832
1833
1834 subcomp_subsurface_cache_merge(css);
1835 cbs = &css->cache;
1836 }
1837
1838 comp_surface_commit_state(cs, cbs);
1839 EINA_LIST_FOREACH(cs->subsurfaces, l, css)
1840 if (css->sync) comp_surface_commit(client, css->surface->res);
1841 cs->commit = 0;
1842}
1843
1844static void
1845comp_surface_set_buffer_transform(struct wl_client *client, struct wl_resource *resource, int32_t transform)
1846{
1847 //Comp_Surface *cs = wl_resource_get_user_data(resource);
1848}
1849
1850static void
1851comp_surface_set_buffer_scale(struct wl_client *client, struct wl_resource *resource, int32_t scale)
1852{
1853 //Comp_Surface *cs = wl_resource_get_user_data(resource);
1854}
1855
1856static const struct wl_surface_interface comp_surface_interface =
1857{
1858 comp_surface_destroy,
1859 comp_surface_attach,
1860 comp_surface_damage,
1861 comp_surface_frame,
1862 comp_surface_set_opaque_region,
1863 comp_surface_set_input_region,
1864 comp_surface_commit,
1865 comp_surface_set_buffer_transform,
1866 comp_surface_set_buffer_scale,
1867 comp_surface_damage_buffer
1868};
1869
1870static void
1871comp_surface_impl_destroy(struct wl_resource *resource)
1872{
1873 Comp_Surface *cs = wl_resource_get_user_data(resource);
1874 Eina_List *subsurfaces;
1875 Comp_Subsurface *css;
1876 Comp_Seat *s;
1877 struct wl_client *client = wl_resource_get_client(resource);
1878
1879 EINA_INLIST_FOREACH(cs->c->seats, s)
1880 {
1881 if (s->kbd.enter == cs) s->kbd.enter = NULL;
1882 if (s->ptr.enter == cs) s->ptr.enter = NULL;
1883 if (s->ptr.cursor.surface == cs)
1884 {
1885 if (s->ptr.in)
1886 {
1887 const Eina_List *l;
1888 Eo *dev;
1889 Ecore_Evas *ee = ecore_evas_ecore_evas_get(s->c->evas);
1890 EINA_LIST_FOREACH(evas_device_list(s->c->evas, s->dev), l, dev)
1891 if (evas_device_class_get(dev) == EVAS_DEVICE_CLASS_MOUSE)
1892 ecore_evas_cursor_device_unset(ee, dev);
1893 }
1894 s->ptr.cursor.surface = NULL;
1895 }
1896 if (s->drag.surface == cs) s->drag.surface = NULL;
1897 }
1898 eina_hash_list_remove(cs->c->client_surfaces, &client, cs);
1899 if (cs->render_queue)
1900 cs->c->render_queue = eina_list_remove(cs->c->render_queue, cs);
1901 subsurfaces = cs->pending_subsurfaces ?: cs->subsurfaces;
1902 EINA_LIST_FREE(subsurfaces, css)
1903 {
1904 evas_object_hide(css->surface->obj);
1905 comp_surface_reparent(css->surface, NULL);
1906 }
1907 if (cs->pending_subsurfaces) eina_list_free(cs->subsurfaces);
1908 cs->pending_subsurfaces = cs->subsurfaces = NULL;
1909 comp_surface_buffer_detach(&cs->buffer[0]);
1910 cs->res = NULL;
1911 if (cs->post_render_queue && (!cs->dead))
1912 {
1913 Eina_List *l;
1914 Eo *o;
1915
1916 cs->dead = 1;
1917 evas_object_hide(cs->obj);
1918 EINA_LIST_FOREACH(cs->proxies, l, o)
1919 evas_object_hide(o);
1920 }
1921 else
1922 {
1923 comp_surface_buffer_detach(&cs->buffer[1]);
1924 if (!cs->dead) evas_object_del(cs->obj);
1925 }
1926}
1927
1928
1929static inline Eina_Bool
1930comp_surface_check_grab(Comp_Surface *cs, Comp_Seat *s)
1931{
1932 Comp_Surface *parent;
1933 if (!s->grab) return EINA_TRUE;
1934 if (cs == s->grab) return EINA_TRUE;
1935 parent = s->grab->parent;
1936 while (parent)
1937 {
1938 if (cs == parent) return EINA_TRUE;
1939 parent = parent->parent;
1940 }
1941 return EINA_FALSE;
1942}
1943
1944static void
1945comp_surface_input_event(Eina_Inlist **list, uint32_t id, uint32_t serial, uint32_t time, Eina_Bool up)
1946{
1947 Input_Sequence *ev;
1948
1949 if (up)
1950 {
1951 EINA_INLIST_FOREACH(*list, ev)
1952 if (ev->id == id)
1953 {
1954 ev->up_serial = serial;
1955 ev->up_time = time;
1956 return;
1957 }
1958 return;
1959 }
1960 ev = calloc(1, sizeof(Input_Sequence));
1961 ev->id = id;
1962 ev->down_serial = serial;
1963 ev->down_time = time;
1964 *list = eina_inlist_append(*list, EINA_INLIST_GET(ev));
1965}
1966
1967static void
1968comp_surface_send_data_device_enter(Comp_Surface *cs, Comp_Seat *s)
1969{
1970 struct wl_resource *offer = NULL;
1971 int x, y, cx, cy;
1972 uint32_t serial;
1973 struct wl_resource *res = data_device_find(s, cs->res);
1974
1975
1976 if (!res) return;
1977 evas_object_geometry_get(cs->obj, &x, &y, NULL, NULL);
1978 if (s->drag.tch)
1979 cx = s->tch.pos.x, cy = s->tch.pos.y;
1980 else
1981 cx = s->ptr.pos.x, cy = s->ptr.pos.y;
1982 if (s->drag.source)
1983 {
1984 data_device_offer_create(s->drag.source, res);
1985 s->drag.source->offer->type = COMP_DATA_DEVICE_OFFER_TYPE_DND;
1986 offer = s->drag.source->offer->res;
1987 }
1988 s->drag.enter = cs;
1989 s->ptr.enter_serial = serial = wl_display_next_serial(cs->c->display);
1990 wl_data_device_send_enter(res, serial, cs->res,
1991 wl_fixed_from_int(cx - x), wl_fixed_from_int(cy - y), offer);
1992}
1993
1994static Eina_Bool
1995comp_surface_send_pointer_enter(Comp_Surface *cs, Comp_Seat *s, int cx, int cy)
1996{
1997 Eina_List *l, *ll;
1998 struct wl_resource *res;
1999 uint32_t serial;
2000 int x, y;
2001
2002 if (s->ptr.enter && (cs != s->grab)) return EINA_FALSE;
2003 if (!comp_surface_check_grab(cs, s)) return EINA_FALSE;
2004 s->ptr.enter = cs;
2005 if (cs->dead) return EINA_FALSE;
2006 if (s->drag.res && (!s->drag.tch))
2007 {
2008 comp_surface_send_data_device_enter(cs, s);
2009 return EINA_TRUE;
2010 }
2011 l = seat_ptr_resources_get(s, wl_resource_get_client(cs->res));
2012 if (!l) return EINA_FALSE;
2013 s->ptr.enter_serial = serial = wl_display_next_serial(cs->c->display);
2014 //fprintf(stderr, "ENTER %s\n", cs->shell.popup ? "POPUP" : "TOPLEVEL");
2015 evas_object_geometry_get(cs->obj, &x, &y, NULL, NULL);
2016 EINA_LIST_FOREACH(l, ll, res)
2017 wl_pointer_send_enter(res, serial, cs->res,
2018 wl_fixed_from_int(cx - x), wl_fixed_from_int(cy - y));
2019 return EINA_TRUE;
2020}
2021
2022static void
2023comp_surface_mouse_in(void *data, Evas *e EINA_UNUSED, Eo *obj EINA_UNUSED, void *event_info)
2024{
2025 Evas_Event_Mouse_In *ev = event_info;
2026 Comp_Seat *s;
2027
2028 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
2029 s = seat_find(data, ev->dev);
2030 if (comp_surface_send_pointer_enter(data, s, ev->canvas.x, ev->canvas.y))
2031 {
2032 s->event_propagate = 1;
2033 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2034 }
2035}
2036
2037static void
2038comp_surface_send_data_device_leave(Comp_Surface *cs, Comp_Seat *s)
2039{
2040 struct wl_resource *res = data_device_find(s, cs->res);
2041 if (!res) return;
2042 if (s->drag.source)
2043 {
2044 s->drag.source->offer->source = NULL;
2045 s->drag.source->offer = NULL;
2046 }
2047 s->drag.enter = NULL;
2048 wl_data_device_send_leave(res);
2049}
2050
2051static Eina_Bool
2052comp_surface_send_pointer_leave(Comp_Surface *cs, Comp_Seat *s)
2053{
2054 Eina_List *l, *ll;
2055 struct wl_resource *res;
2056 uint32_t serial;
2057
2058 if (s->ptr.enter != cs) return EINA_FALSE;
2059 if (!comp_surface_check_grab(cs, s)) return EINA_FALSE;
2060 s->ptr.enter = NULL;
2061 if (cs->dead) return EINA_FALSE;
2062 if (s->drag.res)
2063 {
2064 comp_surface_send_data_device_leave(cs, s);
2065 return EINA_TRUE;
2066 }
2067 l = seat_ptr_resources_get(s, wl_resource_get_client(cs->res));
2068 if (!l) return EINA_FALSE;
2069 serial = wl_display_next_serial(cs->c->display);
2070 //fprintf(stderr, "LEAVE %s\n", cs->shell.popup ? "POPUP" : "TOPLEVEL");
2071 EINA_LIST_FOREACH(l, ll, res)
2072 wl_pointer_send_leave(res, serial, cs->res);
2073 return EINA_TRUE;
2074}
2075
2076static void
2077comp_surface_mouse_out(void *data, Evas *e EINA_UNUSED, Eo *obj EINA_UNUSED, void *event_info)
2078{
2079 Evas_Event_Mouse_Out *ev = event_info;
2080 Comp_Seat *s;
2081
2082 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
2083 s = seat_find(data, ev->dev);
2084 if (comp_surface_send_pointer_leave(data, s))
2085 {
2086 s->event_propagate = 1;
2087 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2088 }
2089}
2090
2091static Eina_Bool
2092comp_surface_mouse_button(Comp_Surface *cs, Comp_Seat *s, uint32_t timestamp, uint32_t button_id, uint32_t state)
2093{
2094 uint32_t serial, btn;
2095 Eina_List *l, *ll;
2096 struct wl_resource *res;
2097
2098 switch (button_id)
2099 {
2100 case 1:
2101 btn = BTN_LEFT;
2102 break;
2103 case 2:
2104 btn = BTN_MIDDLE;
2105 break;
2106 case 3:
2107 btn = BTN_RIGHT;
2108 break;
2109 case 4:
2110 btn = BTN_SIDE;
2111 break;
2112 case 5:
2113 btn = BTN_EXTRA;
2114 break;
2115 case 6:
2116 btn = BTN_FORWARD;
2117 break;
2118 case 7:
2119 btn = BTN_BACK;
2120 break;
2121 default:
2122 btn = button_id + BTN_SIDE - 8;
2123 break;
2124 }
2125 if (s->ptr.enter != cs) return EINA_FALSE;
2126 if (!comp_surface_check_grab(cs, s)) return EINA_FALSE;
2127 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
2128 s->ptr.button_mask |= 1 << button_id;
2129 else
2130 {
2131 if (!(s->ptr.button_mask & (1 << button_id))) return EINA_FALSE;
2132 s->ptr.button_mask &= ~(1 << button_id);
2133 if (s->drag.res && (!s->drag.tch))
2134 {
2135 drag_grab_button(s, timestamp, button_id, WL_POINTER_BUTTON_STATE_RELEASED);
2136 comp_surface_input_event(&s->ptr.events, button_id, 0, timestamp, state == WL_POINTER_BUTTON_STATE_RELEASED);
2137 s->ptr.enter = NULL;
2138 comp_surface_send_pointer_enter(cs, s, s->ptr.pos.x, s->ptr.pos.y);
2139 return EINA_TRUE;
2140 }
2141 }
2142
2143 if (cs->dead)
2144 {
2145 comp_surface_input_event(&s->ptr.events, button_id, 0, timestamp, state == WL_POINTER_BUTTON_STATE_RELEASED);
2146 return EINA_TRUE;
2147 }
2148
2149 l = seat_ptr_resources_get(s, wl_resource_get_client(cs->res));
2150 if (!l) return EINA_FALSE;
2151 serial = wl_display_next_serial(s->c->display);
2152 comp_surface_input_event(&s->ptr.events, button_id, serial, timestamp, state == WL_POINTER_BUTTON_STATE_RELEASED);
2153
2154 EINA_LIST_FOREACH(l, ll, res)
2155 wl_pointer_send_button(res, serial, timestamp, btn, state);
2156 return EINA_TRUE;
2157}
2158
2159static void
2160comp_surface_mouse_down(void *data, Evas *e EINA_UNUSED, Eo *obj EINA_UNUSED, void *event_info)
2161{
2162 Evas_Event_Mouse_Down *ev = event_info;
2163 Comp_Seat *s;
2164
2165 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
2166 s = seat_find(data, ev->dev);
2167 if (comp_surface_mouse_button(data, s, ev->timestamp, ev->button, WL_POINTER_BUTTON_STATE_PRESSED))
2168 {
2169 s->event_propagate = 1;
2170 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2171 }
2172}
2173
2174static void
2175comp_surface_mouse_up(void *data, Evas *e EINA_UNUSED, Eo *obj EINA_UNUSED, void *event_info)
2176{
2177 Evas_Event_Mouse_Down *ev = event_info;
2178 Comp_Seat *s;
2179
2180 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
2181 s = seat_find(data, ev->dev);
2182 if (comp_surface_mouse_button(data, s, ev->timestamp, ev->button, WL_POINTER_BUTTON_STATE_RELEASED))
2183 {
2184 s->event_propagate = 1;
2185 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2186 }
2187}
2188
2189static void
2190comp_surface_mouse_move(void *data, Evas *e EINA_UNUSED, Eo *obj EINA_UNUSED, void *event_info)
2191{
2192 Evas_Event_Mouse_Move *ev = event_info;
2193 Comp_Surface *cs = data;
2194 Eina_List *l = NULL, *ll;
2195 struct wl_resource *res;
2196 int x, y;
2197 Comp_Seat *s;
2198
2199 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
2200 if (cs->dead) return;
2201 s = seat_find(data, ev->dev);
2202 if (s->ptr.enter != cs) return;
2203 if (!comp_surface_check_grab(cs, s)) return;
2204 if (s->drag.res)
2205 {
2206 if (s->drag.enter != cs) return;
2207 res = data_device_find(s, cs->res);
2208 if (!res) return;
2209 }
2210 else
2211 {
2212 l = seat_ptr_resources_get(s, wl_resource_get_client(cs->res));
2213 if (!l) return;
2214 }
2215 evas_object_geometry_get(cs->obj, &x, &y, NULL, NULL);
2216 //fprintf(stderr, "MOTION %s\n", cs->shell.popup ? "POPUP" : "TOPLEVEL");
2217 if (s->drag.res)
2218 wl_data_device_send_motion(res, ev->timestamp,
2219 wl_fixed_from_int(ev->cur.canvas.x - x), wl_fixed_from_int(ev->cur.canvas.y - y));
2220 else
2221 {
2222 //int n = 0;
2223 EINA_LIST_FOREACH(l, ll, res)
2224 {
2225 //fprintf(stderr, "motion %d\n", n++);
2226 wl_pointer_send_motion(res, ev->timestamp,
2227 wl_fixed_from_int(ev->cur.canvas.x - x), wl_fixed_from_int(ev->cur.canvas.y - y));
2228 }
2229 }
2230 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2231 s->event_propagate = 1;
2232}
2233
2234static void
2235comp_surface_mouse_wheel(void *data, Evas *evas EINA_UNUSED, Eo *obj EINA_UNUSED, void *event)
2236{
2237 Evas_Event_Mouse_Wheel *ev = event;
2238 Comp_Surface *cs = data;
2239 Eina_List *l, *ll;
2240 struct wl_resource *res;
2241 uint32_t axis, dir;
2242 Comp_Seat *s;
2243
2244 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
2245 if (ev->direction == 0)
2246 axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
2247 else
2248 axis = WL_POINTER_AXIS_HORIZONTAL_SCROLL;
2249
2250 if (ev->z < 0)
2251 dir = -wl_fixed_from_int(abs(10 * ev->z));
2252 else
2253 dir = wl_fixed_from_int(10 * ev->z);
2254
2255 if (cs->dead) return;
2256 s = seat_find(data, ev->dev);
2257 if (s->ptr.enter != cs) return;
2258 if (!comp_surface_check_grab(cs, s)) return;
2259 l = seat_ptr_resources_get(s, wl_resource_get_client(cs->res));
2260 if (!l) return;
2261 EINA_LIST_FOREACH(l, ll, res)
2262 wl_pointer_send_axis(res, ev->timestamp, axis, dir);
2263 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2264 s->event_propagate = 1;
2265}
2266
2267static void
2268comp_surface_multi_down(void *data, Evas *e EINA_UNUSED, Eo *obj EINA_UNUSED, void *event_info)
2269{
2270 Evas_Event_Multi_Down *ev = event_info;
2271 Comp_Surface *cs = data;
2272 Eina_List *l, *ll;
2273 struct wl_resource *res;
2274 uint32_t serial;
2275 int x, y;
2276 Comp_Seat *s;
2277
2278 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
2279 if (cs->dead) return;
2280 s = seat_find(data, ev->dev);
2281 if (!comp_surface_check_grab(cs, s)) return;
2282 s->tch.enter = cs;
2283 l = seat_tch_resources_get(s, wl_resource_get_client(cs->res));
2284 if (!l)
2285 {
2286 comp_surface_input_event(&s->tch.events, ev->device, 0, ev->timestamp, 0);
2287 s->event_propagate = 1;
2288 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2289 return;
2290 }
2291 evas_object_geometry_get(cs->obj, &x, &y, NULL, NULL);
2292 serial = wl_display_next_serial(cs->c->display);
2293 comp_surface_input_event(&s->tch.events, ev->device, serial, ev->timestamp, 0);
2294 EINA_LIST_FOREACH(l, ll, res)
2295 wl_touch_send_down(res, serial, ev->timestamp, cs->res, ev->device,
2296 wl_fixed_from_int(ev->canvas.x - x), wl_fixed_from_int(ev->canvas.y - y));
2297 s->event_propagate = 1;
2298 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2299}
2300
2301static void
2302comp_surface_multi_up(void *data, Evas *e EINA_UNUSED, Eo *obj EINA_UNUSED, void *event_info)
2303{
2304 Evas_Event_Multi_Up *ev = event_info;
2305 Comp_Surface *cs = data;
2306 Eina_List *l, *ll;
2307 struct wl_resource *res;
2308 uint32_t serial;
2309 Comp_Seat *s;
2310
2311 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
2312 if (cs->dead) return;
2313 s = seat_find(data, ev->dev);
2314 if (!comp_surface_check_grab(cs, s)) return;
2315 if (!ev->device)
2316 s->tch.enter = NULL;
2317 l = seat_tch_resources_get(s, wl_resource_get_client(cs->res));
2318 if ((!l) || (s->drag.tch && ((uint32_t)ev->device == s->drag.id)))
2319 {
2320 if (s->drag.tch)
2321 {
2322 res = data_device_find(s, cs->res);
2323 if (!res) return;
2324
2325 wl_data_device_send_drop(res);
2326 }
2327 comp_surface_input_event(&s->tch.events, ev->device, 0, ev->timestamp, 1);
2328 s->event_propagate = 1;
2329 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2330 return;
2331 }
2332 serial = wl_display_next_serial(cs->c->display);
2333 comp_surface_input_event(&s->tch.events, ev->device, serial, ev->timestamp, 1);
2334 EINA_LIST_FOREACH(l, ll, res)
2335 wl_touch_send_up(res, serial, ev->timestamp, ev->device);
2336 s->event_propagate = 1;
2337 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2338}
2339
2340static void
2341comp_surface_multi_move(void *data, Evas *e EINA_UNUSED, Eo *obj EINA_UNUSED, void *event_info)
2342{
2343 Evas_Event_Multi_Move *ev = event_info;
2344 Comp_Surface *cs = data;
2345 struct wl_resource *res;
2346 int x, y;
2347 Comp_Seat *s;
2348
2349 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
2350 if (cs->dead) return;
2351 s = seat_find(data, ev->dev);
2352 if (!comp_surface_check_grab(cs, s)) return;
2353 evas_object_geometry_get(cs->obj, &x, &y, NULL, NULL);
2354 if (s->drag.tch)
2355 {
2356 if (s->drag.enter != cs) return;
2357 res = data_device_find(s, cs->res);
2358 if (res)
2359 {
2360 wl_data_device_send_motion(res, ev->timestamp,
2361 wl_fixed_from_int(ev->cur.canvas.x - x), wl_fixed_from_int(ev->cur.canvas.y - y));
2362 s->event_propagate = 1;
2363 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2364 }
2365 return;
2366 }
2367 else
2368 {
2369 Eina_List *l, *ll;
2370
2371 l = seat_tch_resources_get(s, wl_resource_get_client(cs->res));
2372 if (!l) return;
2373 EINA_LIST_FOREACH(l, ll, res)
2374 wl_touch_send_motion(res, ev->timestamp, ev->device,
2375 wl_fixed_from_int(ev->cur.canvas.x - x), wl_fixed_from_int(ev->cur.canvas.y - y));
2376 s->event_propagate = 1;
2377 ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
2378 }
2379}
2380
2381EOLIAN static Eo *
2382_efl_wl_surface_efl_object_constructor(Eo *obj, Comp_Surface *cs EINA_UNUSED)
2383{
2384 efl_canvas_group_clipped_set(obj, EINA_TRUE);
2385 return efl_constructor(efl_super(obj, EFL_WL_SURFACE_CLASS));
2386}
2387
2388static void
2389_efl_wl_surface_efl_canvas_group_group_add(Eo *obj, Comp_Surface *cs)
2390{
2391 Evas *e;
2392
2393 efl_canvas_group_add(efl_super(obj, EFL_WL_SURFACE_CLASS));
2394 cs->obj = obj;
2395 evas_object_event_callback_add(cs->obj, EVAS_CALLBACK_MOUSE_DOWN, comp_surface_mouse_down, cs);
2396 evas_object_event_callback_add(cs->obj, EVAS_CALLBACK_MOUSE_UP, comp_surface_mouse_up, cs);
2397 evas_object_event_callback_add(cs->obj, EVAS_CALLBACK_MOUSE_IN, comp_surface_mouse_in, cs);
2398 evas_object_event_callback_add(cs->obj, EVAS_CALLBACK_MOUSE_OUT, comp_surface_mouse_out, cs);
2399 evas_object_event_callback_add(cs->obj, EVAS_CALLBACK_MOUSE_MOVE, comp_surface_mouse_move, cs);
2400 evas_object_event_callback_add(cs->obj, EVAS_CALLBACK_MOUSE_WHEEL, comp_surface_mouse_wheel, cs);
2401 evas_object_event_callback_add(cs->obj, EVAS_CALLBACK_MULTI_DOWN, comp_surface_multi_down, cs);
2402 evas_object_event_callback_add(cs->obj, EVAS_CALLBACK_MULTI_UP, comp_surface_multi_up, cs);
2403 evas_object_event_callback_add(cs->obj, EVAS_CALLBACK_MULTI_MOVE, comp_surface_multi_move, cs);
2404 e = evas_object_evas_get(obj);
2405 cs->img = evas_object_image_filled_add(e);
2406 evas_object_show(cs->img);
2407 cs->clip = (Eo*)efl_canvas_group_clipper_get(obj);
2408 efl_gfx_entity_geometry_set(cs->clip, efl_gfx_entity_geometry_get(obj));
2409
2410 evas_object_smart_member_add(cs->img, cs->obj);
2411 evas_object_image_border_center_fill_set(cs->img, EVAS_BORDER_FILL_SOLID);
2412 evas_object_image_colorspace_set(cs->img, EVAS_COLORSPACE_ARGB8888);
2413}
2414
2415static void
2416_efl_wl_surface_efl_canvas_group_group_del(Eo *obj, Comp_Surface *cs)
2417{
2418 array_clear(&cs->input_rects);
2419 array_clear(&cs->opaque_rects);
2420 eina_tiler_free(cs->opaque);
2421 eina_tiler_free(cs->input);
2422 comp_buffer_state_clear(&cs->pending);
2423 while (cs->proxies)
2424 evas_object_del(eina_list_data_get(cs->proxies));
2425 if (cs->res)
2426 {
2427 cs->dead = 1;
2428 wl_resource_destroy(cs->res);
2429 }
2430 evas_object_del(cs->img);
2431 if (cs->shell.surface)
2432 {
2433 if (cs->role)
2434 wl_resource_destroy(cs->role);
2435 wl_resource_destroy(cs->shell.surface);
2436 }
2437 cs->c->surfaces = eina_inlist_remove(cs->c->surfaces, EINA_INLIST_GET(cs));
2438 cs->c->surfaces_count--;
2439}
2440
2441static void
2442_efl_wl_surface_efl_gfx_entity_position_set(Eo *obj, Comp_Surface *cs, Eina_Position2D pos)
2443{
2444 efl_gfx_entity_position_set(efl_super(obj, EFL_WL_SURFACE_CLASS), pos);
2445 efl_gfx_entity_position_set(cs->clip, pos);
2446
2447 //{
2448 //if (cs->cursor)
2449 //fprintf(stderr, "COMP %sSURFACE(%p) %d,%d\n", cs->subsurface ? "SUB" : "", cs, x, y);
2450 //}
2451}
2452
2453static void
2454_efl_wl_surface_efl_gfx_entity_size_set(Eo *obj, Comp_Surface *cs, Eina_Size2D sz)
2455{
2456 efl_gfx_entity_size_set(efl_super(obj, EFL_WL_SURFACE_CLASS), sz);
2457 evas_object_resize(cs->clip, sz.w, sz.h);
2458 //if (cs->cursor) fprintf(stderr, "COMP %sSURFACE(%p) %dx%d\n", cs->subsurface ? "SUB" : "", cs, w, h);
2459 if (cs->drag)
2460 evas_object_move(cs->obj, cs->drag->ptr.pos.x, cs->drag->ptr.pos.y);
2461}
2462
2463static void
2464_efl_wl_surface_efl_gfx_entity_visible_set(Eo *obj, Comp_Surface *cs, Eina_Bool vis)
2465{
2466 Comp_Surface *pcs = NULL, *lcs;
2467 efl_gfx_entity_visible_set(efl_super(obj, EFL_WL_SURFACE_CLASS), vis);
2468 if (vis)
2469 {
2470 evas_object_show(cs->clip);
2471 cs->mapped = 1;
2472 return;
2473 }
2474 evas_object_hide(cs->clip);
2475 cs->mapped = 0;
2476
2477 if (!cs->shell.activated) return;
2478 cs->shell.activated = 0;
2479 if (cs->shell.popup && cs->role)
2480 xdg_popup_send_popup_done(cs->role);
2481 if (cs->parent && cs->shell.popup) return;
2482 /* attempt to revert focus based on stacking order */
2483 if (cs->parent)
2484 {
2485 EINA_INLIST_REVERSE_FOREACH(cs->parent->children, lcs)
2486 {
2487 if (lcs == cs) continue;
2488 if (!evas_object_visible_get(lcs->obj)) continue;
2489 if ((!lcs->shell.surface) || (!lcs->role)) continue;
2490 lcs->shell.activated = 1;
2491 if (lcs->shell.popup)
2492 {
2493 if (!lcs->extracted)
2494 evas_object_raise(lcs->obj);
2495 }
2496 else
2497 shell_surface_send_configure(lcs);
2498 return;
2499 }
2500 if (!cs->parent->shell.popup)
2501 {
2502 pcs = cs->parent;
2503 if (!pcs->mapped) pcs = NULL;
2504 }
2505 }
2506 if (cs->c->seats)
2507 comp_seats_redo_enter(cs->c, pcs);
2508}
2509
2510static void
2511comp_surface_create(struct wl_client *client, struct wl_resource *resource, uint32_t id)
2512{
2513 struct wl_resource *res;
2514 Comp_Surface *cs;
2515 Comp *c = wl_resource_get_user_data(resource);