Home | History | Annotate | Download | only in efl
      1 /*
      2  * Copyright (C) 2006 Michael Emmel mike.emmel (at) 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 
     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 
     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 
    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 
    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 
    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 
    173 IntRect Widget::frameRect() const
    174 {
    175     return m_frame;
    176 }
    177 
    178 void Widget::setFrameRect(const IntRect& rect)
    179 {
    180     m_frame = rect;
    181     Widget::frameRectsChanged();
    182 }
    183 
    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 
    203 void Widget::setFocus(bool focused)
    204 {
    205 }
    206 
    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 
    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 
    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 
    275 void Widget::show()
    276 {
    277     if (!platformWidget())
    278          return;
    279 
    280     evas_object_show(platformWidget());
    281 }
    282 
    283 void Widget::hide()
    284 {
    285     if (!platformWidget())
    286          return;
    287 
    288     evas_object_hide(platformWidget());
    289 }
    290 
    291 void Widget::paint(GraphicsContext* context, const IntRect&)
    292 {
    293     notImplemented();
    294 }
    295 
    296 void Widget::setIsSelected(bool)
    297 {
    298     notImplemented();
    299 }
    300 
    301 const String Widget::edjeTheme() const
    302 {
    303     return m_data->m_theme;
    304 }
    305 
    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 
    314 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 
    324 Evas* Widget::evas() const
    325 {
    326     return m_data->m_evas;
    327 }
    328 
    329 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 
    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 
    363 Evas_Object* Widget::evasObject() const
    364 {
    365     return m_data->m_evasObject;
    366 }
    367 
    368 }
    369