diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt
index 440a5fcd3..6ff68433d 100644
--- a/code/CMakeLists.txt
+++ b/code/CMakeLists.txt
@@ -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)
diff --git a/code/CMakeModules/FindCEF3.cmake b/code/CMakeModules/FindCEF3.cmake
new file mode 100644
index 000000000..869c354b7
--- /dev/null
+++ b/code/CMakeModules/FindCEF3.cmake
@@ -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()
+
diff --git a/code/nel/include/nel/gui/group_webkit.h b/code/nel/include/nel/gui/group_webkit.h
new file mode 100644
index 000000000..9eeb4015f
--- /dev/null
+++ b/code/nel/include/nel/gui/group_webkit.h
@@ -0,0 +1,186 @@
+// Ryzom - MMORPG Framework
+// 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 .
+
+#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
+
+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 ¶m);
+ ~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 _Browser;
+ CefRefPtr _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
+
diff --git a/code/nel/include/nel/gui/webkit_app.h b/code/nel/include/nel/gui/webkit_app.h
new file mode 100644
index 000000000..545f59c2d
--- /dev/null
+++ b/code/nel/include/nel/gui/webkit_app.h
@@ -0,0 +1,72 @@
+// Ryzom - MMORPG Framework
+// 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 .
+
+#ifndef CL_WEBKIT_APP_H
+#define CL_WEBKIT_APP_H
+
+#include "nel/misc/types_nl.h"
+#include
+
+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 GetRenderProcessHandler() OVERRIDE
+ {
+ return this;
+ }
+
+ // CefRenderProcessHandler
+ virtual void OnFocusedNodeChanged(CefRefPtr browser,
+ CefRefPtr frame,
+ CefRefPtr 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
+
diff --git a/code/nel/include/nel/gui/webkit_handler.h b/code/nel/include/nel/gui/webkit_handler.h
new file mode 100644
index 000000000..fd573a37d
--- /dev/null
+++ b/code/nel/include/nel/gui/webkit_handler.h
@@ -0,0 +1,132 @@
+// Ryzom - MMORPG Framework
+// 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 .
+
+#ifndef CL_WEBKIT_HANDLER_H
+#define CL_WEBKIT_HANDLER_H
+
+#include
+#include
+
+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 GetRenderHandler() { return this; }
+ virtual CefRefPtr GetLifeSpanHandler(){ return this; }
+ virtual CefRefPtr GetLoadHandler() { return this; }
+ virtual CefRefPtr GetDisplayHandler() { return this; }
+ virtual CefRefPtr GetJSDialogHandler() { return this; }
+
+ // CefClient
+ virtual bool OnProcessMessageReceived(CefRefPtr browser,
+ CefProcessId source_process,
+ CefRefPtr message) OVERRIDE;
+
+ // CefLifeSpanHandler
+ virtual bool OnBeforePopup(CefRefPtr browser,
+ CefRefPtr frame,
+ const CefString& target_url,
+ const CefString& target_frame_name,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr& client,
+ CefBrowserSettings& settings,
+ bool* no_javascript_access) OVERRIDE;
+
+ // CefLoadHandler
+ void OnLoadingStateChange(CefRefPtr browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) OVERRIDE;
+
+ // CefLoadHandler
+ void OnLoadError(CefRefPtr browser,
+ CefRefPtr frame,
+ ErrorCode errorCode,
+ const CefString &errorText,
+ const CefString &failedUrl) OVERRIDE;
+
+ // CefDisplayHandler
+ virtual void OnTitleChange(CefRefPtr browser, const CefString& title) OVERRIDE;
+
+ // CefDisplayHandler
+ virtual bool OnTooltip(CefRefPtr browser, CefString &text) OVERRIDE;
+
+ // CefDisplayHandler
+ virtual void OnStatusMessage(CefRefPtr browser, const CefString& value) OVERRIDE;
+
+ // CefDisplayHandler
+ virtual bool OnConsoleMessage(CefRefPtr browser,
+ const CefString& message,
+ const CefString& source,
+ int line) OVERRIDE;
+
+ // CefJSDialogHandler
+ virtual bool OnJSDialog(CefRefPtr browser,
+ const CefString& origin_url,
+ const CefString& accept_lang,
+ JSDialogType dialog_type,
+ const CefString& message_text,
+ const CefString& default_prompt_text,
+ CefRefPtr callback,
+ bool& suppress_message) OVERRIDE;
+
+ //CefJSDialogHandler
+ virtual void OnResetDialogState(CefRefPtr browser) OVERRIDE;
+
+ // CefRenderHandler
+ virtual bool GetScreenInfo(CefRefPtr browser, CefScreenInfo& screen_info) OVERRIDE;
+ virtual bool GetViewRect(CefRefPtr browser, CefRect &rect) OVERRIDE;
+ virtual void OnPopupShow(CefRefPtr browser, bool show) OVERRIDE;
+ virtual void OnPopupSize(CefRefPtr browser, const CefRect& rect) OVERRIDE;
+ virtual void OnPaint(CefRefPtr browser, PaintElementType type, const RectList &dirtyRects, const void *buffer, int width, int height) OVERRIDE;
+ virtual void OnCursorChange(CefRefPtr 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 _JSDialogCallback;
+
+ IMPLEMENT_REFCOUNTING(CWebkitHandler);
+ };
+
+}// namespace
+
+#endif // CL_WEBKIT_HANDLER_H
+
diff --git a/code/nel/src/gui/CMakeLists.txt b/code/nel/src/gui/CMakeLists.txt
index 6e82b2240..3c3e5b45f 100644
--- a/code/nel/src/gui/CMakeLists.txt
+++ b/code/nel/src/gui/CMakeLists.txt
@@ -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)
diff --git a/code/nel/src/gui/group_webkit.cpp b/code/nel/src/gui/group_webkit.cpp
new file mode 100644
index 000000000..965aedb1d
--- /dev/null
+++ b/code/nel/src/gui/group_webkit.cpp
@@ -0,0 +1,976 @@
+// Ryzom - MMORPG Framework
+// 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 .
+
+#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
+
+using namespace std;
+using namespace NL3D;
+using namespace NLMISC;
+using namespace NLGUI;
+
+NLMISC_REGISTER_OBJECT(CViewBase, CGroupWebkit, std::string, "webkit");
+
+ CGroupWebkit::CGroupWebkit(const TCtorParam ¶m)
+: 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; iGetHost()->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(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(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(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(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 × = CWidgetManager::getInstance()->getInterfaceTimes();
+ // times.thisFrameMs / 1000.0f;
+
+ CefDoMessageLoopWork();
+}
+
+// ***************************************************************************
+void CGroupWebkit::showHideStatus(bool show)
+{
+ CInterfaceGroup* group = getParentContainer();
+ if (group)
+ {
+ CInterfaceGroup *pGroup = dynamic_cast(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(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(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(group->getCtrl("browse_refresh"));
+ if (btnRefresh)
+ btnRefresh->setFrozen(loading);
+
+ CCtrlBaseButton *btnUndo = dynamic_cast(group->getCtrl("browse_undo"));
+ if (btnUndo)
+ btnUndo->setFrozen(!undo);
+
+ CCtrlBaseButton *btnRedo = dynamic_cast(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(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");
+
diff --git a/code/nel/src/gui/reflect_register.cpp b/code/nel/src/gui/reflect_register.cpp
index f7f47b1f9..022b18e2f 100644
--- a/code/nel/src/gui/reflect_register.cpp
+++ b/code/nel/src/gui/reflect_register.cpp
@@ -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
}
}
diff --git a/code/nel/src/gui/webkit_app.cpp b/code/nel/src/gui/webkit_app.cpp
new file mode 100644
index 000000000..fe22bc20c
--- /dev/null
+++ b/code/nel/src/gui/webkit_app.cpp
@@ -0,0 +1,107 @@
+// Ryzom - MMORPG Framework
+// 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 .
+
+#include "nel/gui/webkit_app.h"
+
+#include
+
+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 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 browser,
+ CefRefPtr frame,
+ CefRefPtr node)
+ {
+ //CEF_REQUIRE_RENDERER_THREAD();
+
+ bool is_editable = (node.get() && node->IsEditable());
+ if (is_editable != _LastIsEditable)
+ {
+ //printf(">> WebkitApp::OnFocusedNodeChanged\n");
+ _LastIsEditable = is_editable;
+
+ CefRefPtr 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
+
diff --git a/code/nel/src/gui/webkit_handler.cpp b/code/nel/src/gui/webkit_handler.cpp
new file mode 100644
index 000000000..2857a8b18
--- /dev/null
+++ b/code/nel/src/gui/webkit_handler.cpp
@@ -0,0 +1,363 @@
+// Ryzom - MMORPG Framework
+// 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 .
+
+#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 CWebkitHandler::_JSDialogCallback = NULL;
+
+ CWebkitHandler::CWebkitHandler():
+ _Window(NULL)
+ {
+ }
+
+ void CWebkitHandler::setWindow(CGroupWebkit *win)
+ {
+ _Window = win;
+ }
+
+ // CefClient
+ bool CWebkitHandler::OnProcessMessageReceived(CefRefPtr browser,
+ CefProcessId source_process,
+ CefRefPtr 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 browser,
+ CefRefPtr frame,
+ const CefString& target_url,
+ const CefString& target_frame_name,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr& 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 browser, const CefString& title)
+ {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (_Window)
+ _Window->setTitle(title.ToString());
+ }
+
+ // CefDisplayHandler
+ bool CWebkitHandler::OnTooltip(CefRefPtr browser, CefString &text)
+ {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (_Window)
+ _Window->setTooltip(text.ToString());
+
+ return true;
+ }
+
+ // CefRenderHandler
+ bool CWebkitHandler::GetScreenInfo(CefRefPtr 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 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 browser, bool show)
+ {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (_Window)
+ _Window->setPopupVisibility(show);
+ }
+
+ // CefRenderHandler
+ void CWebkitHandler::OnPopupSize(CefRefPtr browser, const CefRect& rect)
+ {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (_Window)
+ _Window->setPopupSize(rect);
+ }
+
+ // CefRenderHandler
+ void CWebkitHandler::OnPaint(CefRefPtr 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 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(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 browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward)
+ {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (_Window)
+ _Window->setLoadingState(isLoading, canGoBack, canGoForward);
+ }
+
+ // CefLoadHandler
+ void CWebkitHandler::OnLoadError(CefRefPtr browser,
+ CefRefPtr frame,
+ ErrorCode errorCode,
+ const CefString &errorText,
+ const CefString &failedUrl)
+ {
+ CEF_REQUIRE_UI_THREAD();
+
+ std::stringstream ss;
+ ss << ""
+ "Failed to load URL " << std::string(failedUrl) << " with error " << std::string(errorText) << " (" << errorCode << ")
"
+ "";
+ frame->LoadString(ss.str(), failedUrl);
+ }
+
+ // CefDisplayHandler
+ void CWebkitHandler::OnStatusMessage(CefRefPtr browser, const CefString& value)
+ {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (_Window)
+ _Window->setStatusMessage(value.ToString());
+ }
+
+ // CefDisplayHandler
+ bool CWebkitHandler::OnConsoleMessage(CefRefPtr 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 browser,
+ const CefString& origin_url,
+ const CefString& accept_lang,
+ JSDialogType dialog_type,
+ const CefString& message_text,
+ const CefString& default_prompt_text,
+ CefRefPtr 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(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(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(group->getView("text"));
+ if (text)
+ text->setText(ucstring(message_text.ToString()));
+
+ CGroupEditBox* eb = dynamic_cast(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 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
+
diff --git a/code/ryzom/client/data/gamedev/webkit.lua b/code/ryzom/client/data/gamedev/webkit.lua
new file mode 100644
index 000000000..bfd99f591
--- /dev/null
+++ b/code/ryzom/client/data/gamedev/webkit.lua
@@ -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
+
+
diff --git a/code/ryzom/client/data/gamedev/webkit.xml b/code/ryzom/client/data/gamedev/webkit.xml
new file mode 100644
index 000000000..73aaa0f61
--- /dev/null
+++ b/code/ryzom/client/data/gamedev/webkit.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/code/ryzom/client/src/CMakeLists.txt b/code/ryzom/client/src/CMakeLists.txt
index 610e434ef..837c8d5fa 100644
--- a/code/ryzom/client/src/CMakeLists.txt
+++ b/code/ryzom/client/src/CMakeLists.txt
@@ -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")
diff --git a/code/ryzom/client/src/client.cpp b/code/ryzom/client/src/client.cpp
index d3bb5254e..9467d63e4 100644
--- a/code/ryzom/client/src/client.cpp
+++ b/code/ryzom/client/src/client.cpp
@@ -64,6 +64,12 @@
#include "client_cfg.h"
#include "far_tp.h"
+#ifdef WITH_CEF3
+#include
+#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 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()))