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