• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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