Compare commits

...

1 Commits

Author SHA1 Message Date
Nimetu 9723854db2 Add webkit browser using cef3 offscreen rendering
--HG--
branch : feature-249-cef3
10 years ago

@ -131,6 +131,11 @@ ENDIF(WITH_STATIC)
INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/PCHSupport.cmake)
IF(WITH_CEF3)
ADD_DEFINITIONS(-DWITH_CEF3=1)
FIND_PACKAGE(CEF3 REQUIRED)
ENDIF(WITH_CEF3)
IF(FINAL_VERSION)
ADD_DEFINITIONS(-DFINAL_VERSION=1)
ENDIF(FINAL_VERSION)

@ -0,0 +1,56 @@
#
# - Locate CEF3 library
# This module defines
# CEF3_LIBRARIES the libraries to link against
# CEF3_INCLUDE_DIR where to find headers.
#
IF(CEF3_LIBRARIES)
SET(CEF3_FIND_QUIETLY TRUE)
ENDIF()
FIND_PATH(CEF3_INCLUDE_DIR
NAMES include/cef_version.h
PATHS ${CEF3_ROOT})
SET(CEF3_INCLUDE_DIR ${CEF3_INCLUDE_DIR} ${CEF3_INCLUDE_DIR}/include)
FIND_LIBRARY(CEF3_LIBRARY_RELEASE
NAMES cef
PATHS ${CEF3_ROOT} PATH_SUFFIXES Release)
FIND_LIBRARY(CEF3_LIBRARY_DEBUG
NAMES cef
PATHS ${CEF3_ROOT} PATH_SUFFIXES Debug)
#SET(CEF3_LIBRARY
# optimized ${CEF3_LIBRARY_RELEASE}
# debug ${CEF3_LIBRARY_DEBUG})
SET(CEF3_LIBRARY ${CEF3_LIBRARY_RELEASE})
#
# libcef_dll_wrapper.a
#
FIND_LIBRARY(CEF3_LIBRARY_WRAPPER_RELEASE
NAMES cef_dll_wrapper
PATHS ${CEF3_ROOT} PATH_SUFFIXES Release)
FIND_LIBRARY(CEF3_LIBRARY_WRAPPER_DEBUG
NAMES cef_dll_wrapper
PATHS ${CEF3_ROOT} PATH_SUFFIXES Debug)
#SET(CEF3_LIBRARY_WRAPPER
# optimized ${CEF3_LIBRARY_WRAPPER_RELEASE}
# debug ${CEF3_LIBRARY_WRAPPER_DEBUG})
SET(CEF3_LIBRARY_WRAPPER ${CEF3_LIBRARY_WRAPPER_RELEASE})
SET(CEF3_LIBRARIES ${CEF3_LIBRARIES} ${CEF3_LIBRARY} ${CEF3_LIBRARY_WRAPPER})
IF(CEF3_LIBRARY AND CEF3_INCLUDE_DIR)
SET(CEF3_FOUND "YES")
IF(NOT CEF3_FIND_QUIETLY)
MESSAGE(STATUS "Found Cef3: ${CEF3_LIBRARIES}")
ENDIF()
ELSE()
IF(NOT CEF3_FIND_QUIETLY)
MESSAGE(STATUS "Warning: Unable to find Cef3!")
ENDIF()
ENDIF()

@ -0,0 +1,186 @@
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef CL_GROUP_WEBKIT_H
#define CL_GROUP_WEBKIT_H
#include "nel/misc/types_nl.h"
#include "nel/gui/interface_group.h"
#include "nel/gui/ctrl_button.h"
#include "nel/gui/view_pointer.h"
#include "nel/gui/widget_manager.h"
#include "nel/gui/reflect.h"
#include "nel/3d/u_material.h"
#include "nel/3d/u_texture.h"
#include "nel/gui/webkit_handler.h"
#include <string>
namespace NLGUI {
// ***************************************************************************
/**
* Chromium Embedded Framework browser impl
*
* \author Meelis Mägi
* \date 2015
*/
class CGroupWebkit : public CInterfaceGroup
{
public:
DECLARE_UI_CLASS(CGroupWebkit)
// Constructor
CGroupWebkit(const TCtorParam &param);
~CGroupWebkit();
// Get Home url
std::string home();
// Get current url
std::string getURL() const { return _URL; }
// Set window title
void setTitle(const std::string &title);
// Load url into browser
void browse(const char *url);
// Reload _URL into browser, ignoring cache
void refresh();
// parse html string into browser
void parseHtml(const std::string &html);
// Browser history
void browseUndo();
void browseRedo();
void clearUndoRedo();
// set browser zoom factor
void browserZoomIn();
void browserZoomOut();
void browserZoomReset();
// browser status bar
void showHideStatus(bool show);
void setStatusMessage(const std::string &msg);
void setLoadingState(bool loading, bool undo, bool redo);
void setTooltip(const std::string &tt);
//
virtual bool handleEvent(const NLGUI::CEventDescriptor& event);
virtual void checkCoords();
virtual void invalidateCoords();
virtual void onInvalidateContent();
virtual bool parse(xmlNodePtr cur, CInterfaceGroup *parentGroup);
virtual void draw ();
//
bool isKeyboardCaptured() const;
void setKeyboardCapture(bool capture);
void setGrabKeyboard(bool grab);
bool getGrabKeyboard() const { return _GrabKeyboard; }
void setGrabKeyboardButtonPushed(bool pushed);
// CefRenderHandler::OnPopupSize
void setPopupSize(const CefRect &rect);
// CefRenderHandler::OnPopupShow
void setPopupVisibility(bool visible);
// CefRenderHandler::OnPaint
void drawIntoTexture(const CefRenderHandler::RectList &dirtyRects, const void *buffer, sint width, sint height, bool popup);
// CefRenderHandler::GetViewRect, GetScreenInfo
sint getTextureWidth() const { return _Texture ? _Texture->getImageWidth() : 0; };
sint getTextureHeight() const { return _Texture ? _Texture->getImageHeight() : 0; };
int luaBrowse(CLuaState &ls);
int luaBrowseUndo(CLuaState &ls);
int luaBrowseRedo(CLuaState &ls);
int luaRefresh(CLuaState &ls);
int luaParseHtml(CLuaState &ls);
int luaZoomIn(CLuaState &ls);
int luaZoomOut(CLuaState &ls);
int luaZoomReset(CLuaState &ls);
REFLECT_EXPORT_START(CGroupWebkit, CInterfaceGroup)
REFLECT_LUA_METHOD("browse", luaBrowse)
REFLECT_LUA_METHOD("browseUndo", luaBrowseUndo)
REFLECT_LUA_METHOD("browseRedo", luaBrowseRedo)
REFLECT_LUA_METHOD("refresh", luaRefresh)
REFLECT_LUA_METHOD("zoomIn", luaZoomIn)
REFLECT_LUA_METHOD("zoomOut", luaZoomOut)
REFLECT_LUA_METHOD("zoomReset", luaZoomReset)
REFLECT_LUA_METHOD("parseHtml", luaParseHtml)
REFLECT_BOOL("grab_keyboard", getGrabKeyboard, setGrabKeyboard)
REFLECT_STRING("url", getURL, browse)
REFLECT_EXPORT_END
protected:
bool handleKeyEvent(const NLGUI::CEventDescriptorKey &event);
bool handleMouseEvent(const NLGUI::CEventDescriptorMouse &event);
void handle();
void setFocus(bool state);
void releaseKeyboard();
void captureKeyboard();
void setProperty(const std::string &name, const std::string &value);
private:
CefRefPtr<CefBrowser> _Browser;
CefRefPtr<CWebkitHandler> _BrowserHandler;
CefKeyEvent _KeyEvent;
// used to draw _Texture and _PopupTexture
NL3D::UMaterial _Material;
// main browser window content
NL3D::UTextureMem *_Texture;
// popup (select/combo box) content
NL3D::UTextureMem *_PopupTexture;
sint _PopupX;
sint _PopupY;
// true if mouse is over browser window
bool _Focused;
// if keyboard should always be captured when mouse is over window
bool _GrabKeyboard;
// if keyboard should be captured after gaining focus again
bool _RestoreKeyboardCapture;
// tracks window visibility
bool _LastActive;
//
std::string _TitlePrefix;
// url that is loaded when doing ::browse('home')
std::string _Home;
// currently loaded page url
std::string _URL;
// detect resize event
sint32 _LastParentW;
sint32 _LastParentH;
// Status message from Cef
std::string _StatusMessage;
std::string _TooltipString;
bool _Loading;
};
}// namespace
#endif // CL_GROUP_WEBKIT_H

@ -0,0 +1,72 @@
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef CL_WEBKIT_APP_H
#define CL_WEBKIT_APP_H
#include "nel/misc/types_nl.h"
#include <cef_app.h>
namespace NLGUI
{
extern const char kFocusedNodeChangedMessage[];
// ***************************************************************************
/**
* Cef client app
*
* \author Meelis Mägi
* \date 2015
*/
class CWebkitApp: public CefApp,
public CefRenderProcessHandler
{
public:
CWebkitApp(): _LastIsEditable(false)
{
}
~CWebkitApp();
// CefApp
virtual CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() OVERRIDE
{
return this;
}
// CefRenderProcessHandler
virtual void OnFocusedNodeChanged(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefDOMNode> node) OVERRIDE;
// Chrome/39.0.2171.95
static std::string getChromeVersion();
private:
bool _LastIsEditable;
IMPLEMENT_REFCOUNTING(CWebkitApp);
};
// Initializes CEF3 for main thread
bool webkitInitialize(const CefMainArgs &args, const std::string &locale, const std::string &userAgent);
void webkitShutdown();
} // namespace
#endif // CL_WEBKIT_APP_H

@ -0,0 +1,132 @@
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef CL_WEBKIT_HANDLER_H
#define CL_WEBKIT_HANDLER_H
#include <cef_client.h>
#include <wrapper/cef_helpers.h>
namespace NLGUI {
class CGroupWebkit;
// ***************************************************************************
/**
* Cef browser client
*
* \author Meelis Mägi
* \date 2015
*/
class CWebkitHandler: public CefClient,
public CefLifeSpanHandler,
public CefLoadHandler,
public CefDisplayHandler,
public CefJSDialogHandler,
public CefRenderHandler
{
public:
CWebkitHandler();
void setWindow(CGroupWebkit *win);
// CefClient
virtual CefRefPtr<CefRenderHandler> GetRenderHandler() { return this; }
virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler(){ return this; }
virtual CefRefPtr<CefLoadHandler> GetLoadHandler() { return this; }
virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() { return this; }
virtual CefRefPtr<CefJSDialogHandler> GetJSDialogHandler() { return this; }
// CefClient
virtual bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
CefProcessId source_process,
CefRefPtr<CefProcessMessage> message) OVERRIDE;
// CefLifeSpanHandler
virtual bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& target_url,
const CefString& target_frame_name,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings,
bool* no_javascript_access) OVERRIDE;
// CefLoadHandler
void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
bool isLoading,
bool canGoBack,
bool canGoForward) OVERRIDE;
// CefLoadHandler
void OnLoadError(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
ErrorCode errorCode,
const CefString &errorText,
const CefString &failedUrl) OVERRIDE;
// CefDisplayHandler
virtual void OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title) OVERRIDE;
// CefDisplayHandler
virtual bool OnTooltip(CefRefPtr<CefBrowser> browser, CefString &text) OVERRIDE;
// CefDisplayHandler
virtual void OnStatusMessage(CefRefPtr<CefBrowser> browser, const CefString& value) OVERRIDE;
// CefDisplayHandler
virtual bool OnConsoleMessage(CefRefPtr<CefBrowser> browser,
const CefString& message,
const CefString& source,
int line) OVERRIDE;
// CefJSDialogHandler
virtual bool OnJSDialog(CefRefPtr<CefBrowser> browser,
const CefString& origin_url,
const CefString& accept_lang,
JSDialogType dialog_type,
const CefString& message_text,
const CefString& default_prompt_text,
CefRefPtr<CefJSDialogCallback> callback,
bool& suppress_message) OVERRIDE;
//CefJSDialogHandler
virtual void OnResetDialogState(CefRefPtr<CefBrowser> browser) OVERRIDE;
// CefRenderHandler
virtual bool GetScreenInfo(CefRefPtr<CefBrowser> browser, CefScreenInfo& screen_info) OVERRIDE;
virtual bool GetViewRect(CefRefPtr<CefBrowser> browser, CefRect &rect) OVERRIDE;
virtual void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) OVERRIDE;
virtual void OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect) OVERRIDE;
virtual void OnPaint(CefRefPtr<CefBrowser> browser, PaintElementType type, const RectList &dirtyRects, const void *buffer, int width, int height) OVERRIDE;
virtual void OnCursorChange(CefRefPtr<CefBrowser> browser, CefCursorHandle cursor, CursorType type, const CefCursorInfo& custom_cursor_info) OVERRIDE;
// called from action handler after ui dialog is closed
static void jsDialogContinue(bool success, const std::string &input);
private:
CGroupWebkit *_Window;
static CefRefPtr<CefJSDialogCallback> _JSDialogCallback;
IMPLEMENT_REFCOUNTING(CWebkitHandler);
};
}// namespace
#endif // CL_WEBKIT_HANDLER_H

@ -1,6 +1,20 @@
FILE(GLOB SRC *.cpp *.h)
FILE(GLOB HEADERS ../../include/nel/gui/*.h)
# Chromium Embbed Framework
IF(NOT WITH_CEF3)
LIST(REMOVE_ITEM SRC
${CMAKE_CURRENT_SOURCE_DIR}/group_webkit.cpp
${CMAKE_CURRENT_SOURCE_DIR}/webkit_app.cpp
${CMAKE_CURRENT_SOURCE_DIR}/webkit_handler.cpp
)
LIST(REMOVE_ITEM HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/../../include/nel/gui/group_webkit.h
${CMAKE_CURRENT_SOURCE_DIR}/../../include/nel/gui/webkit_app.h
${CMAKE_CURRENT_SOURCE_DIR}/../../include/nel/gui/webkit_handler.h
)
ENDIF(NOT WITH_CEF3)
SOURCE_GROUP("include" FILES ${HEADERS})
SOURCE_GROUP("src" FILES ${SRC})
@ -9,6 +23,11 @@ NL_TARGET_LIB(nelgui ${SRC} ${HEADERS})
INCLUDE_DIRECTORIES(${LUA_INCLUDE_DIR} ${LUABIND_INCLUDE_DIR} ${CURL_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(nelgui nelmisc nel3d ${LUA_LIBRARIES} ${LUABIND_LIBRARIES} ${LIBXML2_LIBRARIES} ${CURL_LIBRARIES})
IF(WITH_CEF3)
INCLUDE_DIRECTORIES(${CEF3_INCLUDE_DIR})
TARGET_LINK_LIBRARIES(nelgui ${CEF3_LIBRARIES})
ENDIF(WITH_CEF3)
SET_TARGET_PROPERTIES(nelgui PROPERTIES LINK_INTERFACE_LIBRARIES "")
NL_DEFAULT_PROPS(nelgui "NeL, Library: NeL GUI")
NL_ADD_RUNTIME_FLAGS(nelgui)

@ -0,0 +1,976 @@
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdpch.h"
#include "nel/gui/group_webkit.h"
#include "nel/gui/webkit_handler.h"
#include "nel/gui/group_container.h"
#include "nel/gui/group_editbox.h"
#include "nel/gui/view_text.h"
#include "nel/gui/view_bitmap.h"
#include "nel/gui/lua_ihm.h"
#include <cef_app.h>
using namespace std;
using namespace NL3D;
using namespace NLMISC;
using namespace NLGUI;
NLMISC_REGISTER_OBJECT(CViewBase, CGroupWebkit, std::string, "webkit");
CGroupWebkit::CGroupWebkit(const TCtorParam &param)
: CInterfaceGroup(param)
{
CViewRenderer &rVR = *CViewRenderer::getInstance();
_Material = rVR.getDriver()->createMaterial();
_Material.initUnlit();
_Material.setDoubleSided();
_Material.setZWrite(false);
_Material.setZFunc(UMaterial::always);
_Material.setBlend(true);
_Material.setBlendFunc (UMaterial::srcalpha, UMaterial::invsrcalpha);
_Material.setColor(CRGBA::White);
_Material.setTexture(0, NULL);
_Material.setTexture(1, NULL);
_Material.setTexture(2, NULL);
_Material.setTexture(3, NULL);
_Material.setZBias(0);
_Texture = NULL;
_PopupTexture = NULL;
_PopupX = 0;
_PopupY = 0;
_Focused = false;
_GrabKeyboard = false;
_RestoreKeyboardCapture = false;
_LastActive = false;
_TitlePrefix = "";
_Home = "";
_URL = "";
_LastParentW = 0;
_LastParentH = 0;
_StatusMessage = "";
_TooltipString = "";
_Loading = false;
CefBrowserSettings browserSettings;
CefString(&browserSettings.default_encoding).FromASCII("UTF-8");
browserSettings.image_shrink_standalone_to_fit = STATE_ENABLED;
CefWindowInfo window_info;
window_info.SetAsWindowless(0, true);
// cef handler(s)
_BrowserHandler = new CWebkitHandler();
// there is no texture yet, but set window handler for other events
_BrowserHandler->setWindow(this);
_Browser = CefBrowserHost::CreateBrowserSync(window_info, _BrowserHandler.get(), "about:blank", browserSettings, NULL);
// Cef message loop is depending on this
CWidgetManager::getInstance()->registerClockMsgTarget(this);
}
// ***************************************************************************
CGroupWebkit::~CGroupWebkit()
{
// clear texture from CefRenderHandler
_BrowserHandler->setWindow(NULL);
// force close browser
_Browser->GetHost()->CloseBrowser(true);
_Browser = NULL;
_BrowserHandler = NULL;
CViewRenderer &rVR = *CViewRenderer::getInstance();
if (_Texture)
rVR.getDriver()->deleteTextureMem(_Texture);
if (_PopupTexture)
rVR.getDriver()->deleteTextureMem(_PopupTexture);
_Texture = NULL;
_PopupTexture = NULL;
}
// ***************************************************************************
string CGroupWebkit::home ()
{
return _Home;
}
// ***************************************************************************
void CGroupWebkit::browse(const char *url)
{
_URL = url;
if (_URL.empty() || _URL == "home")
_URL = home();
_Browser->GetMainFrame()->LoadURL(_URL);
}
// ***************************************************************************
void CGroupWebkit::browseUndo()
{
_Browser->GoBack();
}
// ***************************************************************************
void CGroupWebkit::browseRedo()
{
_Browser->GoForward();
}
// ***************************************************************************
void CGroupWebkit::refresh()
{
_Browser->ReloadIgnoreCache();
}
// ***************************************************************************
void CGroupWebkit::parseHtml(const std::string &html)
{
_Browser->GetMainFrame()->LoadString(html, ":");
}
// ***************************************************************************
void CGroupWebkit::clearUndoRedo()
{
// FIXME: missing in cef3?
}
// ***************************************************************************
void CGroupWebkit::setProperty(const std::string &name, const std::string &value)
{
if (name == "title_prefix")
{
if (!value.empty())
_TitlePrefix = value + " - ";
else
_TitlePrefix = "";
}
else
if (name == "url")
_URL = value;
else
if (name == "home")
_Home = value;
else
if (name == "grab_keyboard")
{
bool b;
if (fromString(value, b))
_GrabKeyboard = b;
}
}
// ***************************************************************************
bool CGroupWebkit::parse(xmlNodePtr cur,CInterfaceGroup *parentGroup)
{
CInterfaceGroup::parse(cur, parentGroup);
std::string props[] = {
"title_prefix", "url", "home", "grab_keyboard"
};
uint size = sizeof(props) / sizeof(props[0]);
CXMLAutoPtr ptr;
for (uint i=0; i<size; ++i)
{
ptr = xmlGetProp(cur, (xmlChar*) props[i].c_str());
if (ptr)
setProperty(props[i], string(ptr));
}
// Tooltip position follows mouse
setInstantContextHelp(true);
setToolTipParent(TTMouse);
setToolTipParentPosRef(Hotspot_TTAuto);
setToolTipPosRef(Hotspot_TTAuto);
return true;
}
// ***************************************************************************
bool CGroupWebkit::handleKeyEvent(const NLGUI::CEventDescriptorKey &event)
{
// FIXME:
//_KeyEvent.windows_key_code = ;
//_KeyEvent.native_key_code = ;
if (event.getKeyShift())
_KeyEvent.modifiers |= EVENTFLAG_SHIFT_DOWN;
if (event.getKeyCtrl())
_KeyEvent.modifiers |= EVENTFLAG_CONTROL_DOWN;
if (event.getKeyAlt())
{
_KeyEvent.modifiers |= EVENTFLAG_ALT_DOWN;
_KeyEvent.is_system_key = true;
}
_KeyEvent.character = _KeyEvent.unmodified_character;
if (event.getKeyEventType() == NLGUI::CEventDescriptorKey::keyup)
{
_KeyEvent.type = KEYEVENT_KEYUP;
_KeyEvent.native_key_code = event.getKey();
_KeyEvent.windows_key_code = event.getKey();
_Browser->GetHost()->SendKeyEvent(_KeyEvent);
return true;
}
if (event.getKeyEventType() == NLGUI::CEventDescriptorKey::keydown)
{
_KeyEvent.type = KEYEVENT_KEYDOWN;
_KeyEvent.native_key_code = event.getKey();
_KeyEvent.windows_key_code = event.getKey();
_Browser->GetHost()->SendKeyEvent(_KeyEvent);
return true;
}
if (event.getKeyEventType() == NLGUI::CEventDescriptorKey::keychar)
{
_KeyEvent.character = event.getChar();
_KeyEvent.type = KEYEVENT_KEYUP;
_Browser->GetHost()->SendKeyEvent(_KeyEvent);
_KeyEvent.type = KEYEVENT_CHAR;
_Browser->GetHost()->SendKeyEvent(_KeyEvent);
return true;
}
if (event.getKeyEventType() == NLGUI::CEventDescriptorKey::keystring)
{
// CEF handles this itself when ctrl+v is pressed
return true;
}
return false;
}
// ***************************************************************************
bool CGroupWebkit::handleMouseEvent(const NLGUI::CEventDescriptorMouse &event)
{
// make sure event is for our group and not just in a window
if (!isIn(event.getX(), event.getY()))
return false;
sint32 x = event.getX() - _XReal;
sint32 y = _YReal - event.getY() + _HReal;
CefMouseEvent mouse_event;
mouse_event.x = x;
mouse_event.y = y;
_Browser->GetHost()->SendMouseMoveEvent(mouse_event, false);
if (event.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mousewheel)
{
int dx = 0;
int dy = event.getWheel()*50;
if (_KeyEvent.type == KEYEVENT_KEYDOWN && _KeyEvent.modifiers & EVENTFLAG_CONTROL_DOWN)
{
if (dy > 0)
browserZoomIn();
else
browserZoomOut();
}
else
_Browser->GetHost()->SendMouseWheelEvent(mouse_event, dx, dy);
return true;
}
sint32 type = event.getEventTypeExtended();
// FIXME: double click - interpreted as up/down/up/down
if (type == NLGUI::CEventDescriptorMouse::mouseleftup ||
type == NLGUI::CEventDescriptorMouse::mouseleftdown ||
type == NLGUI::CEventDescriptorMouse::mouseleftdblclk)
{
bool up = (event.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftup);
uint8 count = (type == NLGUI::CEventDescriptorMouse::mouseleftdblclk) ? 2 : 1;
mouse_event.modifiers |= EVENTFLAG_LEFT_MOUSE_BUTTON;
_Browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_LEFT, up, count);
return true;
}
if (type == NLGUI::CEventDescriptorMouse::mouserightup ||
type == NLGUI::CEventDescriptorMouse::mouserightdown ||
type == NLGUI::CEventDescriptorMouse::mouserightdblclk)
{
bool up = (event.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouserightup);
uint8 count = (type == NLGUI::CEventDescriptorMouse::mouserightdblclk) ? 2 : 1;
mouse_event.modifiers |= EVENTFLAG_RIGHT_MOUSE_BUTTON;
_Browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_RIGHT, up, count);
return true;
}
return false;
}
// ***************************************************************************
bool CGroupWebkit::handleEvent(const NLGUI::CEventDescriptor& event)
{
// FIXME: subscribe to keyboard event to know shift/alt/ctrl state when we dont have keyboard focus
//
if (event.getType() == NLGUI::CEventDescriptor::system)
{
const NLGUI::CEventDescriptorSystem &systemEvent = (const NLGUI::CEventDescriptorSystem &) event;
if (systemEvent.getEventTypeExtended() == NLGUI::CEventDescriptorSystem::clocktick)
{
handle();
}
}
if (event.getType() == NLGUI::CEventDescriptor::key)
{
if (handleKeyEvent((const NLGUI::CEventDescriptorKey &)event))
return true;
}
if (event.getType() == NLGUI::CEventDescriptor::mouse)
{
if (handleMouseEvent((const NLGUI::CEventDescriptorMouse &)event))
return true;
}
if (CInterfaceGroup::handleEvent(event)) return true;
return false;
}
// ***************************************************************************
bool CGroupWebkit::isKeyboardCaptured() const
{
return (CWidgetManager::getInstance()->getCaptureKeyboard() == this);
}
// ***************************************************************************
void CGroupWebkit::releaseKeyboard()
{
setGrabKeyboardButtonPushed(false);
if (! isKeyboardCaptured())
return;
_KeyEvent.modifiers = EVENTFLAG_NONE;
CWidgetManager::getInstance()->resetCaptureKeyboard();
}
// ***************************************************************************
void CGroupWebkit::captureKeyboard()
{
setGrabKeyboardButtonPushed(true);
if (isKeyboardCaptured())
return;
CWidgetManager::getInstance()->setCaptureKeyboard(this);
}
// ***************************************************************************
void CGroupWebkit::setKeyboardCapture(bool capture)
{
_RestoreKeyboardCapture = _GrabKeyboard || capture;
// ignore release request if window still has mouse over it
if (capture || (_GrabKeyboard && _Focused))
captureKeyboard();
else
releaseKeyboard();
}
// ***************************************************************************
void CGroupWebkit::setGrabKeyboard(bool grab)
{
_GrabKeyboard = grab;
setKeyboardCapture(grab);
}
// ***************************************************************************
void CGroupWebkit::setGrabKeyboardButtonPushed(bool pushed)
{
CInterfaceGroup* group = getParentContainer();
if (group)
{
CCtrlBaseButton *btn = dynamic_cast<CCtrlBaseButton *>(group->getCtrl("grab_keyboard"));
if (btn)
btn->setPushed(pushed);
}
}
// ***************************************************************************
void CGroupWebkit::setFocus(bool state)
{
if (!_Active)
return;
if (state && ! _Focused)
{
_Focused = true;
_Browser->GetHost()->SendFocusEvent(true);
if (_RestoreKeyboardCapture)
captureKeyboard();
}
else
if (! state && _Focused)
{
_Focused = false;
_Browser->GetHost()->SendFocusEvent(false);
if (isKeyboardCaptured())
releaseKeyboard();
}
setGrabKeyboardButtonPushed(_Focused && _RestoreKeyboardCapture);
}
// ***************************************************************************
void CGroupWebkit::setTitle(const std::string &title)
{
CInterfaceElement *parent = getParent();
if (parent)
{
if ((parent = parent->getParent()))
{
CGroupContainer *container = dynamic_cast<CGroupContainer*>(parent);
if (container)
{
container->setUCTitle(ucstring(_TitlePrefix + title));
}
}
}
}
// ***************************************************************************
void CGroupWebkit::draw ()
{
if (!_Active)
return;
CRGBA color(CRGBA::White);
/* // CtrlQuad::draw
if (getModulateGlobalColor())
color.modulateFromColor(CRGBA::White, CWidgetManager::getInstance()->getGlobalColorForContent());
else
{
color = CRGBA::White;
color.A = (uint8)(((sint32)color.A*((sint32)CWidgetManager::getInstance()->getGlobalColorForContent().A+1))>>8);
}
*/
// get parent container content alpha value
CInterfaceGroup *gr = getParent();
while (gr)
{
if (gr->isGroupContainer())
{
CGroupContainer *gc = static_cast<CGroupContainer *>(gr);
color.A = gc->getCurrentContainerAlpha();
break;
}
gr = gr->getParent();
}
CViewRenderer &rVR = *CViewRenderer::getInstance();
if (_Texture)
{
_Material.setTexture(0, _Texture);
rVR.drawCustom(_XReal, _YReal, _WReal, _HReal, color, _Material);
}
if (_PopupTexture)
{
// calculate bottom-left corner for popup texture inside window
sint popx = _XReal + _PopupX;
sint popy = _YReal + _HReal - _PopupY - _PopupTexture->getImageHeight();
_Material.setTexture(0, _PopupTexture);
rVR.drawCustom(popx, popy, _PopupTexture->getImageWidth(), _PopupTexture->getImageHeight(),
color, _Material);
}
CInterfaceGroup::draw();
}
static void copyBGRAtoRGBA(
// destination buffer and it's size
uint8 *dst, sint dstw, sint dsth,
// source buffer and it's size
const uint8 *src, sint srcw, sint srch,
// rectangle to be copied
const CefRect &rect)
{
uint bytePerPixel = 4;
// make sure we dont overflow either buffers
sint xmax = std::min(dstw, std::min(rect.x + rect.width, rect.x + srcw));
sint ymax = std::min(dsth, std::min(rect.y + rect.height, rect.y + srch));
for(sint x = rect.x; x < xmax; ++x)
{
for(sint y = rect.y; y < ymax; ++y)
{
sint pos = (x + y * srcw) * bytePerPixel;
// RGBA <- BGRA
dst[pos + 0] = src[pos + 2];
dst[pos + 1] = src[pos + 1];
dst[pos + 2] = src[pos];
dst[pos + 3] = src[pos + 3];
}
}
}
// ***************************************************************************
void CGroupWebkit::drawIntoTexture(const CefRenderHandler::RectList &dirtyRects, const void *buffer, sint width, sint height, bool popup)
{
// this can be optimized by copying full buffer into texture using memcpy
// and when drawing, setting up vertex buffer with BGRA format and use driver->renderRawQuads() to draw it
UTextureMem *tex = NULL;
if (popup)
tex = _PopupTexture;
else
tex = _Texture;
if (tex)
{
// dirtyRects should contain only single rect (largest region to update)
if (dirtyRects.size() == 1)
{
const CefRect &rect = dirtyRects[0];
copyBGRAtoRGBA((uint8 *)tex->getPointer(), tex->getImageWidth(), tex->getImageHeight(),
(uint8 *)buffer, width, height,
rect);
}
else
{
CefRenderHandler::RectList::const_iterator i = dirtyRects.begin();
for(; i != dirtyRects.end(); ++i)
{
const CefRect &rect = *i;
copyBGRAtoRGBA((uint8 *)tex->getPointer(), tex->getImageWidth(), tex->getImageHeight(),
(uint8 *)buffer, width, height,
rect);
}
}
tex->touch();
}
else
nldebug("missing %s texture\n", popup ? "main" : "popup");
}
// ***************************************************************************
void CGroupWebkit::setPopupVisibility(bool visible)
{
// hide popup by making sure texture is not set
if (_PopupTexture && !visible)
{
CViewRenderer &rVR = *CViewRenderer::getInstance();
rVR.getDriver()->deleteTextureMem(_PopupTexture);
_PopupTexture = NULL;
}
}
// ***************************************************************************
void CGroupWebkit::setPopupSize(const CefRect &rect)
{
// always get rid of old popup
CViewRenderer &rVR = *CViewRenderer::getInstance();
if (_PopupTexture)
{
rVR.getDriver()->deleteTextureMem(_PopupTexture);
_PopupTexture = NULL;
}
if (rect.width == 0 || rect.height == 0)
return;
// setup new popup with new texture
_PopupTexture = rVR.getDriver()->createTextureMem(rect.width, rect.height, CBitmap::RGBA);
_PopupX = rect.x;
_PopupY = rect.y;
}
// ***************************************************************************
void CGroupWebkit::invalidateCoords()
{
if (!_Active && _LastActive)
{
_Browser->GetHost()->SetWindowVisibility(false);
_LastActive = false;
}
else
if (_Active && !_LastActive)
{
_Browser->GetHost()->SetWindowVisibility(true);
_LastActive = true;
}
CInterfaceGroup::invalidateCoords();
}
// ***************************************************************************
void CGroupWebkit::checkCoords()
{
if (!_Active)
{
if (_LastActive)
_Browser->GetHost()->SetWindowVisibility(false);
_LastActive = false;
releaseKeyboard();
return;
}
// called on each frame
if (_Parent)
{
// switch focus only when not being resized
if (CWidgetManager::getInstance()->getCapturePointerLeft() == NULL)
{
CViewPointerBase *mousePointer = CWidgetManager::getInstance()->getPointer();
if (mousePointer)
{
if (isIn(mousePointer->getX(), mousePointer->getY()))
{
if (!_Focused)
{
// get top-most window and see if any of it belongs to us
CInterfaceGroup *ig = CWidgetManager::getInstance()->getCurrentWindowUnder();
while(ig)
{
if (ig == _Parent->getRootWindow())
{
setFocus(true);
break;
}
ig = ig->getParent();
}
}
}
else
if (_Focused)
setFocus(false);
}
}
// resize event
sint parentWidth = std::min(_Parent->getMaxWReal(), _Parent->getWReal());
sint parentHeight = std::min(_Parent->getMaxHReal(), _Parent->getHReal());
if (_LastParentW != (sint)parentWidth || _LastParentH != (sint)parentHeight)
{
CCtrlBase *pCB = CWidgetManager::getInstance()->getCapturePointerLeft();
if (pCB != NULL)
{
CCtrlResizer *pCR = dynamic_cast<CCtrlResizer *>(pCB);
if (pCR != NULL)
{
// resize in progress
}
else
{
_LastParentW = parentWidth;
_LastParentH = parentHeight;
invalidateContent();
}
}
else
{
_LastParentW = parentWidth;
_LastParentH = parentHeight;
invalidateContent();
}
}
}
CInterfaceGroup::checkCoords();
}
// ***************************************************************************
void CGroupWebkit::onInvalidateContent()
{
if (!_Active)
return;
CViewRenderer &rVR = *CViewRenderer::getInstance();
if (_Texture)
{
rVR.getDriver()->deleteTextureMem(_Texture);
_Texture = NULL;
}
else
{
// must be first call as there is no texture yet
browse(_URL.c_str());
}
if (_WReal > 0 && _HReal > 0)
{
// create texture same size as window
_Texture = rVR.getDriver()->createTextureMem(_WReal, _HReal, CBitmap::RGBA);
_Texture->setWrapS(NL3D::UTexture::Clamp);
_Texture->setWrapT(NL3D::UTexture::Clamp);
_Browser->GetHost()->WasResized();
}
}
// ***************************************************************************
void CGroupWebkit::handle()
{
// FIXME: auto hide status bar on timeout
//const CWidgetManager::SInterfaceTimes &times = CWidgetManager::getInstance()->getInterfaceTimes();
// times.thisFrameMs / 1000.0f;
CefDoMessageLoopWork();
}
// ***************************************************************************
void CGroupWebkit::showHideStatus(bool show)
{
CInterfaceGroup* group = getParentContainer();
if (group)
{
CInterfaceGroup *pGroup = dynamic_cast<CInterfaceGroup*>(group->getGroup("status_bar"));
if (pGroup)
pGroup->setActive(show);
}
}
// ***************************************************************************
void CGroupWebkit::setStatusMessage(const std::string &msg)
{
if (_StatusMessage == msg)
return;
_StatusMessage = msg;
showHideStatus(! _StatusMessage.empty());
CInterfaceGroup* group = getParentContainer();
if (group)
{
CViewText *pView = dynamic_cast<CViewText*>(group->getView("status"));
if (pView)
pView->setText(ucstring(msg));
}
}
// ***************************************************************************
void CGroupWebkit::setTooltip(const std::string &tt)
{
if (_TooltipString == tt)
return;
_TooltipString = tt;
setDefaultContextHelp(tt);
}
// ***************************************************************************
void CGroupWebkit::setLoadingState(bool loading, bool undo, bool redo)
{
if (_Loading == loading)
return;
_Loading = loading;
CInterfaceGroup* group = getParentContainer();
if (group)
{
CViewBitmap *pView = dynamic_cast<CViewBitmap*>(group->getView("loading"));
if (pView)
{
if (loading)
{
pView->setTexture("w_online.tga");
setTitle(_TitlePrefix + CI18N::get("uiPleaseWait").toString());
setStatusMessage(CI18N::get("uiPleaseWait").toString());
}
else
pView->setTexture("w_offline.tga");
}
CCtrlBaseButton *btnRefresh = dynamic_cast<CCtrlBaseButton *>(group->getCtrl("browse_refresh"));
if (btnRefresh)
btnRefresh->setFrozen(loading);
CCtrlBaseButton *btnUndo = dynamic_cast<CCtrlBaseButton *>(group->getCtrl("browse_undo"));
if (btnUndo)
btnUndo->setFrozen(!undo);
CCtrlBaseButton *btnRedo = dynamic_cast<CCtrlBaseButton *>(group->getCtrl("browse_redo"));
if (btnRedo)
btnRedo->setFrozen(!redo);
}
}
// ***************************************************************************
void CGroupWebkit::browserZoomIn()
{
_Browser->GetHost()->SetZoomLevel(_Browser->GetHost()->GetZoomLevel() + 0.5);
}
// ***************************************************************************
void CGroupWebkit::browserZoomOut()
{
_Browser->GetHost()->SetZoomLevel(_Browser->GetHost()->GetZoomLevel() - 0.5);
}
// ***************************************************************************
void CGroupWebkit::browserZoomReset()
{
_Browser->GetHost()->SetZoomLevel(0.0f);
}
// ***************************************************************************
int CGroupWebkit::luaBrowse(CLuaState &ls)
{
const char *funcName = "browse";
CLuaIHM::checkArgCount(ls, funcName, 1);
CLuaIHM::checkArgType(ls, funcName, 1, LUA_TSTRING);
browse(ls.toString(1));
return 0;
}
// ***************************************************************************
int CGroupWebkit::luaBrowseUndo(CLuaState &ls)
{
const char *funcName = "browseUndo";
CLuaIHM::checkArgCount(ls, funcName, 0);
browseUndo();
return 0;
}
// ***************************************************************************
int CGroupWebkit::luaBrowseRedo(CLuaState &ls)
{
const char *funcName = "browseRedo";
CLuaIHM::checkArgCount(ls, funcName, 0);
browseRedo();
return 0;
}
// ***************************************************************************
int CGroupWebkit::luaRefresh(CLuaState &ls)
{
const char *funcName = "refresh";
CLuaIHM::checkArgCount(ls, funcName, 0);
refresh();
return 0;
}
// ***************************************************************************
int CGroupWebkit::luaZoomIn(CLuaState &ls)
{
const char *funcName = "zoomIn";
CLuaIHM::checkArgCount(ls, funcName, 0);
browserZoomIn();
return 0;
}
// ***************************************************************************
int CGroupWebkit::luaZoomOut(CLuaState &ls)
{
const char *funcName = "zoomOut";
CLuaIHM::checkArgCount(ls, funcName, 0);
browserZoomOut();
return 0;
}
// ***************************************************************************
int CGroupWebkit::luaZoomReset(CLuaState &ls)
{
const char *funcName = "zoomReset";
CLuaIHM::checkArgCount(ls, funcName, 0);
browserZoomReset();
return 0;
}
// ***************************************************************************
int CGroupWebkit::luaParseHtml(CLuaState &ls)
{
const char *funcName = "parseHtml";
CLuaIHM::checkArgCount(ls, funcName, 1);
CLuaIHM::checkArgType(ls, funcName, 1, LUA_TSTRING);
std::string html = ls.toString(1);
parseHtml(html);
return 0;
}
// ***************************************************************************
class CHandlerWebkitJSDialog : public IActionHandler
{
void execute(CCtrlBase *pCaller, const std::string &sParams)
{
std::string btn = getParam(sParams, "button");
bool success = (btn == "ok");
std::string input;
// get dialog window
CInterfaceGroup* group = pCaller->getRootWindow();
if (group)
{
// if there is edit box, then it was a prompt dialog
CGroupEditBox* eb = dynamic_cast<CGroupEditBox*>(group->getGroup("prompt:eb"));
if (eb)
input = eb->getInputStringAsUtf8();
}
CWebkitHandler::jsDialogContinue(success, input);
CWidgetManager::getInstance()->popModalWindow();
}
};
REGISTER_ACTION_HANDLER( CHandlerWebkitJSDialog, "webkit_jsdialog");
// ***************************************************************************
class CHandlerWebkitJSDialogCancel : public IActionHandler
{
void execute(CCtrlBase *pCaller, const std::string &sParams)
{
// execute js dialog callback when modal is closed by ESC key for example
CWebkitHandler::jsDialogContinue(false, "");
//CWidgetManager::getInstance()->popModalWindow();
}
};
REGISTER_ACTION_HANDLER( CHandlerWebkitJSDialogCancel, "webkit_jsdialog_cancel");

@ -49,6 +49,10 @@
#include "nel/gui/group_html.h"
#include "nel/gui/group_header.h"
#ifdef WITH_CEF3
#include "nel/gui/group_webkit.h"
#endif
namespace NLGUI
{
void CReflectableRegister::registerClasses()
@ -88,6 +92,9 @@ namespace NLGUI
REGISTER_REFLECTABLE_CLASS(CGroupTree::SNode, CReflectable);
REGISTER_REFLECTABLE_CLASS(CGroupList, CInterfaceGroup);
REGISTER_REFLECTABLE_CLASS(CGroupHeader, CGroupList);
#ifdef WITH_CEF3
REGISTER_REFLECTABLE_CLASS(CGroupWebkit, CInterfaceGroup);
#endif
}
}

@ -0,0 +1,107 @@
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "nel/gui/webkit_app.h"
#include <cef_version.h>
namespace NLGUI {
// ***************************************************************
static bool isWebkitInitialized = false;
bool webkitInitialize(const CefMainArgs &args, const std::string &locale, const std::string &userAgent)
{
if (isWebkitInitialized)
{
nlerror("webkitInitialize called twice");
return false;
}
isWebkitInitialized = true;
// FIXME: could use lazy loading and disable webkit in CGroupWebkit when initialize fails
//printf(">> Cef initialize\n");
CefSettings settings;
// Specify the path for the sub-process webhelper executable.
//CefString(&settings.browser_subprocess_path).FromASCII("/path/to/webhelper.exe");
// Use own cache directory that is not in ryzom search path
CefString(&settings.cache_path).FromASCII("cache_cef3");
CefString(&settings.locale).FromString(locale);
// FIXME: cannot use 'Ryzom' as useragent, because that is used by webpages to detect ingame browser
//CefString(&settings.product_version).FromString(userAgent);
CefRefPtr<CWebkitApp> app(new CWebkitApp);
bool success = CefInitialize(args, settings, app.get(), NULL);
return success;
}
// Automatically called from CWebkitApp destructor
void webkitShutdown()
{
//printf(">> CEF shutdown\n");
if (!isWebkitInitialized)
return;
isWebkitInitialized = false;
CefShutdown();
}
// message from render thread
const char kFocusedNodeChangedMessage[] = "ClientRenderer.FocusedNodeChanged";
// shutdown Cef if it was initialized
CWebkitApp::~CWebkitApp()
{
if (isWebkitInitialized)
webkitShutdown();
}
// CefRenderProcessHandler
void CWebkitApp::OnFocusedNodeChanged(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefDOMNode> node)
{
//CEF_REQUIRE_RENDERER_THREAD();
bool is_editable = (node.get() && node->IsEditable());
if (is_editable != _LastIsEditable)
{
//printf(">> WebkitApp::OnFocusedNodeChanged\n");
_LastIsEditable = is_editable;
CefRefPtr<CefProcessMessage> message = CefProcessMessage::Create(kFocusedNodeChangedMessage);
message->GetArgumentList()->SetBool(0, is_editable);
browser->SendProcessMessage(PID_BROWSER, message);
}
}
// return CEF version
std::string CWebkitApp::getChromeVersion()
{
// Chrome/39.0.2171.95
char buffer[256];
sprintf(buffer, "Chrome/%d.%d.%d.%d", CHROME_VERSION_MAJOR, CHROME_VERSION_MINOR, CHROME_VERSION_BUILD, CHROME_VERSION_PATCH);
return std::string(buffer);
}
} // namespace

@ -0,0 +1,363 @@
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdpch.h"
#include "nel/gui/webkit_app.h"
#include "nel/gui/webkit_handler.h"
#include "nel/gui/group_webkit.h"
#include "nel/gui/view_text.h"
#include "nel/gui/group_editbox.h"
// gui window id for javascript dialog
#define WIN_WEBKIT_JS_ALERT "ui:interface:webkit_js_alert"
#define WIN_WEBKIT_JS_CONFIRM "ui:interface:webkit_js_confirm"
#define WIN_WEBKIT_JS_PROMPT "ui:interface:webkit_js_prompt"
namespace NLGUI {
// global pointer for last javscript dialog callback
CefRefPtr<CefJSDialogCallback> CWebkitHandler::_JSDialogCallback = NULL;
CWebkitHandler::CWebkitHandler():
_Window(NULL)
{
}
void CWebkitHandler::setWindow(CGroupWebkit *win)
{
_Window = win;
}
// CefClient
bool CWebkitHandler::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
CefProcessId source_process,
CefRefPtr<CefProcessMessage> message)
{
CEF_REQUIRE_UI_THREAD();
// message from render thread
//printf(">> OnProcessMessageReceived: process id:%d, name: %s\n",
// source_process, message->GetName().ToString().c_str());
std::string name = message->GetName();
if (name == kFocusedNodeChangedMessage)
{
bool is_editable = message->GetArgumentList()->GetBool(0);
if (_Window)
_Window->setKeyboardCapture(is_editable);
return true;
}
return false;
}
// CefLifeSpanHandler
bool CWebkitHandler::OnBeforePopup(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& target_url,
const CefString& target_frame_name,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings,
bool* no_javascript_access)
{
CEF_REQUIRE_IO_THREAD();
// FIXME: inject new browser using template xml, set url and set active, centered
std::string url(target_url);
// load popup into main window
if (target_url.size() > 0)
browser->GetMainFrame()->LoadURL(target_url);
// block popup
return true;
}
// CefDisplayHandler
void CWebkitHandler::OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title)
{
CEF_REQUIRE_UI_THREAD();
if (_Window)
_Window->setTitle(title.ToString());
}
// CefDisplayHandler
bool CWebkitHandler::OnTooltip(CefRefPtr<CefBrowser> browser, CefString &text)
{
CEF_REQUIRE_UI_THREAD();
if (_Window)
_Window->setTooltip(text.ToString());
return true;
}
// CefRenderHandler
bool CWebkitHandler::GetScreenInfo(CefRefPtr<CefBrowser> browser, CefScreenInfo& screen_info)
{
CEF_REQUIRE_UI_THREAD();
CefRect rect = CefRect(0, 0, 0, 0);
if (_Window)
{
rect.width = _Window->getTextureWidth();
rect.height = _Window->getTextureHeight();
}
screen_info = CefScreenInfo(
1.0f, // scale factor
32, // depth
8, // bits per component
false, // monochrome
rect, // rect - maximum size
rect // available rect - fullscreen maximum size
);
return true;
}
// CefRenderHandler
bool CWebkitHandler::GetViewRect(CefRefPtr<CefBrowser> browser, CefRect &rect)
{
CEF_REQUIRE_UI_THREAD();
rect = CefRect(0, 0, 0, 0);
if (_Window)
{
rect.width = _Window->getTextureWidth();
rect.height = _Window->getTextureHeight();
}
return true;
}
// CefRenderHandler
void CWebkitHandler::OnPopupShow(CefRefPtr<CefBrowser> browser, bool show)
{
CEF_REQUIRE_UI_THREAD();
if (_Window)
_Window->setPopupVisibility(show);
}
// CefRenderHandler
void CWebkitHandler::OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect)
{
CEF_REQUIRE_UI_THREAD();
if (_Window)
_Window->setPopupSize(rect);
}
// CefRenderHandler
void CWebkitHandler::OnPaint(CefRefPtr<CefBrowser> browser, PaintElementType type, const RectList &dirtyRects, const void *buffer, int width, int height)
{
CEF_REQUIRE_UI_THREAD();
if (_Window)
_Window->drawIntoTexture(dirtyRects, buffer, width, height, type == PET_POPUP);
}
// CefRenderHandler
void CWebkitHandler::OnCursorChange(CefRefPtr<CefBrowser> browser,
CefCursorHandle cursor,
CursorType type,
const CefCursorInfo& custom_cursor_info)
{
//printf(">> OnCursorChange: %d\n", type);
// FIXME: type=CT_CUSTOM, custom_cursor_info has cursor image
std::string cursorTexture;
switch(type)
{
case CT_CROSS:
cursorTexture = "curs_default.tga";
break;
case CT_HAND:
cursorTexture = "curs_pick.tga";
break;
case CT_IBEAM:
cursorTexture = "curs_pick_dup.tga";
break;
case CT_WAIT:
cursorTexture = "curs_rotate.tga";
break;
case CT_HELP:
cursorTexture = "curs_help.tga";
break;
default:
cursorTexture = "curs_default.tga";
}
// FIXME: works on login screen, but not ingame
CViewPointer *vp = dynamic_cast<CViewPointer *>(CWidgetManager::getInstance()->getPointer());
if(vp)
{
//printf(">> set cursor to [%s]\n", cursorTexture.c_str());
vp->setStringMode(false);
vp->setCursor(cursorTexture);
}
else
printf(">> error: cursor pointer\n");
}
// CefLoadHandler
void CWebkitHandler::OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
bool isLoading,
bool canGoBack,
bool canGoForward)
{
CEF_REQUIRE_UI_THREAD();
if (_Window)
_Window->setLoadingState(isLoading, canGoBack, canGoForward);
}
// CefLoadHandler
void CWebkitHandler::OnLoadError(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
ErrorCode errorCode,
const CefString &errorText,
const CefString &failedUrl)
{
CEF_REQUIRE_UI_THREAD();
std::stringstream ss;
ss << "<html><body bgcolor=\"white\">"
"<h2>Failed to load URL " << std::string(failedUrl) << " with error " << std::string(errorText) << " (" << errorCode << ")</h2>"
"</body></html>";
frame->LoadString(ss.str(), failedUrl);
}
// CefDisplayHandler
void CWebkitHandler::OnStatusMessage(CefRefPtr<CefBrowser> browser, const CefString& value)
{
CEF_REQUIRE_UI_THREAD();
if (_Window)
_Window->setStatusMessage(value.ToString());
}
// CefDisplayHandler
bool CWebkitHandler::OnConsoleMessage(CefRefPtr<CefBrowser> browser,
const CefString& message,
const CefString& source,
int line)
{
// Log a console message...
printf("[%d] %s: %s\n", line, source.ToString().c_str(), message.ToString().c_str());
return false;
}
// CefJSDialogHandler
bool CWebkitHandler::OnJSDialog(CefRefPtr<CefBrowser> browser,
const CefString& origin_url,
const CefString& accept_lang,
JSDialogType dialog_type,
const CefString& message_text,
const CefString& default_prompt_text,
CefRefPtr<CefJSDialogCallback> callback,
bool& suppress_message)
{
CEF_REQUIRE_UI_THREAD();
CInterfaceGroup* group;
_JSDialogCallback = NULL;
switch(dialog_type)
{
case JSDIALOGTYPE_ALERT:
group = CWidgetManager::getInstance()->getWindowFromId(WIN_WEBKIT_JS_ALERT);
if (group)
{
CViewText* text = dynamic_cast<CViewText*>(group->getView("text"));
if (text)
text->setText(ucstring(message_text.ToString()));
_JSDialogCallback = callback;
CWidgetManager::getInstance()->enableModalWindow(NULL, WIN_WEBKIT_JS_ALERT);
}
else
nldebug("window (%s) for javascript alert dialog not found", WIN_WEBKIT_JS_ALERT);
break;
case JSDIALOGTYPE_CONFIRM:
group = CWidgetManager::getInstance()->getWindowFromId(WIN_WEBKIT_JS_CONFIRM);
if (group)
{
CViewText* text = dynamic_cast<CViewText*>(group->getView("text"));
if (text)
text->setText(ucstring(message_text.ToString()));
_JSDialogCallback = callback;
CWidgetManager::getInstance()->enableModalWindow(NULL, WIN_WEBKIT_JS_CONFIRM);
}
else
nldebug("window (%s) for javascript confirm dialog not found", WIN_WEBKIT_JS_CONFIRM);
break;
case JSDIALOGTYPE_PROMPT:
group = CWidgetManager::getInstance()->getWindowFromId(WIN_WEBKIT_JS_PROMPT);
if (group)
{
CViewText* text = dynamic_cast<CViewText*>(group->getView("text"));
if (text)
text->setText(ucstring(message_text.ToString()));
CGroupEditBox* eb = dynamic_cast<CGroupEditBox*>(group->getGroup("prompt:eb"));
if (eb)
eb->setInputStringAsUtf8(default_prompt_text.ToString());
_JSDialogCallback = callback;
CWidgetManager::getInstance()->enableModalWindow(NULL, WIN_WEBKIT_JS_PROMPT);
}
else
nldebug("window (%s) for javascript prompt dialog not found", WIN_WEBKIT_JS_PROMPT);
break;
default:
// ignore dialog
break;
}
return _JSDialogCallback != NULL;
}
// CefJSDialogHandler
void CWebkitHandler::OnResetDialogState(CefRefPtr<CefBrowser> browser)
{
CEF_REQUIRE_UI_THREAD();
if (_JSDialogCallback)
{
CWidgetManager::getInstance()->popModalWindow();
_JSDialogCallback = NULL;
}
}
// static
void CWebkitHandler::jsDialogContinue(bool success, const std::string &input)
{
if (_JSDialogCallback)
{
_JSDialogCallback->Continue(success, input);
_JSDialogCallback = NULL;
}
}
}// namespace

@ -0,0 +1,146 @@
--
if not Webkit then
Webkit = {
count = 0
}
end
function Webkit:newWindow(url, width, height)
local id = "webkit" .. tostring(self.count);
self.count = self.count + 1;
local ui = createRootGroupInstance("webkit_browser", id, {
x = 0,
y = 0,
w = width,
h = height,
home = url
})
ui.active = true;
end
-- window becomes visible (:active=true)
function Webkit:onActive()
local uiWindow = getUICaller()
-- debugInfo("-- onActive [" .. uiWindow.id .. "]")
if not uiWindow.opened then
uiWindow.opened = true
end
if not uiWindow.active then
uiWindow.active = true
end
end
--
function Webkit:onJsDeactive()
local uiWindow = getUICaller()
-- debugInfo("-- onJsDeactive [" .. uiWindow.id .. "]")
runAH(getUICaller(), "webkit_jsdialog_cancel", "");
end
-- window is minimized
function Webkit:onClickHeaderClose()
-- ui:interface:webkit:header_closed
local uiWindow = getUICaller().parent
-- fixme: save current width/height and minimize window
end
-- window is restored from minimized state
function Webkit:onClickHeaderOpen()
-- ui:interface:webig:header_opened
local uiWindow = getUICaller().parent
-- fixme: restore saved width/height
end
function Webkit:onClickHome()
-- caller is :header_opened:browse_home
local uiWindow = getUICaller().parent.parent
-- window "home" attribute is used
local html = uiWindow:find("html")
html:browse("home")
end
function Webkit:onClickRedo()
-- caller is :header_opened:browse_redo
local uiWindow = getUICaller().parent.parent
local html = uiWindow:find("html")
html:browseRedo();
end
function Webkit:onClickUndo()
-- caller is :header_opened:browse_undo
local uiWindow = getUICaller().parent.parent
local html = uiWindow:find("html")
html:browseUndo();
end
function Webkit:onClickRefresh()
-- caller is :header_opened:browse_refresh
local uiWindow = getUICaller().parent.parent
local html = uiWindow:find("html")
html:refresh()
end
function Webkit:onGrabKeyboard()
-- caller is :header_opened:browse_refresh
local uiWindow = getUICaller().parent.parent
local html = uiWindow:find("html")
html.grab_keyboard = not html.grab_keyboard
end
function Webkit:onMenuHome()
-- :header_closed
-- :header_opened
local uiWindow = getUICaller().parent
local html = uiWindow:find("html")
html:browse("home")
end
function Webkit:onMenuZoomIn()
-- :header_closed
-- :header_opened
local uiWindow = getUICaller().parent
local html = uiWindow:find("html")
html:zoomIn()
end
function Webkit:onMenuZoomOut()
-- :header_closed
-- :header_opened
local uiWindow = getUICaller().parent
local html = uiWindow:find("html")
html:zoomOut()
end
function Webkit:onMenuZoomReset()
-- :header_closed
-- :header_opened
local uiWindow = getUICaller().parent
local html = uiWindow:find("html")
html:zoomReset()
end
function Webkit:onMenuGrabKeyboard()
local uiWindow = getUICaller().parent
local html = uiWindow:find("html")
html.grab_keyboard = not html.grab_keyboard;
end
function Webkit:onMenuQuit()
local uiWindow = getUICaller().parent
deleteUI(uiWindow)
end

@ -0,0 +1,78 @@
<interface_config>
<root id="interface" x="0" y="0" w="800" h="600" active="true"/>
<lua file="webkit.lua"/>
<group type="modal" id="webkit_js_alert" exit_click_out="false" mouse_pos="false" posref="MM MM" x="0" y="45" h="110" w="400" _child_resize_w="true" child_resize_wmargin="10" win_priority="%win_priority_highest" options="skin_modal" on_deactive="lua" on_deactive_params="Webkit:onJsDeactive()">
<view type="text" id="text" posref="TM TM" color="233, 197, 42, 255" x="0" y="-50" fontsize="10" global_color="false" shadow="true" hardtext="alert message..." multi_line="true" multi_line_space="0" multi_line_maxw_only="true" line_maxw="600"/>
<group id="indent_middle" child_resize_w="true" child_resize_wmargin="16" h="24" posref="BM BM" x="8" y="8">
<ctrl style="quit_button" id="button_ok" posref="TL TL" hardtext="uittOK" onclick_l="webkit_jsdialog" params_l="button=ok" color="10 250 180 255" col_over="180 250 180 255" col_pushed="180 255 180 255" text_color_normal="180 250 180 160" />
</group>
</group>
<group type="modal" id="webkit_js_confirm" exit_click_out="false" mouse_pos="false" posref="MM MM" x="0" y="45" h="110" w="400" _child_resize_w="true" child_resize_wmargin="10" win_priority="%win_priority_highest" options="skin_modal" on_deactive="lua" on_deactive_params="Webkit:onJsDeactive()">
<view type="text" id="text" posref="TM TM" color="233, 197, 42, 255" x="0" y="-50" fontsize="10" global_color="false" shadow="true" hardtext="confirm message..." multi_line="true" multi_line_space="0" multi_line_maxw_only="true" line_maxw="600"/>
<group id="indent_middle" child_resize_w="true" child_resize_wmargin="16" h="24" posref="BM BM" x="8" y="8">
<ctrl style="quit_button" id="button_ok" posref="TL TL" hardtext="uittOK" onclick_l="webkit_jsdialog" params_l="button=ok" color="10 250 180 255" col_over="180 250 180 255" col_pushed="180 255 180 255" text_color_normal="180 250 180 160" />
<ctrl style="quit_button" id="button_cancel" posparent="button_ok" posref="TR TL" x="4" hardtext="uittCancel" onclick_l="webkit_jsdialog" params_l="button=cancel" color="10 250 180 255" col_over="180 250 180 255" col_pushed="180 255 180 255" text_color_normal="180 250 180 160" />
</group>
</group>
<group type="modal" id="webkit_js_prompt" exit_click_out="false" mouse_pos="false" posref="MM MM" x="0" y="45" h="110" w="400" _child_resize_w="true" child_resize_wmargin="10" win_priority="%win_priority_highest" options="skin_modal" on_deactive="lua" on_deactive_params="Webkit:onJsDeactive()">
<view type="text" id="text" posref="TM TM" color="233, 197, 42, 255" x="0" y="-50" fontsize="10" global_color="false" shadow="true" hardtext="alert message..." multi_line="true" multi_line_space="0" multi_line_maxw_only="true" line_maxw="600"/>
<instance template="edit_box_widget" id="prompt" sizeref="w" posparent="text" posref="TM TM" x="2" y="-12" w="170" h="20" entry_type="text"/>
<group id="indent_middle" child_resize_w="true" child_resize_wmargin="16" h="24" posref="BM BM" x="8" y="8">
<ctrl style="quit_button" id="button_ok" posref="TL TL" hardtext="uittOK" onclick_l="webkit_jsdialog" params_l="button=ok" color="10 250 180 255" col_over="180 250 180 255" col_pushed="180 255 180 255" text_color_normal="180 250 180 160" />
<ctrl style="quit_button" id="button_cancel" posparent="button_ok" posref="TR TL" x="4" hardtext="uittCancel" onclick_l="webkit_jsdialog" params_l="button=cancel" color="10 250 180 255" col_over="180 250 180 255" col_pushed="180 255 180 255" text_color_normal="180 250 180 160" />
</group>
</group>
<group type="menu" id="webkit_menu" extends="base_menu_with_color">
<action id="home" name="uiHOME" handler="lua" params="Webkit:onMenuHome()"/>
<separator/>
<action id="zoom_in" name="uimZoomIn" handler="lua" params="Webkit:onMenuZoomIn()"/>
<action id="zoom_in" name="uimZoomOut" handler="lua" params="Webkit:onMenuZoomOut()"/>
<action id="zoom_reset" name="uiZoomReset" handler="lua" params="Webkit:onMenuZoomReset()"/>
<action id="grab_keyboard" name="uiGrabKeyboard" handler="lua" params="Webkit:onMenuGrabKeyboard()"/>
<separator/>
<action id="close" name="uiClose" handler="lua" params="Webkit:onMenuQuit()"/>
<separator/>
</group>
<template name="webkit_browser" home="" keep="true" x="0" y="0" w="800" h="600">
<group id="browser" type="container" w="#w" h="#h" x="#x" y="#y" pop_max_w="2000" pop_max_h="2000" pop_min_w="64" pop_min_h="32" header_color="UI:SAVE:WIN:COLORS:COM" posref="TL TL" title="" global_color="true" global_color_over="true" right_button="true" movable="true" active="false" resizer="true" on_active="lua" on_active_params="Webkit:onActive()">
<group id="header_closed" x="0" y="0" h="16" posref="TL TL" group_onclick_r="active_menu" group_params_r="menu=ui:interface:webkit_menu" on_active="lua" on_active_params="Webkit:onClickHeaderClose()"/>
<group id="header_opened" x="0" y="0" h="16" posref="TL TL" group_onclick_r="active_menu" group_params_r="menu=ui:interface:webkit_menu" on_active="lua" on_active_params="Webkit:onClickHeaderOpen()">
<ctrl id="browse_redo" button_type="push_button" style="text_button_header" frozen="true" x="-16" y="0" posref="MR MR" tooltip="uittBrowseRedo" hardtext="uiBrowseRedoButton" onclick_l="lua" params_l="Webkit:onClickRedo()"/>
<ctrl id="browse_undo" button_type="push_button" style="text_button_header" frozen="true" x="-4" y="0" posref="ML MR" posparent="browse_redo" tooltip="uittBrowseUndo" hardtext="uiBrowseUndoButton" onclick_l="lua" params_l="Webkit:onClickUndo()"/>
<ctrl id="browse_refresh" button_type="push_button" style="text_button_header" x="-4" y="0" posref="ML MR" posparent="browse_undo" tooltip="uittBrowseRefresh" hardtext="uiBrowseRefresh" onclick_l="lua" params_l="Webkit:onClickRefresh()"/>
<ctrl id="browse_home" button_type="push_button" style="text_button_header" x="-4" y="0" posref="ML MR" posparent="browse_refresh" tooltip="uittBrowseHome" hardtext="uiBrowseHome" onclick_l="lua" params_l="Webkit:onClickHome()"/>
<ctrl id="grab_keyboard" type="button" button_type="toggle_button" x="-8" y="0" posref="ML MR" posparent="browse_home" tooltip="uittGrabKeyboard" tx_normal="w_win_popin.tga" tx_over="W_button_16_over.tga" tx_pushed="w_warning.tga" onclick_l="lua" params_l="Webkit:onGrabKeyboard()" />
</group>
<group id="content" x="0" y="-2" w="0" h="-2" posref="TL TL">
<group id="html" type="webkit" posref="TL TL" home="#home" title_prefix="" sizeref="wh" x="2" y="-4" w="-4" h="-6">
<!--
<group id="black" posref="BR BR" sizeref="hw" w="-10" h="-12" inherit_gc_alpha="true"/>
<instance template="inner_thin_border" posparent="black" inherit_gc_alpha="true"/>
<view type="bitmap" id="black2" posparent="black" posref="MM MM" sizeref="wh" w="-2" h="-2" inherit_gc_alpha="true" scale="true" texture="blank.tga" global_color="false"/>
-->
</group>
<group id="status_bar" type="text" posref="BL BL" sizeref="w" x="0" y="0" h="16" active="false">
<view type="bitmap" id="black2" posref="MM MM" sizeref="wh" w="-2" h="-2" inherit_gc_alpha="true" scale="true" texture="grey_10.tga" global_color="false"/>
<!-- FIXME: correct texture and tooltip -->
<view type="bitmap" id="loading" posref="MR MR" x="-2" y="0" texture="w_online.tga" global_color="false"/>
<view type="text" id="status" posref="ML ML" x="2" y="0" color="255 255 255 255" shadow="true" value="status text"/>
</group>
</group>
</group>
</template>
<!-- define /webkit <url> command -->
<command name="webkit" action="lua" params="Webkit:newWindow([[+]], 800, 600)"/>
</interface_config>

@ -112,6 +112,11 @@ IF(APPLE)
TARGET_LINK_LIBRARIES(ryzom_client ${FOUNDATION_LIBRARY})
ENDIF(APPLE)
IF(WITH_CEF3)
INCLUDE_DIRECTORIES(${CEF3_INCLUDE_DIR})
#TARGET_LINK_LIBRARIES(ryzom_client ${CEF3_LIBRARIES})
ENDIF(WITH_CEF3)
ADD_DEFINITIONS(${LIBXML2_DEFINITIONS} ${CURL_DEFINITIONS} ${LUABIND_DEFINITIONS})
NL_DEFAULT_PROPS(ryzom_client "Ryzom, Client: Ryzom Core Client")

@ -64,6 +64,12 @@
#include "client_cfg.h"
#include "far_tp.h"
#ifdef WITH_CEF3
#include <cef_app.h>
#include "nel/gui/webkit_app.h"
#include "user_agent.h"
#endif
///////////
// USING //
///////////
@ -360,6 +366,28 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE /* hPrevInstance */, LPSTR cm
int main(int argc, char **argv)
#endif
{
#ifdef WITH_CEF3
#ifdef NL_OS_WINDOWS
CefMainArgs main_args(hInstance);
#else
CefMainArgs main_args(argc, argv);
#endif
// >>>>> webhelper.cpp >>>>>
{
// create app instance used in sub-process threads
CefRefPtr<CWebkitApp> app(new CWebkitApp);
sint result = CefExecuteProcess(main_args, app.get(), NULL);
if (result >= 0)
{
// child process ended
return result;
}
}
// <<<< webhelper.cpp <<<<<
#endif
// init the Nel context
CApplicationContext *appContext = new CApplicationContext;
@ -556,6 +584,19 @@ int main(int argc, char **argv)
prelogInit();
RYZOM_CATCH("Pre-Login Init")
#ifdef WITH_CEF3
{
std::string locale = ClientCfg.getHtmlLanguageCode();
// "Ryzom/ryzomcore/v0.12.0-dev-unix-x64 Chrome/39.0.2171.95"
std::string userAgent = getUserAgent() + " " + CWebkitApp::getChromeVersion();
if (!webkitInitialize(main_args, locale, userAgent))
{
nlerror("webkit initialize failed\n");
return -1;
}
}
#endif
// Log the client and choose from shard
RYZOM_TRY("Login")
if (!ClientCfg.Local && (ClientCfg.TestBrowser || ClientCfg.FSHost.empty()))

Loading…
Cancel
Save