blob: 06414ed85d2eb77f23898adefbbf976941303b4f [file] [log] [blame]
/*
* Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
* Copyright (C) 2007 Holger Hans Peter Freyther
* Copyright (C) 2008 Kenneth Rohde Christiansen
* Copyright (C) 2009-2010 ProFUSION embedded systems
* Copyright (C) 2009-2010 Samsung Electronics
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "Widget.h"
#include "ChromeClient.h"
#include "Cursor.h"
#include "Frame.h"
#include "FrameView.h"
#include "GraphicsContext.h"
#include "IntRect.h"
#include "NotImplemented.h"
#include "Page.h"
#include <Ecore.h>
#include <Ecore_Evas.h>
#include <Edje.h>
#include <Evas.h>
#ifdef HAVE_ECORE_X
#include <Ecore_X.h>
#include <Ecore_X_Cursor.h>
#endif
#include <wtf/HashMap.h>
#include <wtf/text/CString.h>
namespace WebCore {
#ifdef HAVE_ECORE_X
class CursorMap {
private:
HashMap<String, unsigned short> m_cursorStringMap;
public:
CursorMap();
unsigned int cursor(String);
};
unsigned int CursorMap::cursor(String cursorGroup)
{
int ret = m_cursorStringMap.get(cursorGroup);
if (ret < ECORE_X_CURSOR_X || ret > ECORE_X_CURSOR_XTERM)
ret = ECORE_X_CURSOR_LEFT_PTR;
return ret;
}
CursorMap::CursorMap()
{
m_cursorStringMap.set("cursor/pointer", ECORE_X_CURSOR_LEFT_PTR);
m_cursorStringMap.set("cursor/move", ECORE_X_CURSOR_FLEUR);
m_cursorStringMap.set("cursor/cross", ECORE_X_CURSOR_CROSS);
m_cursorStringMap.set("cursor/hand", ECORE_X_CURSOR_HAND2);
m_cursorStringMap.set("cursor/i_beam", ECORE_X_CURSOR_XTERM);
m_cursorStringMap.set("cursor/wait", ECORE_X_CURSOR_WATCH);
m_cursorStringMap.set("cursor/help", ECORE_X_CURSOR_QUESTION_ARROW);
m_cursorStringMap.set("cursor/east_resize", ECORE_X_CURSOR_RIGHT_SIDE);
m_cursorStringMap.set("cursor/north_resize", ECORE_X_CURSOR_TOP_SIDE);
m_cursorStringMap.set("cursor/north_east_resize", ECORE_X_CURSOR_TOP_RIGHT_CORNER);
m_cursorStringMap.set("cursor/north_west_resize", ECORE_X_CURSOR_TOP_LEFT_CORNER);
m_cursorStringMap.set("cursor/south_resize", ECORE_X_CURSOR_BOTTOM_SIDE);
m_cursorStringMap.set("cursor/south_east_resize", ECORE_X_CURSOR_BOTTOM_RIGHT_CORNER);
m_cursorStringMap.set("cursor/south_west_resize", ECORE_X_CURSOR_BOTTOM_LEFT_CORNER);
m_cursorStringMap.set("cursor/west_resize", ECORE_X_CURSOR_LEFT_SIDE);
m_cursorStringMap.set("cursor/north_south_resize", ECORE_X_CURSOR_SB_H_DOUBLE_ARROW);
m_cursorStringMap.set("cursor/east_west_resize", ECORE_X_CURSOR_SB_V_DOUBLE_ARROW);
m_cursorStringMap.set("cursor/north_east_south_west_resize", ECORE_X_CURSOR_SIZING);
m_cursorStringMap.set("cursor/north_west_south_east_resize", ECORE_X_CURSOR_SIZING);
m_cursorStringMap.set("cursor/column_resize", ECORE_X_CURSOR_SB_V_DOUBLE_ARROW);
m_cursorStringMap.set("cursor/row_resize", ECORE_X_CURSOR_SB_H_DOUBLE_ARROW);
m_cursorStringMap.set("cursor/middle_panning", ECORE_X_CURSOR_CROSS_REVERSE);
m_cursorStringMap.set("cursor/east_panning", ECORE_X_CURSOR_CROSS_REVERSE);
m_cursorStringMap.set("cursor/north_panning", ECORE_X_CURSOR_CROSS_REVERSE);
m_cursorStringMap.set("cursor/north_east_panning", ECORE_X_CURSOR_CROSS_REVERSE);
m_cursorStringMap.set("cursor/north_west_panning", ECORE_X_CURSOR_CROSS_REVERSE);
m_cursorStringMap.set("cursor/south_panning", ECORE_X_CURSOR_CROSS_REVERSE);
m_cursorStringMap.set("cursor/south_east_panning", ECORE_X_CURSOR_CROSS_REVERSE);
m_cursorStringMap.set("cursor/south_west_panning", ECORE_X_CURSOR_CROSS_REVERSE);
m_cursorStringMap.set("cursor/west_panning", ECORE_X_CURSOR_CROSS_REVERSE);
m_cursorStringMap.set("cursor/vertical_text", ECORE_X_CURSOR_SB_DOWN_ARROW);
m_cursorStringMap.set("cursor/cell", ECORE_X_CURSOR_ICON);
m_cursorStringMap.set("cursor/context_menu", ECORE_X_CURSOR_HAND2);
m_cursorStringMap.set("cursor/no_drop", ECORE_X_CURSOR_DOT_BOX_MASK);
m_cursorStringMap.set("cursor/copy", ECORE_X_CURSOR_ICON);
m_cursorStringMap.set("cursor/progress", ECORE_X_CURSOR_WATCH);
m_cursorStringMap.set("cursor/alias", ECORE_X_CURSOR_MAN);
m_cursorStringMap.set("cursor/none", ECORE_X_CURSOR_X);
m_cursorStringMap.set("cursor/not_allowed", ECORE_X_CURSOR_X);
m_cursorStringMap.set("cursor/zoom_in", ECORE_X_CURSOR_DIAMOND_CROSS);
m_cursorStringMap.set("cursor/zoom_out", ECORE_X_CURSOR_DIAMOND_CROSS);
m_cursorStringMap.set("cursor/grab", ECORE_X_CURSOR_HAND2);
m_cursorStringMap.set("cursor/grabbing", ECORE_X_CURSOR_HAND2);
}
static CursorMap cursorStringMap = CursorMap();
#endif
class WidgetPrivate {
public:
Evas* m_evas;
Evas_Object* m_evasObject;
String m_theme;
WidgetPrivate()
: m_evas(0)
, m_evasObject(0)
, m_cursorObject(0)
#ifdef HAVE_ECORE_X
, m_isUsingEcoreX(false)
#endif
{ }
/* cursor */
String m_cursorGroup;
Evas_Object* m_cursorObject;
#ifdef HAVE_ECORE_X
bool m_isUsingEcoreX;
#endif
};
Widget::Widget(PlatformWidget widget)
: m_parent(0)
, m_widget(0)
, m_selfVisible(false)
, m_parentVisible(false)
, m_frame(0, 0, 0, 0)
, m_data(new WidgetPrivate)
{
init(widget);
}
Widget::~Widget()
{
ASSERT(!parent());
if (m_data->m_cursorObject)
evas_object_del(m_data->m_cursorObject);
delete m_data;
}
IntRect Widget::frameRect() const
{
return m_frame;
}
void Widget::setFrameRect(const IntRect& rect)
{
m_frame = rect;
Widget::frameRectsChanged();
}
void Widget::frameRectsChanged()
{
Evas_Object* object = evasObject();
Evas_Coord x, y;
if (!parent() || !object)
return;
IntRect rect = frameRect();
if (parent()->isScrollViewScrollbar(this))
rect.setLocation(parent()->convertToContainingWindow(rect.location()));
else
rect.setLocation(parent()->contentsToWindow(rect.location()));
evas_object_geometry_get(root()->evasObject(), &x, &y, 0, 0);
evas_object_move(object, x + rect.x(), y + rect.y());
evas_object_resize(object, rect.width(), rect.height());
}
void Widget::setFocus(bool focused)
{
}
void Widget::applyFallbackCursor()
{
#ifdef HAVE_ECORE_X
if (m_data->m_isUsingEcoreX && !m_data->m_cursorGroup.isNull()) {
int shape = cursorStringMap.cursor(m_data->m_cursorGroup.utf8().data());
if (shape < ECORE_X_CURSOR_X || shape > ECORE_X_CURSOR_XTERM) {
LOG_ERROR("cannot map an equivalent X cursor for"
" c ursor group %s", m_data->m_cursorGroup.utf8().data());
shape = ECORE_X_CURSOR_LEFT_PTR;
}
Ecore_X_Window win = ecore_evas_software_x11_window_get(ecoreEvas());
Ecore_X_Cursor cur = ecore_x_cursor_shape_get(shape);
ecore_x_window_cursor_set(win, cur);
return;
}
#endif
}
void Widget::applyCursor()
{
CString file = edjeThemeRecursive().utf8();
m_data->m_cursorObject = edje_object_add(evas());
if (!file.isNull() && !edje_object_file_set(m_data->m_cursorObject, file.data(), m_data->m_cursorGroup.utf8().data())) {
evas_object_del(m_data->m_cursorObject);
m_data->m_cursorObject = 0;
ecore_evas_object_cursor_set(ecoreEvas(), 0, 0, 0, 0);
applyFallbackCursor();
} else {
Evas_Coord x, y, w, h;
const char *d;
edje_object_size_min_get(m_data->m_cursorObject, &w, &h);
if ((w <= 0) || (h <= 0))
edje_object_size_min_calc(m_data->m_cursorObject, &w, &h);
if ((w <= 0) || (h <= 0))
w = h = 16;
evas_object_resize(m_data->m_cursorObject, w, h);
d = edje_object_data_get(m_data->m_cursorObject, "hot.x");
x = d ? atoi(d) : 0;
d = edje_object_data_get(m_data->m_cursorObject, "hot.y");
y = d ? atoi(d) : 0;
ecore_evas_object_cursor_set(ecoreEvas(), m_data->m_cursorObject,
EVAS_LAYER_MAX, x, y);
}
}
void Widget::setCursor(const Cursor& cursor)
{
if (!evas())
return;
const char* group = cursor.platformCursor();
if (!group || String(group) == m_data->m_cursorGroup)
return;
m_data->m_cursorGroup = group;
applyCursor();
}
void Widget::show()
{
if (!platformWidget())
return;
evas_object_show(platformWidget());
}
void Widget::hide()
{
if (!platformWidget())
return;
evas_object_hide(platformWidget());
}
void Widget::paint(GraphicsContext* context, const IntRect&)
{
notImplemented();
}
void Widget::setIsSelected(bool)
{
notImplemented();
}
const String Widget::edjeTheme() const
{
return m_data->m_theme;
}
void Widget::setEdjeTheme(const String& themePath)
{
if (m_data->m_theme == themePath)
return;
m_data->m_theme = themePath;
}
const String Widget::edjeThemeRecursive() const
{
if (!m_data->m_theme.isNull())
return m_data->m_theme;
if (m_parent)
return m_parent->edjeThemeRecursive();
return String();
}
Evas* Widget::evas() const
{
return m_data->m_evas;
}
Ecore_Evas* Widget::ecoreEvas() const
{
// FIXME EFL: XXX assume evas was created by ecore_evas
return static_cast<Ecore_Evas*>(evas_data_attach_get(evas()));
}
void Widget::setEvasObject(Evas_Object *object)
{
// FIXME: study platformWidget() and use it
// FIXME: right now platformWidget() requires implementing too much
if (m_data->m_evasObject == object)
return;
m_data->m_evasObject = object;
if (!object) {
m_data->m_evas = 0;
#ifdef HAVE_ECORE_X
m_data->m_isUsingEcoreX = false;
#endif
return;
}
m_data->m_evas = evas_object_evas_get(object);
#ifdef HAVE_ECORE_X
const char *engine = ecore_evas_engine_name_get(ecoreEvas());
m_data->m_isUsingEcoreX = (!strcmp(engine, "software_x11")
|| !strcmp(engine, "software_xcb")
|| !strcmp(engine, "software_16_x11")
|| !strncmp(engine, "xrender", sizeof("xrender") - 1));
#endif
Widget::frameRectsChanged();
}
Evas_Object* Widget::evasObject() const
{
return m_data->m_evasObject;
}
}