1 /*
2 * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
3 * Copyright (C) 2007 Holger Hans Peter Freyther
4 * Copyright (C) 2008 Kenneth Rohde Christiansen
5 * Copyright (C) 2009-2010 ProFUSION embedded systems
6 * Copyright (C) 2009-2010 Samsung Electronics
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32 #include "Widget.h"
33
34 #include "ChromeClient.h"
35 #include "Cursor.h"
36 #include "Frame.h"
37 #include "FrameView.h"
38 #include "GraphicsContext.h"
39 #include "IntRect.h"
40 #include "NotImplemented.h"
41 #include "Page.h"
42
43 #include <Ecore.h>
44 #include <Ecore_Evas.h>
45 #include <Edje.h>
46 #include <Evas.h>
47
48 #ifdef HAVE_ECORE_X
49 #include <Ecore_X.h>
50 #include <Ecore_X_Cursor.h>
51 #endif
52
53 #include <wtf/HashMap.h>
54 #include <wtf/text/CString.h>
55
56 namespace WebCore {
57
58 #ifdef HAVE_ECORE_X
59 class CursorMap {
60 private:
61 HashMap<String, unsigned short> m_cursorStringMap;
62
63 public:
64 CursorMap();
65 unsigned int cursor(String);
66 };
67
cursor(String cursorGroup)68 unsigned int CursorMap::cursor(String cursorGroup)
69 {
70 int ret = m_cursorStringMap.get(cursorGroup);
71
72 if (ret < ECORE_X_CURSOR_X || ret > ECORE_X_CURSOR_XTERM)
73 ret = ECORE_X_CURSOR_LEFT_PTR;
74
75 return ret;
76 }
77
CursorMap()78 CursorMap::CursorMap()
79 {
80 m_cursorStringMap.set("cursor/pointer", ECORE_X_CURSOR_LEFT_PTR);
81 m_cursorStringMap.set("cursor/move", ECORE_X_CURSOR_FLEUR);
82 m_cursorStringMap.set("cursor/cross", ECORE_X_CURSOR_CROSS);
83 m_cursorStringMap.set("cursor/hand", ECORE_X_CURSOR_HAND2);
84 m_cursorStringMap.set("cursor/i_beam", ECORE_X_CURSOR_XTERM);
85 m_cursorStringMap.set("cursor/wait", ECORE_X_CURSOR_WATCH);
86 m_cursorStringMap.set("cursor/help", ECORE_X_CURSOR_QUESTION_ARROW);
87 m_cursorStringMap.set("cursor/east_resize", ECORE_X_CURSOR_RIGHT_SIDE);
88 m_cursorStringMap.set("cursor/north_resize", ECORE_X_CURSOR_TOP_SIDE);
89 m_cursorStringMap.set("cursor/north_east_resize", ECORE_X_CURSOR_TOP_RIGHT_CORNER);
90 m_cursorStringMap.set("cursor/north_west_resize", ECORE_X_CURSOR_TOP_LEFT_CORNER);
91 m_cursorStringMap.set("cursor/south_resize", ECORE_X_CURSOR_BOTTOM_SIDE);
92 m_cursorStringMap.set("cursor/south_east_resize", ECORE_X_CURSOR_BOTTOM_RIGHT_CORNER);
93 m_cursorStringMap.set("cursor/south_west_resize", ECORE_X_CURSOR_BOTTOM_LEFT_CORNER);
94 m_cursorStringMap.set("cursor/west_resize", ECORE_X_CURSOR_LEFT_SIDE);
95 m_cursorStringMap.set("cursor/north_south_resize", ECORE_X_CURSOR_SB_H_DOUBLE_ARROW);
96 m_cursorStringMap.set("cursor/east_west_resize", ECORE_X_CURSOR_SB_V_DOUBLE_ARROW);
97 m_cursorStringMap.set("cursor/north_east_south_west_resize", ECORE_X_CURSOR_SIZING);
98 m_cursorStringMap.set("cursor/north_west_south_east_resize", ECORE_X_CURSOR_SIZING);
99 m_cursorStringMap.set("cursor/column_resize", ECORE_X_CURSOR_SB_V_DOUBLE_ARROW);
100 m_cursorStringMap.set("cursor/row_resize", ECORE_X_CURSOR_SB_H_DOUBLE_ARROW);
101 m_cursorStringMap.set("cursor/middle_panning", ECORE_X_CURSOR_CROSS_REVERSE);
102 m_cursorStringMap.set("cursor/east_panning", ECORE_X_CURSOR_CROSS_REVERSE);
103 m_cursorStringMap.set("cursor/north_panning", ECORE_X_CURSOR_CROSS_REVERSE);
104 m_cursorStringMap.set("cursor/north_east_panning", ECORE_X_CURSOR_CROSS_REVERSE);
105 m_cursorStringMap.set("cursor/north_west_panning", ECORE_X_CURSOR_CROSS_REVERSE);
106 m_cursorStringMap.set("cursor/south_panning", ECORE_X_CURSOR_CROSS_REVERSE);
107 m_cursorStringMap.set("cursor/south_east_panning", ECORE_X_CURSOR_CROSS_REVERSE);
108 m_cursorStringMap.set("cursor/south_west_panning", ECORE_X_CURSOR_CROSS_REVERSE);
109 m_cursorStringMap.set("cursor/west_panning", ECORE_X_CURSOR_CROSS_REVERSE);
110 m_cursorStringMap.set("cursor/vertical_text", ECORE_X_CURSOR_SB_DOWN_ARROW);
111 m_cursorStringMap.set("cursor/cell", ECORE_X_CURSOR_ICON);
112 m_cursorStringMap.set("cursor/context_menu", ECORE_X_CURSOR_HAND2);
113 m_cursorStringMap.set("cursor/no_drop", ECORE_X_CURSOR_DOT_BOX_MASK);
114 m_cursorStringMap.set("cursor/copy", ECORE_X_CURSOR_ICON);
115 m_cursorStringMap.set("cursor/progress", ECORE_X_CURSOR_WATCH);
116 m_cursorStringMap.set("cursor/alias", ECORE_X_CURSOR_MAN);
117 m_cursorStringMap.set("cursor/none", ECORE_X_CURSOR_X);
118 m_cursorStringMap.set("cursor/not_allowed", ECORE_X_CURSOR_X);
119 m_cursorStringMap.set("cursor/zoom_in", ECORE_X_CURSOR_DIAMOND_CROSS);
120 m_cursorStringMap.set("cursor/zoom_out", ECORE_X_CURSOR_DIAMOND_CROSS);
121 m_cursorStringMap.set("cursor/grab", ECORE_X_CURSOR_HAND2);
122 m_cursorStringMap.set("cursor/grabbing", ECORE_X_CURSOR_HAND2);
123 }
124
125 static CursorMap cursorStringMap = CursorMap();
126 #endif
127
128 class WidgetPrivate {
129 public:
130 Evas* m_evas;
131 Evas_Object* m_evasObject;
132 String m_theme;
133
WidgetPrivate()134 WidgetPrivate()
135 : m_evas(0)
136 , m_evasObject(0)
137 , m_cursorObject(0)
138 #ifdef HAVE_ECORE_X
139 , m_isUsingEcoreX(false)
140 #endif
141 {}
142
143 /* cursor */
144 String m_cursorGroup;
145 Evas_Object* m_cursorObject;
146
147 #ifdef HAVE_ECORE_X
148 bool m_isUsingEcoreX;
149 #endif
150 };
151
Widget(PlatformWidget widget)152 Widget::Widget(PlatformWidget widget)
153 : m_parent(0)
154 , m_widget(0)
155 , m_selfVisible(false)
156 , m_parentVisible(false)
157 , m_frame(0, 0, 0, 0)
158 , m_data(new WidgetPrivate)
159 {
160 init(widget);
161 }
162
~Widget()163 Widget::~Widget()
164 {
165 ASSERT(!parent());
166
167 if (m_data->m_cursorObject)
168 evas_object_del(m_data->m_cursorObject);
169
170 delete m_data;
171 }
172
frameRect() const173 IntRect Widget::frameRect() const
174 {
175 return m_frame;
176 }
177
setFrameRect(const IntRect & rect)178 void Widget::setFrameRect(const IntRect& rect)
179 {
180 m_frame = rect;
181 Widget::frameRectsChanged();
182 }
183
frameRectsChanged()184 void Widget::frameRectsChanged()
185 {
186 Evas_Object* object = evasObject();
187 Evas_Coord x, y;
188
189 if (!parent() || !object)
190 return;
191
192 IntRect rect = frameRect();
193 if (parent()->isScrollViewScrollbar(this))
194 rect.setLocation(parent()->convertToContainingWindow(rect.location()));
195 else
196 rect.setLocation(parent()->contentsToWindow(rect.location()));
197
198 evas_object_geometry_get(root()->evasObject(), &x, &y, 0, 0);
199 evas_object_move(object, x + rect.x(), y + rect.y());
200 evas_object_resize(object, rect.width(), rect.height());
201 }
202
setFocus(bool focused)203 void Widget::setFocus(bool focused)
204 {
205 }
206
applyFallbackCursor()207 void Widget::applyFallbackCursor()
208 {
209 #ifdef HAVE_ECORE_X
210 if (m_data->m_isUsingEcoreX && !m_data->m_cursorGroup.isNull()) {
211 int shape = cursorStringMap.cursor(m_data->m_cursorGroup.utf8().data());
212
213 if (shape < ECORE_X_CURSOR_X || shape > ECORE_X_CURSOR_XTERM) {
214 LOG_ERROR("cannot map an equivalent X cursor for"
215 " c ursor group %s", m_data->m_cursorGroup.utf8().data());
216 shape = ECORE_X_CURSOR_LEFT_PTR;
217 }
218
219 Ecore_X_Window win = ecore_evas_software_x11_window_get(ecoreEvas());
220 Ecore_X_Cursor cur = ecore_x_cursor_shape_get(shape);
221 ecore_x_window_cursor_set(win, cur);
222 return;
223 }
224 #endif
225 LOG_ERROR("Ooops, no fallback to set cursor %s!\n",
226 m_data->m_cursorGroup.utf8().data());
227 }
228
applyCursor()229 void Widget::applyCursor()
230 {
231 CString file = edjeThemeRecursive().utf8();
232
233 m_data->m_cursorObject = edje_object_add(evas());
234 if (!file.isNull() && !edje_object_file_set(m_data->m_cursorObject, file.data(), m_data->m_cursorGroup.utf8().data())) {
235 evas_object_del(m_data->m_cursorObject);
236 m_data->m_cursorObject = 0;
237 ecore_evas_object_cursor_set(ecoreEvas(), 0, 0, 0, 0);
238 applyFallbackCursor();
239 } else {
240 Evas_Coord x, y, w, h;
241 const char *d;
242
243 edje_object_size_min_get(m_data->m_cursorObject, &w, &h);
244 if ((w <= 0) || (h <= 0))
245 edje_object_size_min_calc(m_data->m_cursorObject, &w, &h);
246 if ((w <= 0) || (h <= 0))
247 w = h = 16;
248 evas_object_resize(m_data->m_cursorObject, w, h);
249
250 d = edje_object_data_get(m_data->m_cursorObject, "hot.x");
251 x = d ? atoi(d) : 0;
252
253 d = edje_object_data_get(m_data->m_cursorObject, "hot.y");
254 y = d ? atoi(d) : 0;
255
256 ecore_evas_object_cursor_set(ecoreEvas(), m_data->m_cursorObject,
257 EVAS_LAYER_MAX, x, y);
258 }
259 }
260
setCursor(const Cursor & cursor)261 void Widget::setCursor(const Cursor& cursor)
262 {
263 if (!evas())
264 return;
265
266 const char *group = cursor.impl();
267 if (!group || String(group) == m_data->m_cursorGroup)
268 return;
269
270 m_data->m_cursorGroup = group;
271
272 applyCursor();
273 }
274
show()275 void Widget::show()
276 {
277 if (!platformWidget())
278 return;
279
280 evas_object_show(platformWidget());
281 }
282
hide()283 void Widget::hide()
284 {
285 if (!platformWidget())
286 return;
287
288 evas_object_hide(platformWidget());
289 }
290
paint(GraphicsContext * context,const IntRect &)291 void Widget::paint(GraphicsContext* context, const IntRect&)
292 {
293 notImplemented();
294 }
295
setIsSelected(bool)296 void Widget::setIsSelected(bool)
297 {
298 notImplemented();
299 }
300
edjeTheme() const301 const String Widget::edjeTheme() const
302 {
303 return m_data->m_theme;
304 }
305
setEdjeTheme(const String & themePath)306 void Widget::setEdjeTheme(const String& themePath)
307 {
308 if (m_data->m_theme == themePath)
309 return;
310
311 m_data->m_theme = themePath;
312 }
313
edjeThemeRecursive() const314 const String Widget::edjeThemeRecursive() const
315 {
316 if (!m_data->m_theme.isNull())
317 return m_data->m_theme;
318 if (m_parent)
319 return m_parent->edjeThemeRecursive();
320
321 return String();
322 }
323
evas() const324 Evas* Widget::evas() const
325 {
326 return m_data->m_evas;
327 }
328
ecoreEvas() const329 Ecore_Evas* Widget::ecoreEvas() const
330 {
331 // FIXME EFL: XXX assume evas was created by ecore_evas
332 return static_cast<Ecore_Evas*>(evas_data_attach_get(evas()));
333 }
334
setEvasObject(Evas_Object * object)335 void Widget::setEvasObject(Evas_Object *object)
336 {
337 // FIXME: study platformWidget() and use it
338 // FIXME: right now platformWidget() requires implementing too much
339 if (m_data->m_evasObject == object)
340 return;
341 m_data->m_evasObject = object;
342 if (!object) {
343 m_data->m_evas = 0;
344 #ifdef HAVE_ECORE_X
345 m_data->m_isUsingEcoreX = false;
346 #endif
347 return;
348 }
349
350 m_data->m_evas = evas_object_evas_get(object);
351
352 #ifdef HAVE_ECORE_X
353 const char *engine = ecore_evas_engine_name_get(ecoreEvas());
354 m_data->m_isUsingEcoreX = (!strcmp(engine, "software_x11")
355 || !strcmp(engine, "software_xcb")
356 || !strcmp(engine, "software_16_x11")
357 || !strncmp(engine, "xrender", sizeof("xrender") - 1));
358 #endif
359
360 Widget::frameRectsChanged();
361 }
362
evasObject() const363 Evas_Object* Widget::evasObject() const
364 {
365 return m_data->m_evasObject;
366 }
367
368 }
369