too many changes to list, many regressions were made, master will be UNSTABLE for a few days
This commit is contained in:
parent
19eb56997d
commit
f548825faf
|
@ -5,7 +5,7 @@ PROJECT(otclient)
|
||||||
SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}")
|
SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}")
|
||||||
|
|
||||||
OPTION(USE_PCH "Use precompiled header" ON)
|
OPTION(USE_PCH "Use precompiled header" ON)
|
||||||
OPTION(NO_CONSOLE "Disable console window on Windows" OFF)
|
OPTION(NO_CONSOLE "Disable console window on Windows platform" OFF)
|
||||||
OPTION(HANDLE_EXCEPTIONS "Generate crash reports" OFF)
|
OPTION(HANDLE_EXCEPTIONS "Generate crash reports" OFF)
|
||||||
OPTION(FORBIDDEN_FUNCTIONS "Enable forbidden lua functions" ON)
|
OPTION(FORBIDDEN_FUNCTIONS "Enable forbidden lua functions" ON)
|
||||||
OPTION(USE_OPENGLES2 "Use OpenGL ES 2.0 (for mobiles devices)" OFF)
|
OPTION(USE_OPENGLES2 "Use OpenGL ES 2.0 (for mobiles devices)" OFF)
|
||||||
|
@ -39,7 +39,7 @@ MESSAGE(STATUS "BUILD TYPE: " ${CMAKE_BUILD_TYPE})
|
||||||
|
|
||||||
# setup compiler options
|
# setup compiler options
|
||||||
IF(CMAKE_COMPILER_IS_GNUCXX)
|
IF(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
SET(CXX_WARNS "-Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-but-set-variable -Wno-unused-variable -Wno-switch")
|
SET(CXX_WARNS "-Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-but-set-variable -Wno-unused-variable -Wno-switch -Wno-missing-field-initializers")
|
||||||
SET(CMAKE_CXX_FLAGS "-std=gnu++0x -pipe ${CXX_WARNS}")
|
SET(CMAKE_CXX_FLAGS "-std=gnu++0x -pipe ${CXX_WARNS}")
|
||||||
SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3 -ggdb3 -fno-inline")
|
SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3 -ggdb3 -fno-inline")
|
||||||
SET(CMAKE_CXX_FLAGS_RELEASE "-O2")
|
SET(CMAKE_CXX_FLAGS_RELEASE "-O2")
|
||||||
|
@ -68,9 +68,9 @@ SET(SOURCES
|
||||||
|
|
||||||
# otclient
|
# otclient
|
||||||
src/otclient/otclient.cpp
|
src/otclient/otclient.cpp
|
||||||
|
src/otclient/luafunctions.cpp
|
||||||
|
|
||||||
# otclient luascript
|
# otclient luascript
|
||||||
src/otclient/luascript/luafunctions.cpp
|
|
||||||
src/otclient/luascript/luavaluecasts.cpp
|
src/otclient/luascript/luavaluecasts.cpp
|
||||||
|
|
||||||
# otclient core
|
# otclient core
|
||||||
|
@ -99,6 +99,10 @@ SET(SOURCES
|
||||||
src/otclient/net/protocolgamesend.cpp
|
src/otclient/net/protocolgamesend.cpp
|
||||||
src/otclient/net/protocolgameparse.cpp
|
src/otclient/net/protocolgameparse.cpp
|
||||||
|
|
||||||
|
# framework
|
||||||
|
src/framework/application.cpp
|
||||||
|
src/framework/luafunctions.cpp
|
||||||
|
|
||||||
# framework third party
|
# framework third party
|
||||||
src/framework/thirdparty/apngloader.cpp
|
src/framework/thirdparty/apngloader.cpp
|
||||||
|
|
||||||
|
@ -118,9 +122,11 @@ SET(SOURCES
|
||||||
src/framework/core/eventdispatcher.cpp
|
src/framework/core/eventdispatcher.cpp
|
||||||
src/framework/core/modulemanager.cpp
|
src/framework/core/modulemanager.cpp
|
||||||
src/framework/core/module.cpp
|
src/framework/core/module.cpp
|
||||||
src/framework/core/engine.cpp
|
|
||||||
src/framework/core/clock.cpp
|
src/framework/core/clock.cpp
|
||||||
|
|
||||||
|
# framework platform
|
||||||
|
src/framework/platform/platformwindow.cpp
|
||||||
|
|
||||||
# framework graphics
|
# framework graphics
|
||||||
src/framework/graphics/font.cpp
|
src/framework/graphics/font.cpp
|
||||||
src/framework/graphics/fontmanager.cpp
|
src/framework/graphics/fontmanager.cpp
|
||||||
|
@ -144,7 +150,6 @@ SET(SOURCES
|
||||||
src/framework/luascript/luainterface.cpp
|
src/framework/luascript/luainterface.cpp
|
||||||
src/framework/luascript/luaobject.cpp
|
src/framework/luascript/luaobject.cpp
|
||||||
src/framework/luascript/luaexception.cpp
|
src/framework/luascript/luaexception.cpp
|
||||||
src/framework/luascript/luafunctions.cpp
|
|
||||||
src/framework/luascript/luavaluecasts.cpp
|
src/framework/luascript/luavaluecasts.cpp
|
||||||
|
|
||||||
# framework ui
|
# framework ui
|
||||||
|
@ -172,7 +177,7 @@ IF(FORBIDDEN_FUNCTIONS)
|
||||||
ENDIF(FORBIDDEN_FUNCTIONS)
|
ENDIF(FORBIDDEN_FUNCTIONS)
|
||||||
|
|
||||||
IF(WIN32)
|
IF(WIN32)
|
||||||
SET(SOURCES ${SOURCES} src/framework/platform/win32platform.cpp)
|
SET(SOURCES ${SOURCES} src/framework/platform/win32window.cpp)
|
||||||
SET(ADDITIONAL_LIBRARIES ws2_32 mswsock)
|
SET(ADDITIONAL_LIBRARIES ws2_32 mswsock)
|
||||||
|
|
||||||
IF(CMAKE_COMPILER_IS_GNUCXX)
|
IF(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
|
@ -180,7 +185,6 @@ IF(WIN32)
|
||||||
ENDIF(CMAKE_COMPILER_IS_GNUCXX)
|
ENDIF(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
|
|
||||||
IF(NO_CONSOLE)
|
IF(NO_CONSOLE)
|
||||||
ADD_DEFINITIONS(-DWIN32_NO_CONSOLE)
|
|
||||||
IF(CMAKE_COMPILER_IS_GNUCXX)
|
IF(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -mwindows")
|
SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -mwindows")
|
||||||
ENDIF(CMAKE_COMPILER_IS_GNUCXX)
|
ENDIF(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
|
@ -195,7 +199,7 @@ IF(WIN32)
|
||||||
ELSE(WIN32)
|
ELSE(WIN32)
|
||||||
SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -rdynamic")
|
SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -rdynamic")
|
||||||
SET(ADDITIONAL_LIBRARIES pthread)
|
SET(ADDITIONAL_LIBRARIES pthread)
|
||||||
SET(SOURCES ${SOURCES} src/framework/platform/x11platform.cpp)
|
SET(SOURCES ${SOURCES} src/framework/platform/x11window.cpp)
|
||||||
ENDIF(WIN32)
|
ENDIF(WIN32)
|
||||||
|
|
||||||
# target executable
|
# target executable
|
||||||
|
|
14
TODO
14
TODO
|
@ -14,3 +14,17 @@ fix moving windows and tooltips conflicts
|
||||||
todo display otclient icon in window bar
|
todo display otclient icon in window bar
|
||||||
remake otui styles states system
|
remake otui styles states system
|
||||||
padding
|
padding
|
||||||
|
|
||||||
|
|
||||||
|
rename Game to g_game, etc
|
||||||
|
implement Console key binding
|
||||||
|
fatal error if sprite load fails
|
||||||
|
impl vertical sync, clipboard
|
||||||
|
crash handler
|
||||||
|
modify COnnection::poll()
|
||||||
|
setOnClose
|
||||||
|
review and reenable some warnings
|
||||||
|
make lua/c++ logger more friendly
|
||||||
|
bind every global lua function in a static class
|
||||||
|
use metatable for Point,Rect,Color,Size lua classes
|
||||||
|
lua binder generator
|
||||||
|
|
|
@ -81,7 +81,7 @@ local function completeCommand()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function onKeyPress(widget, keyCode, keyChar, keyboardModifiers)
|
local function onKeyPress(widget, keyCode, keyText, keyboardModifiers)
|
||||||
if keyboardModifiers == KeyboardNoModifier then
|
if keyboardModifiers == KeyboardNoModifier then
|
||||||
-- execute current command
|
-- execute current command
|
||||||
if keyCode == KeyReturn or keyCode == keyEnter then
|
if keyCode == KeyReturn or keyCode == keyEnter then
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Color = {}
|
|
@ -0,0 +1 @@
|
||||||
|
Point = {}
|
|
@ -0,0 +1 @@
|
||||||
|
Rect = {}
|
|
@ -0,0 +1 @@
|
||||||
|
Size = {}
|
|
@ -6,7 +6,7 @@ local loadBox
|
||||||
local characterList
|
local characterList
|
||||||
|
|
||||||
-- private functions
|
-- private functions
|
||||||
local function onCharactersWindowKeyPress(self, keyCode, keyChar, keyboardModifiers)
|
local function onCharactersWindowKeyPress(self, keyCode, keyText, keyboardModifiers)
|
||||||
if keyboardModifiers == KeyboardNoModifier then
|
if keyboardModifiers == KeyboardNoModifier then
|
||||||
if keyCode == KeyUp or keyCode == KeyTab then
|
if keyCode == KeyUp or keyCode == KeyTab then
|
||||||
characterList:focusPreviousChild(ActiveFocusReason)
|
characterList:focusPreviousChild(ActiveFocusReason)
|
||||||
|
@ -47,7 +47,7 @@ local function tryLogin(charInfo, tries)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- save last used character
|
-- save last used character
|
||||||
ConfigManager.set('lastUsedCharacter', charInfo.characterName)
|
g_configs.set('lastUsedCharacter', charInfo.characterName)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- public functions
|
-- public functions
|
||||||
|
@ -75,7 +75,7 @@ function CharacterList.create(characters, premDays)
|
||||||
label.worldHost = worldHost
|
label.worldHost = worldHost
|
||||||
label.worldPort = worldIp
|
label.worldPort = worldIp
|
||||||
|
|
||||||
if i == 1 or ConfigManager.get('lastUsedCharacter') == characterName then
|
if i == 1 or g_configs.get('lastUsedCharacter') == characterName then
|
||||||
characterList:focusChild(label, ActiveFocusReason)
|
characterList:focusChild(label, ActiveFocusReason)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,8 +11,8 @@ local function clearAccountFields()
|
||||||
enterGame:getChildById('accountNameLineEdit'):clearText()
|
enterGame:getChildById('accountNameLineEdit'):clearText()
|
||||||
enterGame:getChildById('accountPasswordLineEdit'):clearText()
|
enterGame:getChildById('accountPasswordLineEdit'):clearText()
|
||||||
enterGame:getChildById('accountNameLineEdit'):focus()
|
enterGame:getChildById('accountNameLineEdit'):focus()
|
||||||
ConfigManager.set('account', nil)
|
g_configs.set('account', nil)
|
||||||
ConfigManager.set('password', nil)
|
g_configs.set('password', nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function onError(protocol, error)
|
local function onError(protocol, error)
|
||||||
|
@ -30,9 +30,9 @@ end
|
||||||
|
|
||||||
local function onCharacterList(protocol, characters, premDays)
|
local function onCharacterList(protocol, characters, premDays)
|
||||||
if enterGame:getChildById('rememberPasswordBox'):isChecked() then
|
if enterGame:getChildById('rememberPasswordBox'):isChecked() then
|
||||||
ConfigManager.set('account', EnterGame.account)
|
g_configs.set('account', EnterGame.account)
|
||||||
ConfigManager.set('password', EnterGame.password)
|
g_configs.set('password', EnterGame.password)
|
||||||
ConfigManager.set('autologin', tostring(enterGame:getChildById('autoLoginBox'):isChecked()))
|
g_configs.set('autologin', tostring(enterGame:getChildById('autoLoginBox'):isChecked()))
|
||||||
else
|
else
|
||||||
clearAccountFields()
|
clearAccountFields()
|
||||||
end
|
end
|
||||||
|
@ -40,9 +40,9 @@ local function onCharacterList(protocol, characters, premDays)
|
||||||
loadBox:destroy()
|
loadBox:destroy()
|
||||||
CharacterList.create(characters, premDays)
|
CharacterList.create(characters, premDays)
|
||||||
|
|
||||||
local lastMotdNumber = tonumber(ConfigManager.get("motd"))
|
local lastMotdNumber = tonumber(g_configs.get("motd"))
|
||||||
if motdNumber and motdNumber ~= lastMotdNumber then
|
if motdNumber and motdNumber ~= lastMotdNumber then
|
||||||
ConfigManager.set("motd", motdNumber)
|
g_configs.set("motd", motdNumber)
|
||||||
local motdBox = displayInfoBox("Message of the day", motdMessage)
|
local motdBox = displayInfoBox("Message of the day", motdMessage)
|
||||||
motdBox.onOk = CharacterList.show
|
motdBox.onOk = CharacterList.show
|
||||||
CharacterList.hide()
|
CharacterList.hide()
|
||||||
|
@ -53,11 +53,11 @@ end
|
||||||
function EnterGame.create()
|
function EnterGame.create()
|
||||||
enterGame = UI.display('entergame.otui')
|
enterGame = UI.display('entergame.otui')
|
||||||
|
|
||||||
local account = ConfigManager.get('account')
|
local account = g_configs.get('account')
|
||||||
local password = ConfigManager.get('password')
|
local password = g_configs.get('password')
|
||||||
local host = ConfigManager.get('host')
|
local host = g_configs.get('host')
|
||||||
local port = tonumber(ConfigManager.get('port'))
|
local port = tonumber(g_configs.get('port'))
|
||||||
local autologin = toboolean(ConfigManager.get('autologin'))
|
local autologin = toboolean(g_configs.get('autologin'))
|
||||||
|
|
||||||
enterGame:getChildById('accountNameLineEdit'):setText(account)
|
enterGame:getChildById('accountNameLineEdit'):setText(account)
|
||||||
enterGame:getChildById('accountPasswordLineEdit'):setText(password)
|
enterGame:getChildById('accountPasswordLineEdit'):setText(password)
|
||||||
|
@ -93,8 +93,8 @@ function EnterGame.doLogin()
|
||||||
EnterGame.port = enterGame:getChildById('serverPortLineEdit'):getText()
|
EnterGame.port = enterGame:getChildById('serverPortLineEdit'):getText()
|
||||||
EnterGame.hide()
|
EnterGame.hide()
|
||||||
|
|
||||||
ConfigManager.set('host', EnterGame.host)
|
g_configs.set('host', EnterGame.host)
|
||||||
ConfigManager.set('port', EnterGame.port)
|
g_configs.set('port', EnterGame.port)
|
||||||
|
|
||||||
local protocolLogin = ProtocolLogin.create()
|
local protocolLogin = ProtocolLogin.create()
|
||||||
protocolLogin.onError = onError
|
protocolLogin.onError = onError
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
-- private functions
|
-- private functions
|
||||||
local function onGameKeyPress(self, keyCode, keyChar, keyboardModifiers)
|
local function onGameKeyPress(self, keyCode, keyText, keyboardModifiers)
|
||||||
if keyboardModifiers == KeyboardCtrlModifier then
|
if keyboardModifiers == KeyboardCtrlModifier then
|
||||||
if keyCode == KeyG then
|
if keyCode == KeyG then
|
||||||
CharacterList.show()
|
CharacterList.show()
|
||||||
|
|
|
@ -6,8 +6,8 @@ local fpsEnabled = false
|
||||||
local vsyncEnabled = false
|
local vsyncEnabled = false
|
||||||
|
|
||||||
function getConfig(name, default)
|
function getConfig(name, default)
|
||||||
if ConfigManager.exists(name) then
|
if g_configs.exists(name) then
|
||||||
local val = string.trim(ConfigManager.get(name))
|
local val = string.trim(g_configs.get(name))
|
||||||
if val == 'true' or val == 'false' then
|
if val == 'true' or val == 'false' then
|
||||||
return toboolean(val)
|
return toboolean(val)
|
||||||
else
|
else
|
||||||
|
@ -15,7 +15,7 @@ function getConfig(name, default)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if default ~= nil then
|
if default ~= nil then
|
||||||
ConfigManager.set(name, default)
|
g_configs.set(name, default)
|
||||||
return default
|
return default
|
||||||
else
|
else
|
||||||
return nil
|
return nil
|
||||||
|
@ -24,13 +24,13 @@ function getConfig(name, default)
|
||||||
end
|
end
|
||||||
|
|
||||||
function setConfig(name, value)
|
function setConfig(name, value)
|
||||||
ConfigManager.set(name, tostring(value))
|
g_configs.set(name, tostring(value))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- private functions
|
-- private functions
|
||||||
function Options.enableVsync(on)
|
function Options.enableVsync(on)
|
||||||
vsyncEnabled = on
|
vsyncEnabled = on
|
||||||
setVerticalSync(on)
|
g_window.setVerticalSync(on)
|
||||||
setConfig('vsync', on)
|
setConfig('vsync', on)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
OTClient = { }
|
||||||
|
|
||||||
|
-- TODO: load and save configurations
|
||||||
|
function OTClient.init()
|
||||||
|
g_window.move({ x=220, y=220 })
|
||||||
|
g_window.resize({ width=800, height=600 })
|
||||||
|
g_window.setTitle('OTClient')
|
||||||
|
g_window.setIcon('otcicon.png')
|
||||||
|
|
||||||
|
addEvent(g_window.show)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function OTClient.terminate()
|
||||||
|
g_window.hide()
|
||||||
|
end
|
|
@ -3,6 +3,8 @@ Module
|
||||||
description: Load all other otclient modules
|
description: Load all other otclient modules
|
||||||
author: OTClient team
|
author: OTClient team
|
||||||
website: https://github.com/edubart/otclient
|
website: https://github.com/edubart/otclient
|
||||||
|
autoLoad: true
|
||||||
|
autoLoadPriority: 10
|
||||||
dependencies:
|
dependencies:
|
||||||
- core
|
- core
|
||||||
- background
|
- background
|
||||||
|
@ -16,3 +18,10 @@ Module
|
||||||
- chat
|
- chat
|
||||||
- outfit
|
- outfit
|
||||||
- tibiafiles
|
- tibiafiles
|
||||||
|
|
||||||
|
onLoad: |
|
||||||
|
require 'otclient'
|
||||||
|
return OTClient.init()
|
||||||
|
|
||||||
|
onUnload: |
|
||||||
|
OTClient.terminate()
|
||||||
|
|
|
@ -5,9 +5,9 @@ local currentToolTip
|
||||||
|
|
||||||
-- private functions
|
-- private functions
|
||||||
local function moveToolTip(tooltip)
|
local function moveToolTip(tooltip)
|
||||||
local pos = getMouseCursorPos()
|
local pos = g_window.getMousePos()
|
||||||
pos.y = pos.y + 1
|
pos.y = pos.y + 1
|
||||||
local xdif = getScreenSize().width - (pos.x + tooltip:getWidth())
|
local xdif = g_window.getSize().width - (pos.x + tooltip:getWidth())
|
||||||
if xdif < 2 then
|
if xdif < 2 then
|
||||||
pos.x = pos.x - tooltip:getWidth() - 3
|
pos.x = pos.x - tooltip:getWidth() - 3
|
||||||
else
|
else
|
||||||
|
|
|
@ -4,6 +4,7 @@ Module
|
||||||
author: OTClient team
|
author: OTClient team
|
||||||
website: https://github.com/edubart/otclient
|
website: https://github.com/edubart/otclient
|
||||||
autoLoad: true
|
autoLoad: true
|
||||||
|
autoLoadPriority: 2
|
||||||
dependencies:
|
dependencies:
|
||||||
- core
|
- core
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,207 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/otclient>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "application.h"
|
||||||
|
#include <framework/core/clock.h>
|
||||||
|
#include <framework/core/resourcemanager.h>
|
||||||
|
#include <framework/core/modulemanager.h>
|
||||||
|
#include <framework/core/eventdispatcher.h>
|
||||||
|
#include <framework/core/configmanager.h>
|
||||||
|
#include <framework/net/connection.h>
|
||||||
|
#include <framework/platform/platformwindow.h>
|
||||||
|
#include <framework/ui/uimanager.h>
|
||||||
|
#include <framework/ui/uiwidget.h>
|
||||||
|
#include <framework/graphics/graphics.h>
|
||||||
|
#include <framework/luascript/luainterface.h>
|
||||||
|
|
||||||
|
void exitSignalHandler(int sig)
|
||||||
|
{
|
||||||
|
static bool signaled = false;
|
||||||
|
switch(sig) {
|
||||||
|
case SIGTERM:
|
||||||
|
case SIGINT:
|
||||||
|
if(!signaled) {
|
||||||
|
signaled = true;
|
||||||
|
g_dispatcher.addEvent(std::bind(&Application::close, &g_app));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::init(const std::string& appName, const std::vector<std::string>& args)
|
||||||
|
{
|
||||||
|
logInfo("Starting application...");
|
||||||
|
|
||||||
|
m_pollCycleDelay = POLL_CYCLE_DELAY;
|
||||||
|
m_appName = appName;
|
||||||
|
|
||||||
|
// capture exit signals
|
||||||
|
signal(SIGTERM, exitSignalHandler);
|
||||||
|
signal(SIGINT, exitSignalHandler);
|
||||||
|
|
||||||
|
// initialize lua
|
||||||
|
g_lua.init();
|
||||||
|
registerLuaFunctions();
|
||||||
|
|
||||||
|
// initialize resources
|
||||||
|
g_resources.init(args[0].c_str());
|
||||||
|
|
||||||
|
// loads user configuration
|
||||||
|
if(!g_configs.load("config.otml"))
|
||||||
|
logInfo("Using default configurations.");
|
||||||
|
|
||||||
|
// initialize the ui
|
||||||
|
g_ui.init();
|
||||||
|
|
||||||
|
// setup platform window
|
||||||
|
g_window.init();
|
||||||
|
g_window.setOnResize(std::bind(&Application::resize, this, _1));
|
||||||
|
g_window.setOnInputEvent(std::bind(&Application::inputEvent, this, _1));
|
||||||
|
g_window.setOnClose(std::bind(&Application::close, this));
|
||||||
|
|
||||||
|
// initialize graphics
|
||||||
|
g_graphics.init();
|
||||||
|
|
||||||
|
// fire first resize
|
||||||
|
resize(g_window.getSize());
|
||||||
|
|
||||||
|
// auto load lua modules
|
||||||
|
g_modules.discoverAndLoadModules();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Application::terminate()
|
||||||
|
{
|
||||||
|
// hide the window because there is no render anymore
|
||||||
|
g_window.hide();
|
||||||
|
|
||||||
|
// run modules unload events
|
||||||
|
g_modules.unloadModules();
|
||||||
|
|
||||||
|
// release remaining lua object references
|
||||||
|
g_lua.collectGarbage();
|
||||||
|
|
||||||
|
// poll remaining events
|
||||||
|
poll();
|
||||||
|
|
||||||
|
// terminate ui
|
||||||
|
g_ui.terminate();
|
||||||
|
|
||||||
|
// terminate network
|
||||||
|
Connection::terminate();
|
||||||
|
|
||||||
|
// flush remaining dispatcher events
|
||||||
|
g_dispatcher.flush();
|
||||||
|
|
||||||
|
// terminate graphics
|
||||||
|
g_graphics.terminate();
|
||||||
|
|
||||||
|
// save configurations
|
||||||
|
g_configs.save();
|
||||||
|
|
||||||
|
// release resources
|
||||||
|
g_resources.terminate();
|
||||||
|
|
||||||
|
// terminate script environment
|
||||||
|
g_lua.terminate();
|
||||||
|
|
||||||
|
// release platform window
|
||||||
|
g_window.terminate();
|
||||||
|
|
||||||
|
logInfo("Application ended successfully.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::run()
|
||||||
|
{
|
||||||
|
ticks_t lastPollTicks = g_clock.updateTicks();
|
||||||
|
m_stopping = false;
|
||||||
|
m_running = true;
|
||||||
|
|
||||||
|
// run the first poll
|
||||||
|
poll();
|
||||||
|
|
||||||
|
if(g_ui.getRootWidget()->getChildCount() == 0) {
|
||||||
|
logError("There is no root widgets to display, the app will close");
|
||||||
|
m_stopping = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(!m_stopping) {
|
||||||
|
g_clock.updateTicks();
|
||||||
|
|
||||||
|
// poll events every POLL_CYCLE_DELAY
|
||||||
|
// this delay exists to avoid massive polling thus increasing framerate
|
||||||
|
if(g_clock.ticksElapsed(lastPollTicks) >= m_pollCycleDelay) {
|
||||||
|
poll();
|
||||||
|
lastPollTicks = g_clock.ticks();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(g_window.isVisible()) {
|
||||||
|
g_graphics.beginRender();
|
||||||
|
render();
|
||||||
|
g_graphics.endRender();
|
||||||
|
|
||||||
|
// update screen pixels
|
||||||
|
g_window.swapBuffers();
|
||||||
|
} else {
|
||||||
|
// sleeps until next poll to avoid massive cpu usage
|
||||||
|
g_clock.sleep(POLL_CYCLE_DELAY+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_stopping = false;
|
||||||
|
m_running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::exit()
|
||||||
|
{
|
||||||
|
logInfo("Exiting application..");
|
||||||
|
m_stopping = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::poll()
|
||||||
|
{
|
||||||
|
// poll input events
|
||||||
|
g_window.poll();
|
||||||
|
|
||||||
|
// poll network events
|
||||||
|
Connection::poll();
|
||||||
|
|
||||||
|
// poll application genareted events
|
||||||
|
g_dispatcher.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::render()
|
||||||
|
{
|
||||||
|
// everything is rendered by UI components
|
||||||
|
g_ui.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::resize(const Size& size)
|
||||||
|
{
|
||||||
|
g_graphics.resize(size);
|
||||||
|
g_ui.resize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::inputEvent(const InputEvent& event)
|
||||||
|
{
|
||||||
|
g_ui.inputEvent(event);
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/otclient>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef APPLICATION_H
|
||||||
|
#define APPLICATION_H
|
||||||
|
|
||||||
|
#include <framework/core/inputevent.h>
|
||||||
|
|
||||||
|
class Application
|
||||||
|
{
|
||||||
|
enum {
|
||||||
|
POLL_CYCLE_DELAY = 10
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void init(const std::string& appName, const std::vector<std::string>& args);
|
||||||
|
virtual void registerLuaFunctions();
|
||||||
|
virtual void terminate();
|
||||||
|
virtual void run();
|
||||||
|
virtual void exit();
|
||||||
|
virtual void poll();
|
||||||
|
virtual void close() { exit(); }
|
||||||
|
|
||||||
|
void setPollCycleDelay(int delay) { m_pollCycleDelay = delay; }
|
||||||
|
|
||||||
|
bool isRunning() { return m_running; }
|
||||||
|
bool isStopping() { return m_stopping; }
|
||||||
|
std::string getAppName() { return m_appName; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void render();
|
||||||
|
virtual void resize(const Size& size);
|
||||||
|
virtual void inputEvent(const InputEvent& event);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_appName;
|
||||||
|
int m_pollCycleDelay;
|
||||||
|
Boolean<false> m_running;
|
||||||
|
Boolean<false> m_stopping;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Application& g_app;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -225,6 +225,16 @@ namespace Fw
|
||||||
OtherFocusReason
|
OtherFocusReason
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum InputEventType {
|
||||||
|
NoInputEvent = 0,
|
||||||
|
KeyPressInputEvent,
|
||||||
|
KeyReleaseInputEvent,
|
||||||
|
MousePressInputEvent,
|
||||||
|
MouseReleaseInputEvent,
|
||||||
|
MouseMoveInputEvent,
|
||||||
|
MouseWheelInputEvent
|
||||||
|
};
|
||||||
|
|
||||||
enum MouseButton {
|
enum MouseButton {
|
||||||
MouseNoButton = 0,
|
MouseNoButton = 0,
|
||||||
MouseLeftButton,
|
MouseLeftButton,
|
||||||
|
|
|
@ -22,14 +22,18 @@
|
||||||
|
|
||||||
#include "clock.h"
|
#include "clock.h"
|
||||||
|
|
||||||
|
// for usleep
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
Clock g_clock;
|
Clock g_clock;
|
||||||
|
|
||||||
Clock::Clock()
|
Clock::Clock()
|
||||||
{
|
{
|
||||||
m_startupTime = std::chrono::high_resolution_clock::now();
|
m_startupTime = std::chrono::high_resolution_clock::now();
|
||||||
|
m_currentTicks = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Clock::updateTicks()
|
ticks_t Clock::updateTicks()
|
||||||
{
|
{
|
||||||
auto timeNow = std::chrono::high_resolution_clock::now();
|
auto timeNow = std::chrono::high_resolution_clock::now();
|
||||||
m_currentTicks = std::chrono::duration_cast<std::chrono::milliseconds>(timeNow - m_startupTime).count();
|
m_currentTicks = std::chrono::duration_cast<std::chrono::milliseconds>(timeNow - m_startupTime).count();
|
||||||
|
|
|
@ -30,15 +30,15 @@ class Clock
|
||||||
public:
|
public:
|
||||||
Clock();
|
Clock();
|
||||||
|
|
||||||
int updateTicks();
|
ticks_t updateTicks();
|
||||||
void sleep(int ms);
|
void sleep(int ms);
|
||||||
|
|
||||||
int ticks() { return m_currentTicks; }
|
ticks_t ticks() { return m_currentTicks; }
|
||||||
int ticksElapsed(int prevTicks) { return ticks() - prevTicks; }
|
ticks_t ticksElapsed(long prevTicks) { return ticks() - prevTicks; }
|
||||||
int ticksFor(int delay) { return ticks() + delay; }
|
ticks_t ticksFor(int delay) { return ticks() + delay; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_currentTicks;
|
ticks_t m_currentTicks;
|
||||||
std::chrono::system_clock::time_point m_startupTime;
|
std::chrono::system_clock::time_point m_startupTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -26,9 +26,9 @@
|
||||||
#include "declarations.h"
|
#include "declarations.h"
|
||||||
|
|
||||||
struct ScheduledEvent {
|
struct ScheduledEvent {
|
||||||
ScheduledEvent(int ticks, const SimpleCallback& callback) : ticks(ticks), callback(callback) { }
|
ScheduledEvent(ticks_t ticks, const SimpleCallback& callback) : ticks(ticks), callback(callback) { }
|
||||||
bool operator<(const ScheduledEvent& other) const { return ticks > other.ticks; }
|
bool operator<(const ScheduledEvent& other) const { return ticks > other.ticks; }
|
||||||
int ticks;
|
ticks_t ticks;
|
||||||
SimpleCallback callback;
|
SimpleCallback callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -20,20 +20,20 @@
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef PLATFORMLISTENER_H
|
#ifndef INPUTEVENT_H
|
||||||
#define PLATFORMLISTENER_H
|
#define INPUTEVENT_H
|
||||||
|
|
||||||
#include "platformevent.h"
|
#include "declarations.h"
|
||||||
|
|
||||||
class PlatformListener
|
struct InputEvent {
|
||||||
{
|
Fw::InputEventType type;
|
||||||
public:
|
Fw::MouseWheelDirection wheelDirection;
|
||||||
/// Fired when user tries to close the window
|
Fw::MouseButton mouseButton;
|
||||||
virtual void onClose() = 0;
|
int keyboardModifiers;
|
||||||
/// Fired when user resize the window
|
std::string keyText;
|
||||||
virtual void onResize(const Size& size) = 0;
|
Fw::Key keyCode;
|
||||||
/// Fired when user press a key or move the mouse
|
Point mousePos;
|
||||||
virtual void onPlatformEvent(const PlatformEvent& event) = 0;
|
Point mouseMoved;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -22,7 +22,6 @@
|
||||||
|
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "eventdispatcher.h"
|
#include "eventdispatcher.h"
|
||||||
#include <framework/platform/platform.h>
|
|
||||||
|
|
||||||
Logger g_logger;
|
Logger g_logger;
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,11 @@
|
||||||
#include <framework/otml/otml.h>
|
#include <framework/otml/otml.h>
|
||||||
#include <framework/luascript/luainterface.h>
|
#include <framework/luascript/luainterface.h>
|
||||||
|
|
||||||
|
Module::Module(const std::string& name)
|
||||||
|
{
|
||||||
|
m_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
void Module::discover(const OTMLNodePtr& moduleNode)
|
void Module::discover(const OTMLNodePtr& moduleNode)
|
||||||
{
|
{
|
||||||
const static std::string none = "none";
|
const static std::string none = "none";
|
||||||
|
@ -34,6 +39,7 @@ void Module::discover(const OTMLNodePtr& moduleNode)
|
||||||
m_website = moduleNode->valueAt("website", none);
|
m_website = moduleNode->valueAt("website", none);
|
||||||
m_version = moduleNode->valueAt("version", none);
|
m_version = moduleNode->valueAt("version", none);
|
||||||
m_autoLoad = moduleNode->valueAt<bool>("autoLoad", false);
|
m_autoLoad = moduleNode->valueAt<bool>("autoLoad", false);
|
||||||
|
m_autoLoadPriority = moduleNode->valueAt<int>("autoLoadPriority", 100);
|
||||||
|
|
||||||
if(OTMLNodePtr node = moduleNode->get("dependencies")) {
|
if(OTMLNodePtr node = moduleNode->get("dependencies")) {
|
||||||
for(const OTMLNodePtr& tmp : node->children())
|
for(const OTMLNodePtr& tmp : node->children())
|
||||||
|
@ -57,6 +63,9 @@ void Module::discover(const OTMLNodePtr& moduleNode)
|
||||||
|
|
||||||
bool Module::load()
|
bool Module::load()
|
||||||
{
|
{
|
||||||
|
if(m_loaded)
|
||||||
|
return true;
|
||||||
|
|
||||||
for(const std::string& depName : m_dependencies) {
|
for(const std::string& depName : m_dependencies) {
|
||||||
ModulePtr dep = g_modules.getModule(depName);
|
ModulePtr dep = g_modules.getModule(depName);
|
||||||
if(!dep) {
|
if(!dep) {
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
class Module
|
class Module
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Module(const std::string& name) : m_loaded(false), m_autoLoad(false), m_name(name) { }
|
Module(const std::string& name);
|
||||||
void discover(const OTMLNodePtr& moduleNode);
|
void discover(const OTMLNodePtr& moduleNode);
|
||||||
|
|
||||||
bool load();
|
bool load();
|
||||||
|
@ -43,11 +43,13 @@ public:
|
||||||
std::string getAuthor() { return m_author; }
|
std::string getAuthor() { return m_author; }
|
||||||
std::string getWebsite() { return m_website; }
|
std::string getWebsite() { return m_website; }
|
||||||
std::string getVersion() { return m_version; }
|
std::string getVersion() { return m_version; }
|
||||||
bool autoLoad() { return m_autoLoad; }
|
bool isAutoLoad() { return m_autoLoad; }
|
||||||
|
int getAutoLoadPriority() { return m_autoLoadPriority; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_loaded;
|
Boolean<false> m_loaded;
|
||||||
bool m_autoLoad;
|
Boolean<false> m_autoLoad;
|
||||||
|
int m_autoLoadPriority;
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
std::string m_description;
|
std::string m_description;
|
||||||
std::string m_author;
|
std::string m_author;
|
||||||
|
|
|
@ -29,29 +29,32 @@ ModuleManager g_modules;
|
||||||
|
|
||||||
void ModuleManager::discoverAndLoadModules()
|
void ModuleManager::discoverAndLoadModules()
|
||||||
{
|
{
|
||||||
|
std::multimap<int, ModulePtr> m_autoLoadModules;
|
||||||
|
|
||||||
auto moduleDirs = g_resources.listDirectoryFiles("/");
|
auto moduleDirs = g_resources.listDirectoryFiles("/");
|
||||||
for(const std::string& moduleDir : moduleDirs) {
|
for(const std::string& moduleDir : moduleDirs) {
|
||||||
auto moduleFiles = g_resources.listDirectoryFiles("/" + moduleDir);
|
auto moduleFiles = g_resources.listDirectoryFiles("/" + moduleDir);
|
||||||
for(const std::string& file : moduleFiles) {
|
for(const std::string& moduleFile : moduleFiles) {
|
||||||
if(boost::ends_with(file, ".otmod"))
|
if(boost::ends_with(moduleFile, ".otmod")) {
|
||||||
discoverModule("/" + moduleDir + "/" + file);
|
ModulePtr module = discoverModule("/" + moduleDir + "/" + moduleFile);
|
||||||
|
if(module && module->isAutoLoad())
|
||||||
|
m_autoLoadModules.insert(make_pair(module->getAutoLoadPriority(), module));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// auto load modules
|
for(auto& pair : m_autoLoadModules) {
|
||||||
for(const ModulePtr& module : m_modules) {
|
ModulePtr module = pair.second;
|
||||||
if(!module->isLoaded() && module->autoLoad()) {
|
if(!module->isLoaded() && !module->load())
|
||||||
if(!module->load())
|
logFatal("A required module has failed to load, cannot continue to run.");
|
||||||
logFatal("A required module has failed to load, cannot continue to run.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModuleManager::discoverModule(const std::string& file)
|
ModulePtr ModuleManager::discoverModule(const std::string& moduleFile)
|
||||||
{
|
{
|
||||||
ModulePtr module;
|
ModulePtr module;
|
||||||
try {
|
try {
|
||||||
OTMLDocumentPtr doc = OTMLDocument::parse(file);
|
OTMLDocumentPtr doc = OTMLDocument::parse(moduleFile);
|
||||||
OTMLNodePtr moduleNode = doc->at("Module");
|
OTMLNodePtr moduleNode = doc->at("Module");
|
||||||
|
|
||||||
std::string name = moduleNode->valueAt("name");
|
std::string name = moduleNode->valueAt("name");
|
||||||
|
@ -62,10 +65,9 @@ bool ModuleManager::discoverModule(const std::string& file)
|
||||||
module->discover(moduleNode);
|
module->discover(moduleNode);
|
||||||
m_modules.push_back(module);
|
m_modules.push_back(module);
|
||||||
} catch(Exception& e) {
|
} catch(Exception& e) {
|
||||||
logError("Unable to discover module from file '", file, "': ", e.what());
|
logError("Unable to discover module from file '", moduleFile, "': ", e.what());
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return true;
|
return module;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModuleManager::unloadModules()
|
void ModuleManager::unloadModules()
|
||||||
|
|
|
@ -29,7 +29,7 @@ class ModuleManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void discoverAndLoadModules();
|
void discoverAndLoadModules();
|
||||||
bool discoverModule(const std::string& file);
|
ModulePtr discoverModule(const std::string& moduleFile);
|
||||||
void unloadModules();
|
void unloadModules();
|
||||||
|
|
||||||
ModulePtr getModule(const std::string& moduleName);
|
ModulePtr getModule(const std::string& moduleName);
|
||||||
|
|
|
@ -22,24 +22,28 @@
|
||||||
|
|
||||||
#include "resourcemanager.h"
|
#include "resourcemanager.h"
|
||||||
|
|
||||||
#include <framework/platform/platform.h>
|
#include <framework/application.h>
|
||||||
#include <framework/luascript/luainterface.h>
|
#include <framework/luascript/luainterface.h>
|
||||||
|
|
||||||
#include <physfs.h>
|
#include <physfs.h>
|
||||||
|
|
||||||
ResourceManager g_resources;
|
ResourceManager g_resources;
|
||||||
|
|
||||||
void ResourceManager::init(const char* argv0, const char *appName)
|
void ResourceManager::init(const char *argv0)
|
||||||
{
|
{
|
||||||
PHYSFS_init(argv0);
|
PHYSFS_init(argv0);
|
||||||
|
|
||||||
// try to find modules directory, all data lives there
|
// setup write directory
|
||||||
std::string baseDir = PHYSFS_getBaseDir();
|
if(!g_resources.setupWriteDir())
|
||||||
|
logError("Could not setup write directory");
|
||||||
|
|
||||||
|
// try to find modules directory, all data lives there
|
||||||
|
//TODO: move this to Application class
|
||||||
|
std::string baseDir = PHYSFS_getBaseDir();
|
||||||
std::string possibleDirs[] = { "modules",
|
std::string possibleDirs[] = { "modules",
|
||||||
baseDir + "modules",
|
baseDir + "modules",
|
||||||
baseDir + "../modules",
|
baseDir + "../modules",
|
||||||
baseDir + "../share/" + appName + "/otclient/modules",
|
baseDir + "../share/" + g_app.getAppName() + "/otclient/modules",
|
||||||
"" };
|
"" };
|
||||||
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
@ -52,14 +56,7 @@ void ResourceManager::init(const char* argv0, const char *appName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!found)
|
if(!found)
|
||||||
logFatal("Could not find modules directory.");
|
logFatal("Could not find modules directory");
|
||||||
|
|
||||||
// setup write directory
|
|
||||||
std::string dir = g_platform.getAppUserDir();
|
|
||||||
if(g_resources.setWriteDir(dir))
|
|
||||||
g_resources.addToSearchPath(dir);
|
|
||||||
else
|
|
||||||
logError("could not setup write directory");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResourceManager::terminate()
|
void ResourceManager::terminate()
|
||||||
|
@ -67,10 +64,22 @@ void ResourceManager::terminate()
|
||||||
PHYSFS_deinit();
|
PHYSFS_deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ResourceManager::setWriteDir(const std::string& path)
|
bool ResourceManager::setupWriteDir()
|
||||||
{
|
{
|
||||||
if(!PHYSFS_setWriteDir(path.c_str()))
|
std::string userDir = PHYSFS_getUserDir();
|
||||||
return false;
|
std::string dirName = Fw::mkstr(".", g_app.getAppName());
|
||||||
|
std::string writeDir = userDir + dirName;
|
||||||
|
if(!PHYSFS_setWriteDir(writeDir.c_str())) {
|
||||||
|
if(!PHYSFS_setWriteDir(userDir.c_str()))
|
||||||
|
return false;
|
||||||
|
if(!PHYSFS_mkdir(dirName.c_str())) {
|
||||||
|
PHYSFS_setWriteDir(NULL);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(!PHYSFS_setWriteDir(writeDir.c_str()))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
addToSearchPath(writeDir);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +106,7 @@ bool ResourceManager::fileExists(const std::string& fileName)
|
||||||
|
|
||||||
bool ResourceManager::directoryExists(const std::string& directoryName)
|
bool ResourceManager::directoryExists(const std::string& directoryName)
|
||||||
{
|
{
|
||||||
return (PHYSFS_exists(resolvePath(directoryName).c_str()) && PHYSFS_isDirectory(resolvePath(directoryName).c_str()));
|
return (PHYSFS_isDirectory(resolvePath(directoryName).c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResourceManager::loadFile(const std::string& fileName, std::iostream& out)
|
void ResourceManager::loadFile(const std::string& fileName, std::iostream& out)
|
||||||
|
|
|
@ -28,11 +28,10 @@
|
||||||
class ResourceManager
|
class ResourceManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void init(const char* argv0, const char *appName);
|
void init(const char *argv0);
|
||||||
void terminate();
|
void terminate();
|
||||||
|
|
||||||
/// Set output files directory
|
bool setupWriteDir();
|
||||||
bool setWriteDir(const std::string& path);
|
|
||||||
|
|
||||||
/// Add an package or directory to the search path
|
/// Add an package or directory to the search path
|
||||||
bool addToSearchPath(const std::string& path, bool insertInFront = true);
|
bool addToSearchPath(const std::string& path, bool insertInFront = true);
|
||||||
|
@ -55,6 +54,7 @@ public:
|
||||||
std::list<std::string> listDirectoryFiles(const std::string& directoryPath = "");
|
std::list<std::string> listDirectoryFiles(const std::string& directoryPath = "");
|
||||||
|
|
||||||
std::string resolvePath(const std::string& path);
|
std::string resolvePath(const std::string& path);
|
||||||
|
std::string getAppUserPath();
|
||||||
};
|
};
|
||||||
|
|
||||||
extern ResourceManager g_resources;
|
extern ResourceManager g_resources;
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <unistd.h>
|
#include <csignal>
|
||||||
|
|
||||||
// common STL headers
|
// common STL headers
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
|
@ -23,11 +23,8 @@
|
||||||
#include "animatedtexture.h"
|
#include "animatedtexture.h"
|
||||||
#include "graphics.h"
|
#include "graphics.h"
|
||||||
|
|
||||||
#include <framework/platform/platform.h>
|
|
||||||
#include <framework/core/eventdispatcher.h>
|
#include <framework/core/eventdispatcher.h>
|
||||||
|
|
||||||
#include <GL/gl.h>
|
|
||||||
|
|
||||||
AnimatedTexture::AnimatedTexture(int width, int height, int channels, int numFrames, uchar *framesPixels, int *framesDelay) :
|
AnimatedTexture::AnimatedTexture(int width, int height, int channels, int numFrames, uchar *framesPixels, int *framesDelay) :
|
||||||
Texture(),
|
Texture(),
|
||||||
m_numFrames(numFrames)
|
m_numFrames(numFrames)
|
||||||
|
|
|
@ -41,7 +41,7 @@ private:
|
||||||
std::vector<int> m_framesDelay;
|
std::vector<int> m_framesDelay;
|
||||||
int m_numFrames;
|
int m_numFrames;
|
||||||
int m_currentFrame;
|
int m_currentFrame;
|
||||||
int m_lastAnimCheckTicks;
|
ticks_t m_lastAnimCheckTicks;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#define FRAMEWORK_GRAPHICS_DECLARATIONS_H
|
#define FRAMEWORK_GRAPHICS_DECLARATIONS_H
|
||||||
|
|
||||||
#include <framework/global.h>
|
#include <framework/global.h>
|
||||||
|
#include "glutil.h"
|
||||||
|
|
||||||
class Texture;
|
class Texture;
|
||||||
class AnimatedTexture;
|
class AnimatedTexture;
|
||||||
|
|
|
@ -24,17 +24,6 @@
|
||||||
#include "graphics.h"
|
#include "graphics.h"
|
||||||
#include "texture.h"
|
#include "texture.h"
|
||||||
|
|
||||||
#include <framework/platform/platform.h>
|
|
||||||
|
|
||||||
#include <GL/gl.h>
|
|
||||||
#include <GL/glext.h>
|
|
||||||
|
|
||||||
PFNGLGENFRAMEBUFFERSPROC oglGenFramebuffers = 0;
|
|
||||||
PFNGLBINDFRAMEBUFFERPROC oglBindFramebuffer = 0;
|
|
||||||
PFNGLFRAMEBUFFERTEXTURE2DPROC oglFramebufferTexture2D = 0;
|
|
||||||
PFNGLDELETEFRAMEBUFFERSPROC oglDeleteFramebuffers = 0;
|
|
||||||
PFNGLCHECKFRAMEBUFFERSTATUSPROC oglCheckFramebufferStatus = 0;
|
|
||||||
|
|
||||||
FrameBuffer::FrameBuffer(int width, int height)
|
FrameBuffer::FrameBuffer(int width, int height)
|
||||||
{
|
{
|
||||||
m_fbo = 0;
|
m_fbo = 0;
|
||||||
|
@ -46,22 +35,15 @@ FrameBuffer::FrameBuffer(int width, int height)
|
||||||
// use FBO ext only if supported
|
// use FBO ext only if supported
|
||||||
if(g_graphics.isExtensionSupported("GL_ARB_framebuffer_object")) {
|
if(g_graphics.isExtensionSupported("GL_ARB_framebuffer_object")) {
|
||||||
m_fallbackOldImp = false;
|
m_fallbackOldImp = false;
|
||||||
if(!oglGenFramebuffers) {
|
|
||||||
oglGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)g_platform.getExtensionProcAddress("glGenFramebuffers");
|
|
||||||
oglBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)g_platform.getExtensionProcAddress("glBindFramebuffer");
|
|
||||||
oglFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)g_platform.getExtensionProcAddress("glFramebufferTexture2D");
|
|
||||||
oglDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)g_platform.getExtensionProcAddress("glDeleteFramebuffers");
|
|
||||||
oglCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)g_platform.getExtensionProcAddress("glCheckFramebufferStatus");
|
|
||||||
}
|
|
||||||
|
|
||||||
// generate FBO
|
// generate FBO
|
||||||
oglGenFramebuffers(1, &m_fbo);
|
glGenFramebuffers(1, &m_fbo);
|
||||||
oglBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fbo);
|
glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fbo);
|
||||||
|
|
||||||
// attach 2D texture to this FBO
|
// attach 2D texture to this FBO
|
||||||
oglFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_texture->getId(), 0);
|
glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_texture->getId(), 0);
|
||||||
|
|
||||||
GLenum status = oglCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
|
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
|
||||||
switch(status) {
|
switch(status) {
|
||||||
case GL_FRAMEBUFFER_COMPLETE_EXT:
|
case GL_FRAMEBUFFER_COMPLETE_EXT:
|
||||||
//ok
|
//ok
|
||||||
|
@ -72,7 +54,7 @@ FrameBuffer::FrameBuffer(int width, int height)
|
||||||
}
|
}
|
||||||
|
|
||||||
// restore back buffer
|
// restore back buffer
|
||||||
oglBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
|
||||||
glDrawBuffer(GL_BACK);
|
glDrawBuffer(GL_BACK);
|
||||||
glReadBuffer(GL_BACK);
|
glReadBuffer(GL_BACK);
|
||||||
} else {
|
} else {
|
||||||
|
@ -87,14 +69,14 @@ FrameBuffer::FrameBuffer(int width, int height)
|
||||||
FrameBuffer::~FrameBuffer()
|
FrameBuffer::~FrameBuffer()
|
||||||
{
|
{
|
||||||
if(m_fbo)
|
if(m_fbo)
|
||||||
oglDeleteFramebuffers(1, &m_fbo);
|
glDeleteFramebuffers(1, &m_fbo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrameBuffer::bind()
|
void FrameBuffer::bind()
|
||||||
{
|
{
|
||||||
if(!m_fallbackOldImp) {
|
if(!m_fallbackOldImp) {
|
||||||
// bind framebuffer
|
// bind framebuffer
|
||||||
oglBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fbo);
|
glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fbo);
|
||||||
} else {
|
} else {
|
||||||
int screenWidth = g_graphics.getScreenSize().width();
|
int screenWidth = g_graphics.getScreenSize().width();
|
||||||
int screenHeight = g_graphics.getScreenSize().height();
|
int screenHeight = g_graphics.getScreenSize().height();
|
||||||
|
@ -126,7 +108,7 @@ void FrameBuffer::unbind()
|
||||||
{
|
{
|
||||||
if(!m_fallbackOldImp) {
|
if(!m_fallbackOldImp) {
|
||||||
// bind back buffer again
|
// bind back buffer again
|
||||||
oglBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
|
||||||
glDrawBuffer(GL_BACK);
|
glDrawBuffer(GL_BACK);
|
||||||
glReadBuffer(GL_BACK);
|
glReadBuffer(GL_BACK);
|
||||||
|
|
||||||
|
|
|
@ -31,13 +31,8 @@ public:
|
||||||
FrameBuffer(int width, int height);
|
FrameBuffer(int width, int height);
|
||||||
virtual ~FrameBuffer();
|
virtual ~FrameBuffer();
|
||||||
|
|
||||||
/// Binds the framebuffer, by switching render buffer to itself, everything rendered will be draw on it
|
|
||||||
void bind();
|
void bind();
|
||||||
|
|
||||||
/// Unbinds the framebuffer (switch render buffer to back buffer again)
|
|
||||||
void unbind();
|
void unbind();
|
||||||
|
|
||||||
/// Draws framebuffer texture
|
|
||||||
void draw(const Rect& screenCoords, const Rect& framebufferCoords = Rect());
|
void draw(const Rect& screenCoords, const Rect& framebufferCoords = Rect());
|
||||||
|
|
||||||
TexturePtr getTexture() { return m_texture; }
|
TexturePtr getTexture() { return m_texture; }
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/otclient>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef GLUTIL_H
|
||||||
|
#define GLUTIL_H
|
||||||
|
|
||||||
|
#define GL_GLEXT_PROTOTYPES
|
||||||
|
|
||||||
|
#ifndef OPENGL_ES2
|
||||||
|
#include <GL/gl.h>
|
||||||
|
#include <GL/glext.h>
|
||||||
|
#else
|
||||||
|
#include <GLES2/gl2.h>
|
||||||
|
#include <GLES2/gl2ext.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -25,9 +25,6 @@
|
||||||
#include <framework/graphics/graphics.h>
|
#include <framework/graphics/graphics.h>
|
||||||
#include <framework/graphics/texture.h>
|
#include <framework/graphics/texture.h>
|
||||||
|
|
||||||
#include <GL/gl.h>
|
|
||||||
#include <GL/glext.h>
|
|
||||||
|
|
||||||
Graphics g_graphics;
|
Graphics g_graphics;
|
||||||
|
|
||||||
void Graphics::init()
|
void Graphics::init()
|
||||||
|
|
|
@ -23,9 +23,6 @@
|
||||||
#include "texture.h"
|
#include "texture.h"
|
||||||
#include "graphics.h"
|
#include "graphics.h"
|
||||||
|
|
||||||
#include <GL/gl.h>
|
|
||||||
#include <GL/glext.h>
|
|
||||||
|
|
||||||
Texture::Texture()
|
Texture::Texture()
|
||||||
{
|
{
|
||||||
m_textureId = 0;
|
m_textureId = 0;
|
||||||
|
@ -61,7 +58,7 @@ uint Texture::internalLoadGLTexture(uchar *pixels, int channels, int width, int
|
||||||
logError("loading texture with size ", width, "x", height, " failed, "
|
logError("loading texture with size ", width, "x", height, " failed, "
|
||||||
"the maximum size allowed by the graphics card is ", maxTexSize, "x", maxTexSize, ",",
|
"the maximum size allowed by the graphics card is ", maxTexSize, "x", maxTexSize, ",",
|
||||||
"to prevent crashes the texture will be displayed as a blank texture");
|
"to prevent crashes the texture will be displayed as a blank texture");
|
||||||
//TODO: a workground, like bilinear scaling the texture
|
//TODO: make a workaround, could be bilinear scaling the texture
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,17 +20,18 @@
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "luainterface.h"
|
#include <framework/luascript/luainterface.h>
|
||||||
|
#include <framework/application.h>
|
||||||
#include <framework/graphics/fontmanager.h>
|
#include <framework/graphics/fontmanager.h>
|
||||||
#include <framework/ui/ui.h>
|
#include <framework/ui/ui.h>
|
||||||
#include <framework/net/protocol.h>
|
#include <framework/net/protocol.h>
|
||||||
#include <framework/core/eventdispatcher.h>
|
#include <framework/core/eventdispatcher.h>
|
||||||
#include <framework/core/configmanager.h>
|
#include <framework/core/configmanager.h>
|
||||||
#include <framework/platform/platform.h>
|
|
||||||
#include <framework/otml/otml.h>
|
#include <framework/otml/otml.h>
|
||||||
#include <framework/graphics/graphics.h>
|
#include <framework/graphics/graphics.h>
|
||||||
|
#include <framework/platform/platformwindow.h>
|
||||||
|
|
||||||
void LuaInterface::registerFunctions()
|
void Application::registerLuaFunctions()
|
||||||
{
|
{
|
||||||
// UIWidget
|
// UIWidget
|
||||||
g_lua.registerClass<UIWidget>();
|
g_lua.registerClass<UIWidget>();
|
||||||
|
@ -152,10 +153,21 @@ void LuaInterface::registerFunctions()
|
||||||
g_lua.registerClass<Protocol>();
|
g_lua.registerClass<Protocol>();
|
||||||
|
|
||||||
// ConfigManager
|
// ConfigManager
|
||||||
g_lua.registerClass<ConfigManager>();
|
g_lua.registerStaticClass("g_configs");
|
||||||
g_lua.bindClassStaticFunction<ConfigManager>("set", std::bind(&ConfigManager::set, &g_configs, _1, _2));
|
g_lua.bindClassStaticFunction("g_configs", "set", std::bind(&ConfigManager::set, &g_configs, _1, _2));
|
||||||
g_lua.bindClassStaticFunction<ConfigManager>("get", std::bind(&ConfigManager::get, &g_configs, _1));
|
g_lua.bindClassStaticFunction("g_configs", "get", std::bind(&ConfigManager::get, &g_configs, _1));
|
||||||
g_lua.bindClassStaticFunction<ConfigManager>("exists", std::bind(&ConfigManager::exists, &g_configs, _1));
|
g_lua.bindClassStaticFunction("g_configs", "exists", std::bind(&ConfigManager::exists, &g_configs, _1));
|
||||||
|
|
||||||
|
g_lua.registerStaticClass("g_window");
|
||||||
|
g_lua.bindClassStaticFunction("g_window", "show", std::bind(&PlatformWindow::show, &g_window));
|
||||||
|
g_lua.bindClassStaticFunction("g_window", "hide", std::bind(&PlatformWindow::hide, &g_window));
|
||||||
|
g_lua.bindClassStaticFunction("g_window", "move", std::bind(&PlatformWindow::move, &g_window, _1));
|
||||||
|
g_lua.bindClassStaticFunction("g_window", "resize", std::bind(&PlatformWindow::resize, &g_window, _1));
|
||||||
|
g_lua.bindClassStaticFunction("g_window", "setVerticalSync", std::bind(&PlatformWindow::setVerticalSync, &g_window, _1));
|
||||||
|
g_lua.bindClassStaticFunction("g_window", "setTitle", std::bind(&PlatformWindow::setTitle, &g_window, _1));
|
||||||
|
g_lua.bindClassStaticFunction("g_window", "setIcon", std::bind(&PlatformWindow::setIcon, &g_window, _1));
|
||||||
|
g_lua.bindClassStaticFunction("g_window", "getMousePos", std::bind(&PlatformWindow::getMousePos, &g_window));
|
||||||
|
g_lua.bindClassStaticFunction("g_window", "getSize", std::bind(&PlatformWindow::getSize, &g_window));
|
||||||
|
|
||||||
// Logger
|
// Logger
|
||||||
g_lua.registerClass<Logger>();
|
g_lua.registerClass<Logger>();
|
||||||
|
@ -171,7 +183,4 @@ void LuaInterface::registerFunctions()
|
||||||
g_lua.bindGlobalFunction("getRootWidget", std::bind(&UIManager::getRootWidget, &g_ui));
|
g_lua.bindGlobalFunction("getRootWidget", std::bind(&UIManager::getRootWidget, &g_ui));
|
||||||
g_lua.bindGlobalFunction("addEvent", std::bind(&EventDispatcher::addEvent, &g_dispatcher, _1, false));
|
g_lua.bindGlobalFunction("addEvent", std::bind(&EventDispatcher::addEvent, &g_dispatcher, _1, false));
|
||||||
g_lua.bindGlobalFunction("scheduleEvent", std::bind(&EventDispatcher::scheduleEvent, &g_dispatcher, _1, _2));
|
g_lua.bindGlobalFunction("scheduleEvent", std::bind(&EventDispatcher::scheduleEvent, &g_dispatcher, _1, _2));
|
||||||
g_lua.bindGlobalFunction("getMouseCursorPos", std::bind(&Platform::getMouseCursorPos, &g_platform));
|
|
||||||
g_lua.bindGlobalFunction("setVerticalSync", std::bind(&Platform::setVerticalSync, &g_platform, _1));
|
|
||||||
g_lua.bindGlobalFunction("getScreenSize", std::bind(&Graphics::getScreenSize, &g_graphics));
|
|
||||||
}
|
}
|
|
@ -47,9 +47,6 @@ void LuaInterface::init()
|
||||||
// register LuaObject, the base of all other objects
|
// register LuaObject, the base of all other objects
|
||||||
registerClass<LuaObject>();
|
registerClass<LuaObject>();
|
||||||
bindClassMemberGetField<LuaObject>("use_count", &LuaObject::getUseCount);
|
bindClassMemberGetField<LuaObject>("use_count", &LuaObject::getUseCount);
|
||||||
|
|
||||||
// register the real script stuff
|
|
||||||
registerFunctions();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LuaInterface::terminate()
|
void LuaInterface::terminate()
|
||||||
|
@ -58,6 +55,14 @@ void LuaInterface::terminate()
|
||||||
closeLuaState();
|
closeLuaState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LuaInterface::registerStaticClass(const std::string& className)
|
||||||
|
{
|
||||||
|
newTable();
|
||||||
|
pushValue();
|
||||||
|
setGlobal(className);
|
||||||
|
pop();
|
||||||
|
}
|
||||||
|
|
||||||
void LuaInterface::registerClass(const std::string& className, const std::string& baseClass)
|
void LuaInterface::registerClass(const std::string& className, const std::string& baseClass)
|
||||||
{
|
{
|
||||||
// creates the class table (that it's also the class methods table)
|
// creates the class table (that it's also the class methods table)
|
||||||
|
|
|
@ -42,6 +42,7 @@ public:
|
||||||
void registerFunctions();
|
void registerFunctions();
|
||||||
|
|
||||||
// functions that will register all script stuff in lua global environment
|
// functions that will register all script stuff in lua global environment
|
||||||
|
void registerStaticClass(const std::string& className);
|
||||||
void registerClass(const std::string& className, const std::string& baseClass = "LuaObject");
|
void registerClass(const std::string& className, const std::string& baseClass = "LuaObject");
|
||||||
|
|
||||||
void registerClassStaticFunction(const std::string& className,
|
void registerClassStaticFunction(const std::string& className,
|
||||||
|
@ -86,18 +87,28 @@ public:
|
||||||
// methods for binding functions
|
// methods for binding functions
|
||||||
template<class C, typename F>
|
template<class C, typename F>
|
||||||
void bindClassStaticFunction(const std::string& functionName, const F& function);
|
void bindClassStaticFunction(const std::string& functionName, const F& function);
|
||||||
|
template<typename F>
|
||||||
|
void bindClassStaticFunction(const std::string& className, const std::string& functionName, const F& function);
|
||||||
|
|
||||||
template<class C, typename F>
|
template<class C, typename F>
|
||||||
void bindClassMemberFunction(const std::string& functionName, F C::*function);
|
void bindClassMemberFunction(const std::string& functionName, F C::*function);
|
||||||
|
template<class C, typename F>
|
||||||
|
void bindClassMemberFunction(const std::string& className, const std::string& functionName, F C::*function);
|
||||||
|
|
||||||
template<class C, typename F1, typename F2>
|
template<class C, typename F1, typename F2>
|
||||||
void bindClassMemberField(const std::string& fieldName, F1 C::*getFunction, F2 C::*setFunction);
|
void bindClassMemberField(const std::string& fieldName, F1 C::*getFunction, F2 C::*setFunction);
|
||||||
|
template<class C, typename F1, typename F2>
|
||||||
|
void bindClassMemberField(const std::string& className, const std::string& fieldName, F1 C::*getFunction, F2 C::*setFunction);
|
||||||
|
|
||||||
template<class C, typename F>
|
template<class C, typename F>
|
||||||
void bindClassMemberGetField(const std::string& fieldName, F C::*getFunction);
|
void bindClassMemberGetField(const std::string& fieldName, F C::*getFunction);
|
||||||
|
template<class C, typename F>
|
||||||
|
void bindClassMemberGetField(const std::string& className, const std::string& fieldName, F C::*getFunction);
|
||||||
|
|
||||||
template<class C, typename F>
|
template<class C, typename F>
|
||||||
void bindClassMemberSetField(const std::string& fieldName, F C::*setFunction);
|
void bindClassMemberSetField(const std::string& fieldName, F C::*setFunction);
|
||||||
|
template<class C, typename F>
|
||||||
|
void bindClassMemberSetField(const std::string& className, const std::string& fieldName, F C::*setFunction);
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
void bindGlobalFunction(const std::string& functionName, const F& function);
|
void bindGlobalFunction(const std::string& functionName, const F& function);
|
||||||
|
@ -314,31 +325,45 @@ template<class C, typename F>
|
||||||
void LuaInterface::bindClassStaticFunction(const std::string& functionName, const F& function) {
|
void LuaInterface::bindClassStaticFunction(const std::string& functionName, const F& function) {
|
||||||
registerClassStaticFunction<C>(functionName, luabinder::bind_fun(function));
|
registerClassStaticFunction<C>(functionName, luabinder::bind_fun(function));
|
||||||
}
|
}
|
||||||
|
template<typename F>
|
||||||
|
void LuaInterface::bindClassStaticFunction(const std::string& className, const std::string& functionName, const F& function) {
|
||||||
|
registerClassStaticFunction(className, functionName, luabinder::bind_fun(function));
|
||||||
|
}
|
||||||
|
|
||||||
template<class C, typename F>
|
template<class C, typename F>
|
||||||
void LuaInterface::bindClassMemberFunction(const std::string& functionName, F C::*function) {
|
void LuaInterface::bindClassMemberFunction(const std::string& functionName, F C::*function) {
|
||||||
registerClassMemberFunction<C>(functionName, luabinder::bind_mem_fun(function));
|
registerClassMemberFunction<C>(functionName, luabinder::bind_mem_fun(function));
|
||||||
}
|
}
|
||||||
|
template<class C, typename F>
|
||||||
|
void LuaInterface::bindClassMemberFunction(const std::string& className, const std::string& functionName, F C::*function) {
|
||||||
|
registerClassMemberFunction(className, functionName, luabinder::bind_mem_fun(function));
|
||||||
|
}
|
||||||
|
|
||||||
template<class C, typename F1, typename F2>
|
template<class C, typename F1, typename F2>
|
||||||
void LuaInterface::bindClassMemberField(const std::string& fieldName, F1 C::*getFunction, F2 C::*setFunction) {
|
void LuaInterface::bindClassMemberField(const std::string& fieldName, F1 C::*getFunction, F2 C::*setFunction) {
|
||||||
registerClassMemberField<C>(fieldName,
|
registerClassMemberField<C>(fieldName, luabinder::bind_mem_fun(getFunction), luabinder::bind_mem_fun(setFunction));
|
||||||
luabinder::bind_mem_fun(getFunction),
|
}
|
||||||
luabinder::bind_mem_fun(setFunction));
|
template<class C, typename F1, typename F2>
|
||||||
|
void LuaInterface::bindClassMemberField(const std::string& className, const std::string& fieldName, F1 C::*getFunction, F2 C::*setFunction) {
|
||||||
|
registerClassMemberField(className, fieldName, luabinder::bind_mem_fun(getFunction), luabinder::bind_mem_fun(setFunction));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class C, typename F>
|
template<class C, typename F>
|
||||||
void LuaInterface::bindClassMemberGetField(const std::string& fieldName, F C::*getFunction) {
|
void LuaInterface::bindClassMemberGetField(const std::string& fieldName, F C::*getFunction) {
|
||||||
registerClassMemberField<C>(fieldName,
|
registerClassMemberField<C>(fieldName, luabinder::bind_mem_fun(getFunction), LuaCppFunction());
|
||||||
luabinder::bind_mem_fun(getFunction),
|
}
|
||||||
LuaCppFunction());
|
template<class C, typename F>
|
||||||
|
void LuaInterface::bindClassMemberGetField(const std::string& className, const std::string& fieldName, F C::*getFunction) {
|
||||||
|
registerClassMemberField(className, fieldName, luabinder::bind_mem_fun(getFunction), LuaCppFunction());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class C, typename F>
|
template<class C, typename F>
|
||||||
void LuaInterface::bindClassMemberSetField(const std::string& fieldName, F C::*setFunction) {
|
void LuaInterface::bindClassMemberSetField(const std::string& fieldName, F C::*setFunction) {
|
||||||
registerClassMemberField<C>(fieldName,
|
registerClassMemberField<C>(fieldName, LuaCppFunction(), luabinder::bind_mem_fun(setFunction));
|
||||||
LuaCppFunction(),
|
}
|
||||||
luabinder::bind_mem_fun(setFunction));
|
template<class C, typename F>
|
||||||
|
void LuaInterface::bindClassMemberSetField(const std::string& className, const std::string& fieldName, F C::*setFunction) {
|
||||||
|
registerClassMemberField(className, fieldName, LuaCppFunction(), luabinder::bind_mem_fun(setFunction));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/otclient>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HANDLE_EXCEPTIONS
|
||||||
|
|
||||||
|
#include <csignal>
|
||||||
|
#include <execinfo.h>
|
||||||
|
|
||||||
|
#define MAX_BACKTRACE_DEPTH 128
|
||||||
|
#define DEMANGLE_BACKTRACE_SYMBOLS
|
||||||
|
|
||||||
|
void crashHandler(int signum, siginfo_t* info, void* secret)
|
||||||
|
{
|
||||||
|
logError("Application crashed");
|
||||||
|
|
||||||
|
ucontext_t context = *(ucontext_t*)secret;
|
||||||
|
time_t tnow;
|
||||||
|
char fileName[128];
|
||||||
|
time(&tnow);
|
||||||
|
tm *ts = localtime(&tnow);
|
||||||
|
strftime(fileName, 128, (x11.appName + "-crash_-%d-%m-%Y_%H:%M:%S.txt").c_str(), ts);
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
ss.flags(std::ios::hex | std::ios::showbase);
|
||||||
|
#if __WORDSIZE == 32
|
||||||
|
ss <<
|
||||||
|
ss << " at eip = " << context.uc_mcontext.gregs[REG_EIP] << std::endl;
|
||||||
|
ss << " eax = " << context.uc_mcontext.gregs[REG_EAX] << std::endl;
|
||||||
|
ss << " ebx = " << context.uc_mcontext.gregs[REG_EBX] << std::endl;
|
||||||
|
ss << " ecx = " << context.uc_mcontext.gregs[REG_ECX] << std::endl;
|
||||||
|
ss << " edx = " << context.uc_mcontext.gregs[REG_EDX] << std::endl;
|
||||||
|
ss << " esi = " << context.uc_mcontext.gregs[REG_ESI] << std::endl;
|
||||||
|
ss << " edi = " << context.uc_mcontext.gregs[REG_EDI] << std::endl;
|
||||||
|
ss << " ebp = " << context.uc_mcontext.gregs[REG_EBP] << std::endl;
|
||||||
|
ss << " esp = " << context.uc_mcontext.gregs[REG_ESP] << std::endl;
|
||||||
|
ss << " efl = " << context.uc_mcontext.gregs[REG_EFL] << std::endl;
|
||||||
|
#else // 64-bit
|
||||||
|
ss << " at rip = " << context.uc_mcontext.gregs[REG_RIP] << std::endl;
|
||||||
|
ss << " rax = " << context.uc_mcontext.gregs[REG_RAX] << std::endl;
|
||||||
|
ss << " rbx = " << context.uc_mcontext.gregs[REG_RBX] << std::endl;
|
||||||
|
ss << " rcx = " << context.uc_mcontext.gregs[REG_RCX] << std::endl;
|
||||||
|
ss << " rdx = " << context.uc_mcontext.gregs[REG_RDX] << std::endl;
|
||||||
|
ss << " rsi = " << context.uc_mcontext.gregs[REG_RSI] << std::endl;
|
||||||
|
ss << " rdi = " << context.uc_mcontext.gregs[REG_RDI] << std::endl;
|
||||||
|
ss << " rbp = " << context.uc_mcontext.gregs[REG_RBP] << std::endl;
|
||||||
|
ss << " rsp = " << context.uc_mcontext.gregs[REG_RSP] << std::endl;
|
||||||
|
ss << " efl = " << context.uc_mcontext.gregs[REG_EFL] << std::endl;
|
||||||
|
#endif
|
||||||
|
ss << std::endl;
|
||||||
|
ss.flags(std::ios::dec);
|
||||||
|
ss << " backtrace:" << std::endl;
|
||||||
|
|
||||||
|
void* buffer[MAX_BACKTRACE_DEPTH];
|
||||||
|
int numLevels = backtrace(buffer, MAX_BACKTRACE_DEPTH);
|
||||||
|
char **tracebackBuffer = backtrace_symbols(buffer, numLevels);
|
||||||
|
if(tracebackBuffer) {
|
||||||
|
for(int i = 2; i < numLevels; i++) {
|
||||||
|
std::string line = tracebackBuffer[i];
|
||||||
|
if(line.find("__libc_start_main") != std::string::npos)
|
||||||
|
break;
|
||||||
|
#ifdef DEMANGLE_BACKTRACE_SYMBOLS
|
||||||
|
std::size_t demanglePos = line.find("(_Z");
|
||||||
|
if(demanglePos != std::string::npos) {
|
||||||
|
demanglePos++;
|
||||||
|
int len = std::min(line.find_first_of("+", demanglePos), line.find_first_of(")", demanglePos)) - demanglePos;
|
||||||
|
std::string funcName = line.substr(demanglePos, len);
|
||||||
|
line.replace(demanglePos, len, Fw::demangleName(funcName.c_str()));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
ss << " " << i-1 << ": " << line << std::endl;
|
||||||
|
}
|
||||||
|
free(tracebackBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
logInfo(ss.str());
|
||||||
|
|
||||||
|
std::ofstream out(fileName);
|
||||||
|
out << ss.str();
|
||||||
|
out.close();
|
||||||
|
logInfo("Crash report saved to file ", fileName);
|
||||||
|
|
||||||
|
signal(SIGILL, SIG_DFL);
|
||||||
|
signal(SIGSEGV, SIG_DFL);
|
||||||
|
signal(SIGFPE, SIG_DFL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HANDLE_EXCEPTIONS
|
||||||
|
struct sigaction sa;
|
||||||
|
sa.sa_sigaction = &crashHandler;
|
||||||
|
sigemptyset (&sa.sa_mask);
|
||||||
|
sa.sa_flags = SA_RESTART | SA_SIGINFO;
|
||||||
|
|
||||||
|
sigaction(SIGILL, &sa, NULL); // illegal instruction
|
||||||
|
sigaction(SIGSEGV, &sa, NULL); // segmentation fault
|
||||||
|
sigaction(SIGFPE, &sa, NULL); // floating-point exception
|
||||||
|
#endif
|
|
@ -1,86 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/otclient>
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef PLATFORM_H
|
|
||||||
#define PLATFORM_H
|
|
||||||
|
|
||||||
#include <framework/global.h>
|
|
||||||
|
|
||||||
class PlatformListener;
|
|
||||||
|
|
||||||
class Platform
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void init(PlatformListener* platformListener, const char* appName);
|
|
||||||
void terminate();
|
|
||||||
|
|
||||||
/// Poll platform input/window events
|
|
||||||
void poll();
|
|
||||||
|
|
||||||
/// Sleep in current thread
|
|
||||||
void sleep(ulong ms);
|
|
||||||
|
|
||||||
bool createWindow(int x, int y, int width, int height, int minWidth, int minHeight, bool maximized);
|
|
||||||
void setWindowIcon(const std::string& pngIcon);
|
|
||||||
void destroyWindow();
|
|
||||||
void showWindow();
|
|
||||||
void hideWindow();
|
|
||||||
void setWindowTitle(const char* title);
|
|
||||||
bool isWindowFocused();
|
|
||||||
bool isWindowVisible();
|
|
||||||
int getWindowX();
|
|
||||||
int getWindowY();
|
|
||||||
int getWindowWidth();
|
|
||||||
int getWindowHeight();
|
|
||||||
bool isWindowMaximized();
|
|
||||||
|
|
||||||
int getDisplayHeight();
|
|
||||||
int getDisplayWidth();
|
|
||||||
|
|
||||||
/// Get GL extension function address
|
|
||||||
void* getExtensionProcAddress(const char* ext);
|
|
||||||
/// Check if GLX/WGL extension is supported
|
|
||||||
bool isExtensionSupported(const char* ext);
|
|
||||||
|
|
||||||
/// Get text from Ctrl+c
|
|
||||||
const char* getClipboardText();
|
|
||||||
/// Set text for Ctrl+v
|
|
||||||
void setClipboardText(const char* text);
|
|
||||||
|
|
||||||
void hideMouseCursor();
|
|
||||||
void showMouseCursor();
|
|
||||||
Point getMouseCursorPos();
|
|
||||||
|
|
||||||
/// Enable or disable vertical synchronization
|
|
||||||
void setVerticalSync(bool enable);
|
|
||||||
/// Swap GL buffers
|
|
||||||
void swapBuffers();
|
|
||||||
|
|
||||||
/// Get the app user directory, the place to save files configurations files
|
|
||||||
std::string getAppUserDir();
|
|
||||||
|
|
||||||
void displayFatalError(const std::string& message);
|
|
||||||
};
|
|
||||||
|
|
||||||
extern Platform g_platform;
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,63 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/otclient>
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef INPUTEVENT_H
|
|
||||||
#define INPUTEVENT_H
|
|
||||||
|
|
||||||
#include <framework/global.h>
|
|
||||||
|
|
||||||
enum PlatformEventType {
|
|
||||||
EventNone = 0,
|
|
||||||
EventMouseAction = 1,
|
|
||||||
EventKeyboardAction = 2,
|
|
||||||
EventDown = 4,
|
|
||||||
EventUp = 8,
|
|
||||||
EventMouseWheel = 16,
|
|
||||||
EventMouseLeftButton = 32,
|
|
||||||
EventMouseRightButton = 64,
|
|
||||||
EventMouseMidButton = 128,
|
|
||||||
EventKeyDown = EventKeyboardAction | EventDown,
|
|
||||||
EventKeyUp = EventKeyboardAction | EventUp,
|
|
||||||
EventMouseMove = EventMouseAction | 512,
|
|
||||||
EventMouseLeftButtonDown = EventMouseAction | EventMouseLeftButton | EventDown,
|
|
||||||
EventMouseLeftButtonUp = EventMouseAction | EventMouseLeftButton | EventUp,
|
|
||||||
EventMouseMiddleButtonDown = EventMouseAction | EventMouseMidButton | EventDown,
|
|
||||||
EventMouseMiddleButtonUp = EventMouseAction | EventMouseMidButton | EventUp,
|
|
||||||
EventMouseRightButtonDown = EventMouseAction | EventMouseRightButton | EventDown,
|
|
||||||
EventMouseRightButtonUp = EventMouseAction | EventMouseRightButton | EventUp,
|
|
||||||
EventMouseWheelUp = EventMouseAction | EventMouseWheel | EventUp,
|
|
||||||
EventMouseWheelDown = EventMouseAction | EventMouseWheel | EventDown
|
|
||||||
};
|
|
||||||
|
|
||||||
//TODO: rework platform events, make more compatible with UI events
|
|
||||||
struct PlatformEvent {
|
|
||||||
int type;
|
|
||||||
Point mousePos;
|
|
||||||
Point mouseMoved;
|
|
||||||
char keychar;
|
|
||||||
Fw::Key keycode;
|
|
||||||
bool ctrl;
|
|
||||||
bool shift;
|
|
||||||
bool alt;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -20,5 +20,14 @@
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "engine.h"
|
#include "platformwindow.h"
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include "win32window.h"
|
||||||
|
WIN32Window window;
|
||||||
|
#else
|
||||||
|
#include "x11window.h"
|
||||||
|
X11Window window;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PlatformWindow& g_window = window;
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/otclient>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PLATFORMWINDOW_H
|
||||||
|
#define PLATFORMWINDOW_H
|
||||||
|
|
||||||
|
#include <framework/global.h>
|
||||||
|
#include <framework/core/inputevent.h>
|
||||||
|
|
||||||
|
class PlatformWindow
|
||||||
|
{
|
||||||
|
typedef std::function<void(const Size&)> OnResizeCallback;
|
||||||
|
typedef std::function<void(const InputEvent&)> OnInputEventCallback;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void init() = 0;
|
||||||
|
virtual void terminate() = 0;
|
||||||
|
|
||||||
|
virtual void move(const Point& pos) = 0;
|
||||||
|
virtual void resize(const Size& size) = 0;
|
||||||
|
virtual void show() = 0;
|
||||||
|
virtual void hide() = 0;
|
||||||
|
virtual void maximize() = 0;
|
||||||
|
virtual void poll() = 0;
|
||||||
|
virtual void swapBuffers() = 0;
|
||||||
|
virtual void showMouse() = 0;
|
||||||
|
virtual void hideMouse() = 0;
|
||||||
|
|
||||||
|
virtual void setTitle(const std::string& title) = 0;
|
||||||
|
virtual void setMinimumSize(const Size& minimumSize) = 0;
|
||||||
|
virtual void setFullscreen(bool fullscreen) = 0;
|
||||||
|
virtual void setVerticalSync(bool enable) = 0;
|
||||||
|
virtual void setIcon(const std::string& iconFile) = 0;
|
||||||
|
virtual void setClipboardText(const std::string& text) = 0;
|
||||||
|
|
||||||
|
virtual Size getDisplaySize() = 0;
|
||||||
|
virtual std::string getClipboardText() = 0;
|
||||||
|
|
||||||
|
int getDisplayWidth() { return getDisplaySize().width(); }
|
||||||
|
int getDisplayHeight() { return getDisplaySize().width(); }
|
||||||
|
|
||||||
|
Size getSize() { return m_size; }
|
||||||
|
int getWidth() { return m_size.width(); }
|
||||||
|
int getHeight() { return m_size.height(); }
|
||||||
|
Point getPos() { return m_pos; }
|
||||||
|
int getX() { return m_pos.x; }
|
||||||
|
int getY() { return m_pos.y; }
|
||||||
|
Point getMousePos() { return m_inputEvent.mousePos; }
|
||||||
|
int getKeyboardModifiers() { return m_inputEvent.keyboardModifiers; }
|
||||||
|
|
||||||
|
bool isVisible() { return m_visible; }
|
||||||
|
bool isFullscreen() { return m_fullscreen; }
|
||||||
|
bool hasFocus() { return m_focused; }
|
||||||
|
|
||||||
|
void setOnClose(const SimpleCallback& onClose) { m_onClose = onClose; }
|
||||||
|
void setOnResize(const OnResizeCallback& onResize) { m_onResize = onResize; }
|
||||||
|
void setOnInputEvent(const OnInputEventCallback& onInputEvent) { m_onInputEvent = onInputEvent; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Size m_size;
|
||||||
|
Point m_pos;
|
||||||
|
InputEvent m_inputEvent;
|
||||||
|
|
||||||
|
Boolean<false> m_created;
|
||||||
|
Boolean<false> m_visible;
|
||||||
|
Boolean<false> m_focused;
|
||||||
|
Boolean<false> m_fullscreen;
|
||||||
|
|
||||||
|
SimpleCallback m_onClose;
|
||||||
|
OnResizeCallback m_onResize;
|
||||||
|
OnInputEventCallback m_onInputEvent;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern PlatformWindow& g_window;
|
||||||
|
|
||||||
|
#endif
|
|
@ -20,6 +20,10 @@
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// disabled for a while
|
||||||
|
#if 0
|
||||||
|
#include "win32window.h"
|
||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "platformlistener.h"
|
#include "platformlistener.h"
|
||||||
|
|
||||||
|
@ -789,3 +793,4 @@ void Platform::displayFatalError(const std::string& message)
|
||||||
MessageBoxA(NULL, message.c_str(), "Fatal Error", MB_OK | MB_ICONERROR);
|
MessageBoxA(NULL, message.c_str(), "Fatal Error", MB_OK | MB_ICONERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -20,14 +20,14 @@
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef ENGINE_H
|
#ifndef WIN32WINDOW_H
|
||||||
#define ENGINE_H
|
#define WIN32WINDOW_H
|
||||||
|
|
||||||
#include "declarations.h"
|
#include "platformwindow.h"
|
||||||
|
|
||||||
class Engine
|
class WIN32Window : public PlatformWindow
|
||||||
{
|
{
|
||||||
|
//TODO
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,989 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/otclient>
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "platform.h"
|
|
||||||
#include "platformlistener.h"
|
|
||||||
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include <physfs.h>
|
|
||||||
|
|
||||||
#include <GL/glx.h>
|
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#include <X11/Xatom.h>
|
|
||||||
|
|
||||||
#include <framework/thirdparty/apngloader.h>
|
|
||||||
#include <framework/core/resourcemanager.h>
|
|
||||||
|
|
||||||
struct X11PlatformPrivate {
|
|
||||||
Display *display;
|
|
||||||
XVisualInfo *visual;
|
|
||||||
GLXContext glxContext;
|
|
||||||
XIM xim;
|
|
||||||
XIC xic;
|
|
||||||
Colormap colormap;
|
|
||||||
Window window;
|
|
||||||
Cursor cursor;
|
|
||||||
Atom atomDeleteWindow;
|
|
||||||
Atom atomClipboard;
|
|
||||||
Atom atomTargets;
|
|
||||||
Atom atomText;
|
|
||||||
Atom atomCompoundText;
|
|
||||||
Atom atomUTF8String;
|
|
||||||
Atom atomWindowState;
|
|
||||||
Atom atomWindowMaximizedVert;
|
|
||||||
Atom atomWindowMaximizedHorz;
|
|
||||||
bool visible;
|
|
||||||
bool focused;
|
|
||||||
bool maximizeOnFirstShow;
|
|
||||||
std::string appName;
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
int x;
|
|
||||||
int y;
|
|
||||||
int lastTicks;
|
|
||||||
std::string clipboardText;
|
|
||||||
std::map<int, Fw::Key> keyMap;
|
|
||||||
PlatformListener* listener;
|
|
||||||
PlatformEvent platformEvent;
|
|
||||||
} x11;
|
|
||||||
|
|
||||||
Platform g_platform;
|
|
||||||
|
|
||||||
#ifdef HANDLE_EXCEPTIONS
|
|
||||||
|
|
||||||
#include <csignal>
|
|
||||||
#include <execinfo.h>
|
|
||||||
|
|
||||||
#define MAX_BACKTRACE_DEPTH 128
|
|
||||||
#define DEMANGLE_BACKTRACE_SYMBOLS
|
|
||||||
|
|
||||||
void crashHandler(int signum, siginfo_t* info, void* secret)
|
|
||||||
{
|
|
||||||
logError("Application crashed");
|
|
||||||
|
|
||||||
ucontext_t context = *(ucontext_t*)secret;
|
|
||||||
time_t tnow;
|
|
||||||
char fileName[128];
|
|
||||||
time(&tnow);
|
|
||||||
tm *ts = localtime(&tnow);
|
|
||||||
strftime(fileName, 128, (x11.appName + "-crash_-%d-%m-%Y_%H:%M:%S.txt").c_str(), ts);
|
|
||||||
|
|
||||||
std::stringstream ss;
|
|
||||||
ss.flags(std::ios::hex | std::ios::showbase);
|
|
||||||
#if __WORDSIZE == 32
|
|
||||||
ss <<
|
|
||||||
ss << " at eip = " << context.uc_mcontext.gregs[REG_EIP] << std::endl;
|
|
||||||
ss << " eax = " << context.uc_mcontext.gregs[REG_EAX] << std::endl;
|
|
||||||
ss << " ebx = " << context.uc_mcontext.gregs[REG_EBX] << std::endl;
|
|
||||||
ss << " ecx = " << context.uc_mcontext.gregs[REG_ECX] << std::endl;
|
|
||||||
ss << " edx = " << context.uc_mcontext.gregs[REG_EDX] << std::endl;
|
|
||||||
ss << " esi = " << context.uc_mcontext.gregs[REG_ESI] << std::endl;
|
|
||||||
ss << " edi = " << context.uc_mcontext.gregs[REG_EDI] << std::endl;
|
|
||||||
ss << " ebp = " << context.uc_mcontext.gregs[REG_EBP] << std::endl;
|
|
||||||
ss << " esp = " << context.uc_mcontext.gregs[REG_ESP] << std::endl;
|
|
||||||
ss << " efl = " << context.uc_mcontext.gregs[REG_EFL] << std::endl;
|
|
||||||
#else // 64-bit
|
|
||||||
ss << " at rip = " << context.uc_mcontext.gregs[REG_RIP] << std::endl;
|
|
||||||
ss << " rax = " << context.uc_mcontext.gregs[REG_RAX] << std::endl;
|
|
||||||
ss << " rbx = " << context.uc_mcontext.gregs[REG_RBX] << std::endl;
|
|
||||||
ss << " rcx = " << context.uc_mcontext.gregs[REG_RCX] << std::endl;
|
|
||||||
ss << " rdx = " << context.uc_mcontext.gregs[REG_RDX] << std::endl;
|
|
||||||
ss << " rsi = " << context.uc_mcontext.gregs[REG_RSI] << std::endl;
|
|
||||||
ss << " rdi = " << context.uc_mcontext.gregs[REG_RDI] << std::endl;
|
|
||||||
ss << " rbp = " << context.uc_mcontext.gregs[REG_RBP] << std::endl;
|
|
||||||
ss << " rsp = " << context.uc_mcontext.gregs[REG_RSP] << std::endl;
|
|
||||||
ss << " efl = " << context.uc_mcontext.gregs[REG_EFL] << std::endl;
|
|
||||||
#endif
|
|
||||||
ss << std::endl;
|
|
||||||
ss.flags(std::ios::dec);
|
|
||||||
ss << " backtrace:" << std::endl;
|
|
||||||
|
|
||||||
void* buffer[MAX_BACKTRACE_DEPTH];
|
|
||||||
int numLevels = backtrace(buffer, MAX_BACKTRACE_DEPTH);
|
|
||||||
char **tracebackBuffer = backtrace_symbols(buffer, numLevels);
|
|
||||||
if(tracebackBuffer) {
|
|
||||||
for(int i = 2; i < numLevels; i++) {
|
|
||||||
std::string line = tracebackBuffer[i];
|
|
||||||
if(line.find("__libc_start_main") != std::string::npos)
|
|
||||||
break;
|
|
||||||
#ifdef DEMANGLE_BACKTRACE_SYMBOLS
|
|
||||||
std::size_t demanglePos = line.find("(_Z");
|
|
||||||
if(demanglePos != std::string::npos) {
|
|
||||||
demanglePos++;
|
|
||||||
int len = std::min(line.find_first_of("+", demanglePos), line.find_first_of(")", demanglePos)) - demanglePos;
|
|
||||||
std::string funcName = line.substr(demanglePos, len);
|
|
||||||
line.replace(demanglePos, len, Fw::demangleName(funcName.c_str()));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
ss << " " << i-1 << ": " << line << std::endl;
|
|
||||||
}
|
|
||||||
free(tracebackBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
logInfo(ss.str());
|
|
||||||
|
|
||||||
std::ofstream out(fileName);
|
|
||||||
out << ss.str();
|
|
||||||
out.close();
|
|
||||||
logInfo("Crash report saved to file ", fileName);
|
|
||||||
|
|
||||||
signal(SIGILL, SIG_DFL);
|
|
||||||
signal(SIGSEGV, SIG_DFL);
|
|
||||||
signal(SIGFPE, SIG_DFL);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void Platform::init(PlatformListener* platformListener, const char *appName)
|
|
||||||
{
|
|
||||||
#ifdef HANDLE_EXCEPTIONS
|
|
||||||
struct sigaction sa;
|
|
||||||
sa.sa_sigaction = &crashHandler;
|
|
||||||
sigemptyset (&sa.sa_mask);
|
|
||||||
sa.sa_flags = SA_RESTART | SA_SIGINFO;
|
|
||||||
|
|
||||||
sigaction(SIGILL, &sa, NULL); // illegal instruction
|
|
||||||
sigaction(SIGSEGV, &sa, NULL); // segmentation fault
|
|
||||||
sigaction(SIGFPE, &sa, NULL); // floating-point exception
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// seend random numbers
|
|
||||||
srand(time(NULL));
|
|
||||||
|
|
||||||
x11.appName = appName;
|
|
||||||
x11.display = NULL;
|
|
||||||
x11.visual = NULL;
|
|
||||||
x11.glxContext = NULL;
|
|
||||||
x11.xim = NULL;
|
|
||||||
x11.xic = NULL;
|
|
||||||
x11.colormap = None;
|
|
||||||
x11.window = None;
|
|
||||||
x11.cursor = None;
|
|
||||||
x11.visible = false;
|
|
||||||
x11.focused = false;
|
|
||||||
x11.width = 0;
|
|
||||||
x11.height = 0;
|
|
||||||
x11.maximizeOnFirstShow = false;
|
|
||||||
x11.listener = platformListener;
|
|
||||||
|
|
||||||
x11.keyMap[XK_Escape] = Fw::KeyEscape;
|
|
||||||
x11.keyMap[XK_Tab] = Fw::KeyTab;
|
|
||||||
x11.keyMap[XK_Return] = Fw::KeyReturn;
|
|
||||||
x11.keyMap[XK_BackSpace] = Fw::KeyBackspace;
|
|
||||||
|
|
||||||
x11.keyMap[XK_Page_Up] = Fw::KeyPageUp;
|
|
||||||
x11.keyMap[XK_Page_Down] = Fw::KeyPageDown;
|
|
||||||
x11.keyMap[XK_Home] = Fw::KeyHome;
|
|
||||||
x11.keyMap[XK_End] = Fw::KeyEnd;
|
|
||||||
x11.keyMap[XK_Insert] = Fw::KeyInsert;
|
|
||||||
x11.keyMap[XK_Delete] = Fw::KeyDelete;
|
|
||||||
|
|
||||||
x11.keyMap[XK_Up] = Fw::KeyUp;
|
|
||||||
x11.keyMap[XK_Down] = Fw::KeyDown;
|
|
||||||
x11.keyMap[XK_Left] = Fw::KeyLeft;
|
|
||||||
x11.keyMap[XK_Right] = Fw::KeyRight;
|
|
||||||
|
|
||||||
x11.keyMap[XK_Num_Lock] = Fw::KeyNumLock;
|
|
||||||
x11.keyMap[XK_Scroll_Lock] = Fw::KeyScrollLock;
|
|
||||||
x11.keyMap[XK_Caps_Lock] = Fw::KeyCapsLock;
|
|
||||||
x11.keyMap[XK_Print] = Fw::KeyPrintScreen;
|
|
||||||
x11.keyMap[XK_Pause] = Fw::KeyPause;
|
|
||||||
|
|
||||||
x11.keyMap[XK_Control_L] = Fw::KeyCtrl;
|
|
||||||
x11.keyMap[XK_Control_R] = Fw::KeyCtrl;
|
|
||||||
x11.keyMap[XK_Shift_R] = Fw::KeyShift;
|
|
||||||
x11.keyMap[XK_Shift_L] = Fw::KeyShift;
|
|
||||||
x11.keyMap[XK_Alt_R] = Fw::KeyAlt;
|
|
||||||
x11.keyMap[XK_Alt_L] = Fw::KeyAltGr;
|
|
||||||
x11.keyMap[XK_Meta_L] = Fw::KeyMeta;
|
|
||||||
x11.keyMap[XK_Meta_R] = Fw::KeyMeta;
|
|
||||||
x11.keyMap[XK_Menu] = Fw::KeyMenu;
|
|
||||||
|
|
||||||
// ascii characters
|
|
||||||
x11.keyMap[XK_space] = Fw::KeySpace;
|
|
||||||
x11.keyMap[XK_exclam] = Fw::KeyExclamation;
|
|
||||||
x11.keyMap[XK_quotedbl] = Fw::KeyQuote;
|
|
||||||
x11.keyMap[XK_numbersign] = Fw::KeyNumberSign;
|
|
||||||
x11.keyMap[XK_dollar] = Fw::KeyDollar;
|
|
||||||
x11.keyMap[XK_percent] = Fw::KeyPercent;
|
|
||||||
x11.keyMap[XK_ampersand] = Fw::KeyAmpersand;
|
|
||||||
x11.keyMap[XK_apostrophe] = Fw::KeyApostrophe;
|
|
||||||
x11.keyMap[XK_parenleft] = Fw::KeyLeftParen;
|
|
||||||
x11.keyMap[XK_parenright] = Fw::KeyRightParen;
|
|
||||||
x11.keyMap[XK_asterisk] = Fw::KeyAsterisk;
|
|
||||||
x11.keyMap[XK_plus] = Fw::KeyPlus;
|
|
||||||
x11.keyMap[XK_comma] = Fw::KeyComma;
|
|
||||||
x11.keyMap[XK_minus] = Fw::KeyMinus;
|
|
||||||
x11.keyMap[XK_period] = Fw::KeyPeriod;
|
|
||||||
x11.keyMap[XK_slash] = Fw::KeySlash;
|
|
||||||
x11.keyMap[XK_1] = Fw::Key1;
|
|
||||||
x11.keyMap[XK_2] = Fw::Key2;
|
|
||||||
x11.keyMap[XK_3] = Fw::Key3;
|
|
||||||
x11.keyMap[XK_4] = Fw::Key4;
|
|
||||||
x11.keyMap[XK_5] = Fw::Key5;
|
|
||||||
x11.keyMap[XK_6] = Fw::Key6;
|
|
||||||
x11.keyMap[XK_7] = Fw::Key7;
|
|
||||||
x11.keyMap[XK_8] = Fw::Key8;
|
|
||||||
x11.keyMap[XK_9] = Fw::Key9;
|
|
||||||
x11.keyMap[XK_0] = Fw::Key0;
|
|
||||||
x11.keyMap[XK_colon] = Fw::KeyColon;
|
|
||||||
x11.keyMap[XK_semicolon] = Fw::KeySemicolon;
|
|
||||||
x11.keyMap[XK_less] = Fw::KeyLess;
|
|
||||||
x11.keyMap[XK_equal] = Fw::KeyEqual;
|
|
||||||
x11.keyMap[XK_greater] = Fw::KeyGreater;
|
|
||||||
x11.keyMap[XK_question] = Fw::KeyQuestion;
|
|
||||||
x11.keyMap[XK_at] = Fw::KeyAtSign;
|
|
||||||
x11.keyMap[XK_a] = Fw::KeyA;
|
|
||||||
x11.keyMap[XK_b] = Fw::KeyB;
|
|
||||||
x11.keyMap[XK_c] = Fw::KeyC;
|
|
||||||
x11.keyMap[XK_d] = Fw::KeyD;
|
|
||||||
x11.keyMap[XK_e] = Fw::KeyE;
|
|
||||||
x11.keyMap[XK_f] = Fw::KeyF;
|
|
||||||
x11.keyMap[XK_g] = Fw::KeyG;
|
|
||||||
x11.keyMap[XK_h] = Fw::KeyH;
|
|
||||||
x11.keyMap[XK_i] = Fw::KeyI;
|
|
||||||
x11.keyMap[XK_j] = Fw::KeyJ;
|
|
||||||
x11.keyMap[XK_k] = Fw::KeyK;
|
|
||||||
x11.keyMap[XK_l] = Fw::KeyL;
|
|
||||||
x11.keyMap[XK_m] = Fw::KeyM;
|
|
||||||
x11.keyMap[XK_n] = Fw::KeyN;
|
|
||||||
x11.keyMap[XK_o] = Fw::KeyO;
|
|
||||||
x11.keyMap[XK_p] = Fw::KeyP;
|
|
||||||
x11.keyMap[XK_q] = Fw::KeyQ;
|
|
||||||
x11.keyMap[XK_r] = Fw::KeyR;
|
|
||||||
x11.keyMap[XK_s] = Fw::KeyS;
|
|
||||||
x11.keyMap[XK_t] = Fw::KeyT;
|
|
||||||
x11.keyMap[XK_u] = Fw::KeyU;
|
|
||||||
x11.keyMap[XK_v] = Fw::KeyV;
|
|
||||||
x11.keyMap[XK_w] = Fw::KeyW;
|
|
||||||
x11.keyMap[XK_x] = Fw::KeyX;
|
|
||||||
x11.keyMap[XK_y] = Fw::KeyY;
|
|
||||||
x11.keyMap[XK_z] = Fw::KeyZ;
|
|
||||||
x11.keyMap[XK_bracketleft] = Fw::KeyLeftBracket;
|
|
||||||
x11.keyMap[XK_backslash] = Fw::KeyBackslash;
|
|
||||||
x11.keyMap[XK_bracketright] = Fw::KeyRightBracket;
|
|
||||||
x11.keyMap[XK_asciicircum] = Fw::KeyCaret;
|
|
||||||
x11.keyMap[XK_underscore] = Fw::KeyUnderscore;
|
|
||||||
x11.keyMap[XK_grave] = Fw::KeyGrave;
|
|
||||||
x11.keyMap[XK_braceleft] = Fw::KeyLeftCurly;
|
|
||||||
x11.keyMap[XK_bar] = Fw::KeyBar;
|
|
||||||
x11.keyMap[XK_braceright] = Fw::KeyRightCurly;
|
|
||||||
x11.keyMap[XK_asciitilde] = Fw::KeyTilde;
|
|
||||||
|
|
||||||
// keypad
|
|
||||||
x11.keyMap[XK_KP_Add] = Fw::KeyPlus;
|
|
||||||
x11.keyMap[XK_KP_Subtract] = Fw::KeyMinus;
|
|
||||||
x11.keyMap[XK_KP_Decimal] = Fw::KeyPeriod;
|
|
||||||
x11.keyMap[XK_KP_Divide] = Fw::KeySlash;
|
|
||||||
x11.keyMap[XK_KP_Multiply] = Fw::KeyAsterisk;
|
|
||||||
x11.keyMap[XK_KP_Enter] = Fw::KeyEnter;
|
|
||||||
|
|
||||||
// keypad with numlock off
|
|
||||||
x11.keyMap[XK_KP_Insert] = Fw::KeyNumpad0;
|
|
||||||
x11.keyMap[XK_KP_End] = Fw::KeyNumpad1;
|
|
||||||
x11.keyMap[XK_KP_Down] = Fw::KeyNumpad2;
|
|
||||||
x11.keyMap[XK_KP_Page_Down] = Fw::KeyNumpad3;
|
|
||||||
x11.keyMap[XK_KP_Left] = Fw::KeyNumpad4;
|
|
||||||
x11.keyMap[XK_KP_Begin] = Fw::KeyNumpad5;
|
|
||||||
x11.keyMap[XK_KP_Right] = Fw::KeyNumpad6;
|
|
||||||
x11.keyMap[XK_KP_Home] = Fw::KeyNumpad7;
|
|
||||||
x11.keyMap[XK_KP_Up] = Fw::KeyNumpad8;
|
|
||||||
x11.keyMap[XK_KP_Page_Up] = Fw::KeyNumpad9;
|
|
||||||
x11.keyMap[XK_KP_Delete] = Fw::KeyDelete;
|
|
||||||
|
|
||||||
// keypad with numlock on
|
|
||||||
x11.keyMap[XK_KP_0] = Fw::Key0;
|
|
||||||
x11.keyMap[XK_KP_1] = Fw::Key1;
|
|
||||||
x11.keyMap[XK_KP_2] = Fw::Key2;
|
|
||||||
x11.keyMap[XK_KP_3] = Fw::Key3;
|
|
||||||
x11.keyMap[XK_KP_4] = Fw::Key4;
|
|
||||||
x11.keyMap[XK_KP_5] = Fw::Key5;
|
|
||||||
x11.keyMap[XK_KP_6] = Fw::Key6;
|
|
||||||
x11.keyMap[XK_KP_7] = Fw::Key7;
|
|
||||||
x11.keyMap[XK_KP_8] = Fw::Key8;
|
|
||||||
x11.keyMap[XK_KP_9] = Fw::Key9;
|
|
||||||
|
|
||||||
x11.keyMap[XK_F1] = Fw::KeyF1;
|
|
||||||
x11.keyMap[XK_F2] = Fw::KeyF2;
|
|
||||||
x11.keyMap[XK_F3] = Fw::KeyF3;
|
|
||||||
x11.keyMap[XK_F4] = Fw::KeyF4;
|
|
||||||
x11.keyMap[XK_F5] = Fw::KeyF5;
|
|
||||||
x11.keyMap[XK_F6] = Fw::KeyF6;
|
|
||||||
x11.keyMap[XK_F7] = Fw::KeyF7;
|
|
||||||
x11.keyMap[XK_F8] = Fw::KeyF8;
|
|
||||||
x11.keyMap[XK_F9] = Fw::KeyF9;
|
|
||||||
x11.keyMap[XK_F10] = Fw::KeyF10;
|
|
||||||
x11.keyMap[XK_F11] = Fw::KeyF11;
|
|
||||||
x11.keyMap[XK_F12] = Fw::KeyF12;
|
|
||||||
|
|
||||||
// try to set a latin1 locales otherwise fallback to standard C locale
|
|
||||||
static char locales[][32] = { "en_US.iso88591", "iso88591", "en_US", "C" };
|
|
||||||
for(int i=0;i<4;++i) {
|
|
||||||
if(setlocale(LC_ALL, locales[i]))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// open display
|
|
||||||
x11.display = XOpenDisplay(0);
|
|
||||||
if(!x11.display)
|
|
||||||
logFatal("Failed to open X display");
|
|
||||||
|
|
||||||
// check if GLX is supported on this display
|
|
||||||
if(!glXQueryExtension(x11.display, 0, 0))
|
|
||||||
logFatal("GLX not supported");
|
|
||||||
|
|
||||||
// retrieve GLX version
|
|
||||||
int glxMajor;
|
|
||||||
int glxMinor;
|
|
||||||
if(!glXQueryVersion(x11.display, &glxMajor, &glxMinor))
|
|
||||||
logFatal("Unable to query GLX version");
|
|
||||||
logInfo("GLX version ",glxMajor,".",glxMinor);
|
|
||||||
|
|
||||||
// clipboard related atoms
|
|
||||||
x11.atomClipboard = XInternAtom(x11.display, "CLIPBOARD", False);
|
|
||||||
x11.atomTargets = XInternAtom(x11.display, "TARGETS", False);
|
|
||||||
x11.atomUTF8String = XInternAtom(x11.display, "UTF8_STRING", False);
|
|
||||||
x11.atomText = XInternAtom(x11.display, "TEXT", False);
|
|
||||||
x11.atomCompoundText = XInternAtom(x11.display, "COMPOUND_TEXT", False);
|
|
||||||
x11.atomWindowState = XInternAtom(x11.display, "_NET_WM_STATE", False);
|
|
||||||
x11.atomWindowMaximizedVert = XInternAtom(x11.display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
|
|
||||||
x11.atomWindowMaximizedHorz = XInternAtom(x11.display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Platform::terminate()
|
|
||||||
{
|
|
||||||
if(x11.window) {
|
|
||||||
destroyWindow();
|
|
||||||
x11.window = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// close display
|
|
||||||
if(x11.display) {
|
|
||||||
XCloseDisplay(x11.display);
|
|
||||||
x11.display = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Platform::poll()
|
|
||||||
{
|
|
||||||
XEvent event, peekevent;
|
|
||||||
PlatformEvent& platformEvent = x11.platformEvent;
|
|
||||||
static int oldWidth = -1;
|
|
||||||
static int oldHeight = -1;
|
|
||||||
while(XPending(x11.display) > 0) {
|
|
||||||
XNextEvent(x11.display, &event);
|
|
||||||
|
|
||||||
// call filter because xim will discard KeyPress events when keys still composing
|
|
||||||
if(XFilterEvent(&event, x11.window))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// discard events of repeated key releases
|
|
||||||
if(event.type == KeyRelease && XPending(x11.display)) {
|
|
||||||
XPeekEvent(x11.display, &peekevent);
|
|
||||||
if((peekevent.type == KeyPress) &&
|
|
||||||
(peekevent.xkey.keycode == event.xkey.keycode) &&
|
|
||||||
((peekevent.xkey.time-event.xkey.time) < 2))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(event.type) {
|
|
||||||
case Expose:
|
|
||||||
// needs redraw
|
|
||||||
break;
|
|
||||||
case ConfigureNotify:
|
|
||||||
// window resize
|
|
||||||
if(oldWidth != event.xconfigure.width || oldHeight != event.xconfigure.height) {
|
|
||||||
x11.listener->onResize(Size(event.xconfigure.width, event.xconfigure.height));
|
|
||||||
oldWidth = event.xconfigure.width;
|
|
||||||
oldHeight = event.xconfigure.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!isWindowMaximized()) {
|
|
||||||
x11.width = event.xconfigure.width;
|
|
||||||
x11.height = event.xconfigure.height;
|
|
||||||
|
|
||||||
// hack to fix x11 windows move gaps
|
|
||||||
static int gap_x = -1, gap_y = -1;
|
|
||||||
if(gap_x == -1 && gap_y == -1) {
|
|
||||||
gap_x = event.xconfigure.x;
|
|
||||||
gap_y = event.xconfigure.y;
|
|
||||||
}
|
|
||||||
x11.x = event.xconfigure.x - gap_x;
|
|
||||||
x11.y = event.xconfigure.y - gap_y;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KeyPress:
|
|
||||||
case KeyRelease: {
|
|
||||||
KeySym keysym;
|
|
||||||
char buf[32];
|
|
||||||
int len;
|
|
||||||
|
|
||||||
platformEvent.ctrl = (event.xkey.state & ControlMask);
|
|
||||||
platformEvent.shift = (event.xkey.state & ShiftMask);
|
|
||||||
platformEvent.alt = (event.xkey.state & Mod1Mask);
|
|
||||||
platformEvent.keychar = 0;
|
|
||||||
|
|
||||||
// fire enter text event
|
|
||||||
if(event.type == KeyPress && !platformEvent.ctrl && !platformEvent.alt) {
|
|
||||||
if(x11.xic) { // with xim we can get latin1 input correctly
|
|
||||||
Status status;
|
|
||||||
len = XmbLookupString(x11.xic, &event.xkey, buf, sizeof(buf), &keysym, &status);
|
|
||||||
} else { // otherwise use XLookupString, but it doesn't work right with dead keys often
|
|
||||||
static XComposeStatus compose = {NULL, 0};
|
|
||||||
len = XLookupString(&event.xkey, buf, sizeof(buf), &keysym, &compose);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(len > 0 &&
|
|
||||||
// these keys produces characters that we don't want to capture
|
|
||||||
keysym != XK_BackSpace &&
|
|
||||||
keysym != XK_Return &&
|
|
||||||
keysym != XK_Delete &&
|
|
||||||
keysym != XK_Escape &&
|
|
||||||
(uchar)(buf[0]) >= 32
|
|
||||||
) {
|
|
||||||
//logDebug("char: ", buf[0], " code: ", (uint)buf[0]);
|
|
||||||
platformEvent.keychar = buf[0];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//event.xkey.state &= ~(ShiftMask | LockMask);
|
|
||||||
len = XLookupString(&event.xkey, buf, sizeof(buf), &keysym, 0);
|
|
||||||
|
|
||||||
if(len > 0 && (uchar)platformEvent.keychar >= 32)
|
|
||||||
platformEvent.keychar = (len > 0) ? buf[0] : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(x11.keyMap.find(keysym) != x11.keyMap.end())
|
|
||||||
platformEvent.keycode = x11.keyMap[keysym];
|
|
||||||
else
|
|
||||||
platformEvent.keycode = Fw::KeyUnknown;
|
|
||||||
|
|
||||||
platformEvent.keycode = x11.keyMap[keysym];
|
|
||||||
platformEvent.type = (event.type == KeyPress) ? EventKeyDown : EventKeyUp;
|
|
||||||
|
|
||||||
if(platformEvent.keycode != Fw::KeyUnknown || platformEvent.keychar != 0)
|
|
||||||
x11.listener->onPlatformEvent(platformEvent);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ButtonPress:
|
|
||||||
case ButtonRelease:
|
|
||||||
switch(event.xbutton.button) {
|
|
||||||
case Button1:
|
|
||||||
platformEvent.type = (event.type == ButtonPress) ? EventMouseLeftButtonDown : EventMouseLeftButtonUp;
|
|
||||||
break;
|
|
||||||
case Button3:
|
|
||||||
platformEvent.type = (event.type == ButtonPress) ? EventMouseRightButtonDown : EventMouseRightButtonUp;
|
|
||||||
break;
|
|
||||||
case Button2:
|
|
||||||
platformEvent.type = (event.type == ButtonPress) ? EventMouseMiddleButtonDown : EventMouseMiddleButtonUp;
|
|
||||||
break;
|
|
||||||
case Button4:
|
|
||||||
platformEvent.type = EventMouseWheelUp;
|
|
||||||
break;
|
|
||||||
case Button5:
|
|
||||||
platformEvent.type = EventMouseWheelDown;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
x11.listener->onPlatformEvent(platformEvent);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MotionNotify:
|
|
||||||
{
|
|
||||||
platformEvent.type = EventMouseMove;
|
|
||||||
Point newMousePos(event.xbutton.x, event.xbutton.y);
|
|
||||||
platformEvent.mouseMoved = newMousePos - platformEvent.mousePos;
|
|
||||||
platformEvent.mousePos = newMousePos;
|
|
||||||
x11.listener->onPlatformEvent(platformEvent);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case MapNotify:
|
|
||||||
x11.visible = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case UnmapNotify:
|
|
||||||
x11.visible = false;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FocusIn:
|
|
||||||
x11.focused = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FocusOut:
|
|
||||||
x11.focused = false;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// clipboard data request
|
|
||||||
case SelectionRequest:
|
|
||||||
{
|
|
||||||
XEvent respond;
|
|
||||||
XSelectionRequestEvent *req = &(event.xselectionrequest);
|
|
||||||
|
|
||||||
if(req->target == x11.atomTargets ) {
|
|
||||||
Atom typeList[] = {x11.atomText, x11.atomCompoundText, x11.atomUTF8String, XA_STRING};
|
|
||||||
|
|
||||||
XChangeProperty(x11.display, req->requestor,
|
|
||||||
req->property, req->target,
|
|
||||||
8, PropModeReplace,
|
|
||||||
(uchar *) &typeList,
|
|
||||||
sizeof(typeList));
|
|
||||||
respond.xselection.property = req->property;
|
|
||||||
} else {
|
|
||||||
XChangeProperty(x11.display,
|
|
||||||
req->requestor,
|
|
||||||
req->property, req->target,
|
|
||||||
8,
|
|
||||||
PropModeReplace,
|
|
||||||
(uchar*) x11.clipboardText.c_str(),
|
|
||||||
x11.clipboardText.size());
|
|
||||||
respond.xselection.property = req->property;
|
|
||||||
}
|
|
||||||
|
|
||||||
respond.xselection.type = SelectionNotify;
|
|
||||||
respond.xselection.display = req->display;
|
|
||||||
respond.xselection.requestor = req->requestor;
|
|
||||||
respond.xselection.selection = req->selection;
|
|
||||||
respond.xselection.target = req->target;
|
|
||||||
respond.xselection.time = req->time;
|
|
||||||
XSendEvent(x11.display, req->requestor, 0, 0, &respond);
|
|
||||||
XFlush(x11.display);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ClientMessage:
|
|
||||||
{
|
|
||||||
if((Atom)event.xclient.data.l[0] == x11.atomDeleteWindow)
|
|
||||||
x11.listener->onClose();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Platform::createWindow(int x, int y, int width, int height, int minWidth, int minHeight, bool maximized)
|
|
||||||
{
|
|
||||||
static int attrList[] = {
|
|
||||||
GLX_USE_GL,
|
|
||||||
GLX_RGBA,
|
|
||||||
GLX_DOUBLEBUFFER,
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
// choose OpenGL, RGBA, double buffered, visual
|
|
||||||
x11.visual = glXChooseVisual(x11.display, DefaultScreen(x11.display), attrList);
|
|
||||||
if(!x11.visual)
|
|
||||||
logFatal("RGBA/Double buffered visual not supported");
|
|
||||||
|
|
||||||
// create GLX context
|
|
||||||
x11.glxContext = glXCreateContext(x11.display, x11.visual, NULL, True);
|
|
||||||
if(!x11.glxContext)
|
|
||||||
logFatal("Unable to create GLX context");
|
|
||||||
|
|
||||||
logInfo("Direct rendering: ", glXIsDirect(x11.display, x11.glxContext) ? "Yes" : "No");
|
|
||||||
|
|
||||||
// color map
|
|
||||||
x11.colormap = XCreateColormap(x11.display,
|
|
||||||
RootWindow(x11.display, x11.visual->screen),
|
|
||||||
x11.visual->visual,
|
|
||||||
AllocNone);
|
|
||||||
|
|
||||||
// setup window type
|
|
||||||
XSetWindowAttributes attr;
|
|
||||||
attr.colormap = x11.colormap;
|
|
||||||
attr.border_pixel = 0;
|
|
||||||
attr.event_mask = KeyPressMask | KeyReleaseMask |
|
|
||||||
ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
|
|
||||||
ExposureMask | VisibilityChangeMask |
|
|
||||||
StructureNotifyMask | FocusChangeMask;
|
|
||||||
unsigned int mask = CWBorderPixel | CWColormap | CWEventMask;
|
|
||||||
|
|
||||||
x11.x = x;
|
|
||||||
x11.y = y;
|
|
||||||
|
|
||||||
// create the window
|
|
||||||
x11.window = XCreateWindow(x11.display,
|
|
||||||
RootWindow(x11.display, x11.visual->screen),
|
|
||||||
0, 0,
|
|
||||||
width, height,
|
|
||||||
0,
|
|
||||||
x11.visual->depth,
|
|
||||||
InputOutput,
|
|
||||||
x11.visual->visual,
|
|
||||||
mask,
|
|
||||||
&attr);
|
|
||||||
if(!x11.window)
|
|
||||||
logFatal("XCreateWindow failed");
|
|
||||||
|
|
||||||
// create input context (to have better key input handling)
|
|
||||||
if(XSupportsLocale()) {
|
|
||||||
XSetLocaleModifiers("");
|
|
||||||
x11.xim = XOpenIM(x11.display, NULL, NULL, NULL);
|
|
||||||
if(x11.xim) {
|
|
||||||
x11.xic = XCreateIC(x11.xim,
|
|
||||||
XNInputStyle,
|
|
||||||
XIMPreeditNothing | XIMStatusNothing,
|
|
||||||
XNClientWindow, x11.window, NULL);
|
|
||||||
if(!x11.xic)
|
|
||||||
logError("Unable to create the input context");
|
|
||||||
} else
|
|
||||||
logError("Failed to open an input method");
|
|
||||||
} else
|
|
||||||
logError("X11 does not support the current locale");
|
|
||||||
|
|
||||||
if(!x11.xic)
|
|
||||||
logWarning("Input of special keys maybe messed up because we couldn't create an input context");
|
|
||||||
|
|
||||||
// set window minimum size
|
|
||||||
XSizeHints xsizehints;
|
|
||||||
xsizehints.flags = PMinSize;
|
|
||||||
xsizehints.min_width = minWidth;
|
|
||||||
xsizehints.min_height= minHeight;
|
|
||||||
XSetWMSizeHints(x11.display, x11.window, &xsizehints, XA_WM_NORMAL_HINTS);
|
|
||||||
|
|
||||||
// handle delete window event
|
|
||||||
x11.atomDeleteWindow = XInternAtom(x11.display, "WM_DELETE_WINDOW", True);
|
|
||||||
XSetWMProtocols(x11.display, x11.window, &x11.atomDeleteWindow , 1);
|
|
||||||
|
|
||||||
// connect the GLX-context to the window
|
|
||||||
if(!glXMakeCurrent(x11.display, x11.window, x11.glxContext))
|
|
||||||
logFatal("glXMakeCurrent failed");
|
|
||||||
|
|
||||||
x11.width = width;
|
|
||||||
x11.height = height;
|
|
||||||
x11.maximizeOnFirstShow = maximized;
|
|
||||||
|
|
||||||
// call first onResize
|
|
||||||
x11.listener->onResize(Size(width, height));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Platform::setWindowIcon(const std::string& pngIcon)
|
|
||||||
{
|
|
||||||
apng_data apng;
|
|
||||||
std::stringstream fin;
|
|
||||||
g_resources.loadFile(pngIcon, fin);
|
|
||||||
if(load_apng(fin, &apng) == 0) {
|
|
||||||
if(apng.bpp != 4) {
|
|
||||||
logError("could not set app icon, icon image must have 4 channels");
|
|
||||||
free_apng(&apng);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int n = apng.width * apng.height;
|
|
||||||
std::vector<unsigned long int> iconData(n + 2);
|
|
||||||
iconData[0] = apng.width;
|
|
||||||
iconData[1] = apng.height;
|
|
||||||
for(int i=0; i < n;++i) {
|
|
||||||
uint8 *pixel = (uint8*)&iconData[2 + i];
|
|
||||||
pixel[2] = *(apng.pdata + (i * 4) + 0);
|
|
||||||
pixel[1] = *(apng.pdata + (i * 4) + 1);
|
|
||||||
pixel[0] = *(apng.pdata + (i * 4) + 2);
|
|
||||||
pixel[3] = *(apng.pdata + (i * 4) + 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
Atom property = XInternAtom(x11.display, "_NET_WM_ICON", 0);
|
|
||||||
if(!XChangeProperty(x11.display, x11.window, property, XA_CARDINAL, 32, PropModeReplace, (const unsigned char*)&iconData[0], iconData.size()))
|
|
||||||
logError("Couldn't set app icon");
|
|
||||||
|
|
||||||
free_apng(&apng);
|
|
||||||
} else
|
|
||||||
logError("Couldn't load app icon");
|
|
||||||
}
|
|
||||||
|
|
||||||
void Platform::destroyWindow()
|
|
||||||
{
|
|
||||||
if(x11.glxContext) {
|
|
||||||
glXMakeCurrent(x11.display, None, NULL);
|
|
||||||
glXDestroyContext(x11.display, x11.glxContext);
|
|
||||||
x11.glxContext = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(x11.visual) {
|
|
||||||
XFree(x11.visual);
|
|
||||||
x11.visual = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(x11.colormap != None) {
|
|
||||||
XFreeColormap(x11.display, x11.colormap);
|
|
||||||
x11.colormap = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(x11.window != None) {
|
|
||||||
XDestroyWindow(x11.display, x11.window);
|
|
||||||
x11.window = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(x11.xic) {
|
|
||||||
XDestroyIC(x11.xic);
|
|
||||||
x11.xic = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(x11.xim) {
|
|
||||||
XCloseIM(x11.xim);
|
|
||||||
x11.xim = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Platform::showWindow()
|
|
||||||
{
|
|
||||||
XMapWindow(x11.display, x11.window);
|
|
||||||
|
|
||||||
static bool firstShow = true;
|
|
||||||
if(firstShow) {
|
|
||||||
// move window
|
|
||||||
XMoveWindow(x11.display, x11.window, x11.x, x11.y);
|
|
||||||
|
|
||||||
// set window maximized if needed
|
|
||||||
if(x11.maximizeOnFirstShow) {
|
|
||||||
XEvent e;
|
|
||||||
memset(&e, 0, sizeof(XEvent));
|
|
||||||
e.xany.type = ClientMessage;
|
|
||||||
e.xclient.message_type = x11.atomWindowState;
|
|
||||||
e.xclient.format = 32;
|
|
||||||
e.xclient.window = x11.window;
|
|
||||||
e.xclient.data.l[0] = 1l;
|
|
||||||
e.xclient.data.l[1] = x11.atomWindowMaximizedVert;
|
|
||||||
e.xclient.data.l[2] = x11.atomWindowMaximizedHorz;
|
|
||||||
e.xclient.data.l[3] = 0l;
|
|
||||||
|
|
||||||
XSendEvent(x11.display, RootWindow(x11.display, x11.visual->screen), 0,
|
|
||||||
SubstructureNotifyMask | SubstructureRedirectMask, &e);
|
|
||||||
}
|
|
||||||
firstShow = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Platform::hideWindow()
|
|
||||||
{
|
|
||||||
XUnmapWindow(x11.display, x11.window);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Platform::setWindowTitle(const char *title)
|
|
||||||
{
|
|
||||||
XStoreName(x11.display, x11.window, title);
|
|
||||||
XSetIconName(x11.display, x11.window, title);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *Platform::getExtensionProcAddress(const char *ext)
|
|
||||||
{
|
|
||||||
return (void*)glXGetProcAddressARB((const GLubyte*)ext);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Platform::isExtensionSupported(const char *ext)
|
|
||||||
{
|
|
||||||
const char *exts = glXQueryExtensionsString(x11.display, DefaultScreen(x11.display));
|
|
||||||
if(strstr(exts, ext))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *Platform::getClipboardText()
|
|
||||||
{
|
|
||||||
Window ownerWindow = XGetSelectionOwner(x11.display, x11.atomClipboard);
|
|
||||||
if(ownerWindow == x11.window)
|
|
||||||
return x11.clipboardText.c_str();
|
|
||||||
|
|
||||||
std::string clipboard = "";
|
|
||||||
if(ownerWindow != None) {
|
|
||||||
XConvertSelection(x11.display, x11.atomClipboard, XA_STRING, 0, ownerWindow, CurrentTime);
|
|
||||||
XFlush(x11.display);
|
|
||||||
|
|
||||||
// hack to wait SelectioNotify event, otherwise we will get wrong clipboard pastes
|
|
||||||
usleep(100 * 1000);
|
|
||||||
|
|
||||||
// check for data
|
|
||||||
Atom type;
|
|
||||||
int format;
|
|
||||||
ulong numItems, bytesLeft, dummy;
|
|
||||||
uchar *data;
|
|
||||||
XGetWindowProperty(x11.display, ownerWindow,
|
|
||||||
XA_STRING,
|
|
||||||
0, 0, 0,
|
|
||||||
AnyPropertyType,
|
|
||||||
&type,
|
|
||||||
&format,
|
|
||||||
&numItems,
|
|
||||||
&bytesLeft,
|
|
||||||
&data);
|
|
||||||
if(bytesLeft > 0) {
|
|
||||||
// get the data get
|
|
||||||
int result = XGetWindowProperty(x11.display, ownerWindow,
|
|
||||||
XA_STRING,
|
|
||||||
0,
|
|
||||||
bytesLeft,
|
|
||||||
0,
|
|
||||||
AnyPropertyType,
|
|
||||||
&type,
|
|
||||||
&format,
|
|
||||||
&numItems,
|
|
||||||
&dummy,
|
|
||||||
&data);
|
|
||||||
if(result == Success)
|
|
||||||
clipboard = (const char*)data;
|
|
||||||
XFree(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return clipboard.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Platform::setClipboardText(const char *text)
|
|
||||||
{
|
|
||||||
x11.clipboardText = text;
|
|
||||||
XSetSelectionOwner(x11.display, x11.atomClipboard, x11.window, CurrentTime);
|
|
||||||
XFlush(x11.display);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Platform::hideMouseCursor()
|
|
||||||
{
|
|
||||||
if(x11.cursor == None) {
|
|
||||||
char bm[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
||||||
Pixmap pix = XCreateBitmapFromData(x11.display, x11.window, bm, 8, 8);
|
|
||||||
XColor black;
|
|
||||||
memset(&black, 0, sizeof(XColor));
|
|
||||||
black.flags = DoRed | DoGreen | DoBlue;
|
|
||||||
x11.cursor = XCreatePixmapCursor(x11.display, pix, pix, &black, &black, 0, 0);
|
|
||||||
XFreePixmap(x11.display, pix);
|
|
||||||
}
|
|
||||||
XDefineCursor(x11.display, x11.window, x11.cursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Platform::showMouseCursor()
|
|
||||||
{
|
|
||||||
XUndefineCursor(x11.display, x11.window);
|
|
||||||
if(x11.cursor != None) {
|
|
||||||
XFreeCursor(x11.display, x11.cursor);
|
|
||||||
x11.cursor = None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Point Platform::getMouseCursorPos()
|
|
||||||
{
|
|
||||||
return x11.platformEvent.mousePos;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Platform::setVerticalSync(bool enable)
|
|
||||||
{
|
|
||||||
typedef GLint (*glSwapIntervalProc)(GLint);
|
|
||||||
glSwapIntervalProc glSwapInterval = NULL;
|
|
||||||
|
|
||||||
if(isExtensionSupported("GLX_MESA_swap_control"))
|
|
||||||
glSwapInterval = (glSwapIntervalProc)getExtensionProcAddress("glXSwapIntervalMESA");
|
|
||||||
else if(isExtensionSupported("GLX_SGI_swap_control"))
|
|
||||||
glSwapInterval = (glSwapIntervalProc)getExtensionProcAddress("glXSwapIntervalSGI");
|
|
||||||
|
|
||||||
if(glSwapInterval)
|
|
||||||
glSwapInterval(enable ? 1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Platform::swapBuffers()
|
|
||||||
{
|
|
||||||
//glFlush();
|
|
||||||
//glFinish();
|
|
||||||
glXSwapBuffers(x11.display, x11.window);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Platform::isWindowFocused()
|
|
||||||
{
|
|
||||||
return x11.focused;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Platform::isWindowVisible()
|
|
||||||
{
|
|
||||||
return x11.visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Platform::getWindowX()
|
|
||||||
{
|
|
||||||
return x11.x;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Platform::getWindowY()
|
|
||||||
{
|
|
||||||
return x11.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Platform::getWindowWidth()
|
|
||||||
{
|
|
||||||
return x11.width;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Platform::getWindowHeight()
|
|
||||||
{
|
|
||||||
return x11.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Platform::getDisplayWidth()
|
|
||||||
{
|
|
||||||
return XDisplayWidth(x11.display, DefaultScreen(x11.display));
|
|
||||||
}
|
|
||||||
|
|
||||||
int Platform::getDisplayHeight()
|
|
||||||
{
|
|
||||||
return XDisplayHeight(x11.display, DefaultScreen(x11.display));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Platform::isWindowMaximized()
|
|
||||||
{
|
|
||||||
bool ret = false;
|
|
||||||
Atom actualType;
|
|
||||||
int actualFormat;
|
|
||||||
ulong i, numItems, bytesAfter;
|
|
||||||
uchar *propertyValue = NULL;
|
|
||||||
long maxLength = 1024;
|
|
||||||
|
|
||||||
if(XGetWindowProperty(x11.display, x11.window, x11.atomWindowState,
|
|
||||||
0l, maxLength, False, XA_ATOM, &actualType,
|
|
||||||
&actualFormat, &numItems, &bytesAfter,
|
|
||||||
&propertyValue) == Success) {
|
|
||||||
Atom *atoms = (Atom *)propertyValue;
|
|
||||||
int maximized = 0;
|
|
||||||
|
|
||||||
for(i=0; i<numItems; ++i) {
|
|
||||||
if(atoms[i] == x11.atomWindowMaximizedVert)
|
|
||||||
maximized |= 1;
|
|
||||||
else if(atoms[i] == x11.atomWindowMaximizedHorz)
|
|
||||||
maximized |= 2;
|
|
||||||
}
|
|
||||||
if(maximized == 3)
|
|
||||||
ret = true;
|
|
||||||
XFree(propertyValue);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Platform::getAppUserDir()
|
|
||||||
{
|
|
||||||
std::stringstream sdir;
|
|
||||||
sdir << PHYSFS_getUserDir() << "." << x11.appName;
|
|
||||||
if((mkdir(sdir.str().c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) && (errno != EEXIST))
|
|
||||||
logError("Couldn't create directory for saving configuration file. (",sdir.str(),")");
|
|
||||||
return sdir.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Platform::displayFatalError(const std::string& message)
|
|
||||||
{
|
|
||||||
// nothing to do
|
|
||||||
}
|
|
|
@ -0,0 +1,887 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/otclient>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "x11window.h"
|
||||||
|
#include <framework/core/resourcemanager.h>
|
||||||
|
#include <framework/thirdparty/apngloader.h>
|
||||||
|
|
||||||
|
X11Window::X11Window()
|
||||||
|
{
|
||||||
|
m_cursor = None;
|
||||||
|
m_visual = 0;
|
||||||
|
m_colormap = 0;
|
||||||
|
|
||||||
|
m_keyMap[XK_Escape] = Fw::KeyEscape;
|
||||||
|
m_keyMap[XK_Tab] = Fw::KeyTab;
|
||||||
|
m_keyMap[XK_Return] = Fw::KeyReturn;
|
||||||
|
m_keyMap[XK_BackSpace] = Fw::KeyBackspace;
|
||||||
|
|
||||||
|
m_keyMap[XK_Page_Up] = Fw::KeyPageUp;
|
||||||
|
m_keyMap[XK_Page_Down] = Fw::KeyPageDown;
|
||||||
|
m_keyMap[XK_Home] = Fw::KeyHome;
|
||||||
|
m_keyMap[XK_End] = Fw::KeyEnd;
|
||||||
|
m_keyMap[XK_Insert] = Fw::KeyInsert;
|
||||||
|
m_keyMap[XK_Delete] = Fw::KeyDelete;
|
||||||
|
|
||||||
|
m_keyMap[XK_Up] = Fw::KeyUp;
|
||||||
|
m_keyMap[XK_Down] = Fw::KeyDown;
|
||||||
|
m_keyMap[XK_Left] = Fw::KeyLeft;
|
||||||
|
m_keyMap[XK_Right] = Fw::KeyRight;
|
||||||
|
|
||||||
|
m_keyMap[XK_Num_Lock] = Fw::KeyNumLock;
|
||||||
|
m_keyMap[XK_Scroll_Lock] = Fw::KeyScrollLock;
|
||||||
|
m_keyMap[XK_Caps_Lock] = Fw::KeyCapsLock;
|
||||||
|
m_keyMap[XK_Print] = Fw::KeyPrintScreen;
|
||||||
|
m_keyMap[XK_Pause] = Fw::KeyPause;
|
||||||
|
|
||||||
|
m_keyMap[XK_Control_L] = Fw::KeyCtrl;
|
||||||
|
m_keyMap[XK_Control_R] = Fw::KeyCtrl;
|
||||||
|
m_keyMap[XK_Shift_R] = Fw::KeyShift;
|
||||||
|
m_keyMap[XK_Shift_L] = Fw::KeyShift;
|
||||||
|
m_keyMap[XK_Alt_R] = Fw::KeyAlt;
|
||||||
|
m_keyMap[XK_Alt_L] = Fw::KeyAltGr;
|
||||||
|
m_keyMap[XK_Meta_L] = Fw::KeyMeta;
|
||||||
|
m_keyMap[XK_Meta_R] = Fw::KeyMeta;
|
||||||
|
m_keyMap[XK_Menu] = Fw::KeyMenu;
|
||||||
|
|
||||||
|
// ascii characters
|
||||||
|
m_keyMap[XK_space] = Fw::KeySpace;
|
||||||
|
m_keyMap[XK_exclam] = Fw::KeyExclamation;
|
||||||
|
m_keyMap[XK_quotedbl] = Fw::KeyQuote;
|
||||||
|
m_keyMap[XK_numbersign] = Fw::KeyNumberSign;
|
||||||
|
m_keyMap[XK_dollar] = Fw::KeyDollar;
|
||||||
|
m_keyMap[XK_percent] = Fw::KeyPercent;
|
||||||
|
m_keyMap[XK_ampersand] = Fw::KeyAmpersand;
|
||||||
|
m_keyMap[XK_apostrophe] = Fw::KeyApostrophe;
|
||||||
|
m_keyMap[XK_parenleft] = Fw::KeyLeftParen;
|
||||||
|
m_keyMap[XK_parenright] = Fw::KeyRightParen;
|
||||||
|
m_keyMap[XK_asterisk] = Fw::KeyAsterisk;
|
||||||
|
m_keyMap[XK_plus] = Fw::KeyPlus;
|
||||||
|
m_keyMap[XK_comma] = Fw::KeyComma;
|
||||||
|
m_keyMap[XK_minus] = Fw::KeyMinus;
|
||||||
|
m_keyMap[XK_period] = Fw::KeyPeriod;
|
||||||
|
m_keyMap[XK_slash] = Fw::KeySlash;
|
||||||
|
m_keyMap[XK_1] = Fw::Key1;
|
||||||
|
m_keyMap[XK_2] = Fw::Key2;
|
||||||
|
m_keyMap[XK_3] = Fw::Key3;
|
||||||
|
m_keyMap[XK_4] = Fw::Key4;
|
||||||
|
m_keyMap[XK_5] = Fw::Key5;
|
||||||
|
m_keyMap[XK_6] = Fw::Key6;
|
||||||
|
m_keyMap[XK_7] = Fw::Key7;
|
||||||
|
m_keyMap[XK_8] = Fw::Key8;
|
||||||
|
m_keyMap[XK_9] = Fw::Key9;
|
||||||
|
m_keyMap[XK_0] = Fw::Key0;
|
||||||
|
m_keyMap[XK_colon] = Fw::KeyColon;
|
||||||
|
m_keyMap[XK_semicolon] = Fw::KeySemicolon;
|
||||||
|
m_keyMap[XK_less] = Fw::KeyLess;
|
||||||
|
m_keyMap[XK_equal] = Fw::KeyEqual;
|
||||||
|
m_keyMap[XK_greater] = Fw::KeyGreater;
|
||||||
|
m_keyMap[XK_question] = Fw::KeyQuestion;
|
||||||
|
m_keyMap[XK_at] = Fw::KeyAtSign;
|
||||||
|
m_keyMap[XK_a] = Fw::KeyA;
|
||||||
|
m_keyMap[XK_b] = Fw::KeyB;
|
||||||
|
m_keyMap[XK_c] = Fw::KeyC;
|
||||||
|
m_keyMap[XK_d] = Fw::KeyD;
|
||||||
|
m_keyMap[XK_e] = Fw::KeyE;
|
||||||
|
m_keyMap[XK_f] = Fw::KeyF;
|
||||||
|
m_keyMap[XK_g] = Fw::KeyG;
|
||||||
|
m_keyMap[XK_h] = Fw::KeyH;
|
||||||
|
m_keyMap[XK_i] = Fw::KeyI;
|
||||||
|
m_keyMap[XK_j] = Fw::KeyJ;
|
||||||
|
m_keyMap[XK_k] = Fw::KeyK;
|
||||||
|
m_keyMap[XK_l] = Fw::KeyL;
|
||||||
|
m_keyMap[XK_m] = Fw::KeyM;
|
||||||
|
m_keyMap[XK_n] = Fw::KeyN;
|
||||||
|
m_keyMap[XK_o] = Fw::KeyO;
|
||||||
|
m_keyMap[XK_p] = Fw::KeyP;
|
||||||
|
m_keyMap[XK_q] = Fw::KeyQ;
|
||||||
|
m_keyMap[XK_r] = Fw::KeyR;
|
||||||
|
m_keyMap[XK_s] = Fw::KeyS;
|
||||||
|
m_keyMap[XK_t] = Fw::KeyT;
|
||||||
|
m_keyMap[XK_u] = Fw::KeyU;
|
||||||
|
m_keyMap[XK_v] = Fw::KeyV;
|
||||||
|
m_keyMap[XK_w] = Fw::KeyW;
|
||||||
|
m_keyMap[XK_x] = Fw::KeyX;
|
||||||
|
m_keyMap[XK_y] = Fw::KeyY;
|
||||||
|
m_keyMap[XK_z] = Fw::KeyZ;
|
||||||
|
m_keyMap[XK_bracketleft] = Fw::KeyLeftBracket;
|
||||||
|
m_keyMap[XK_backslash] = Fw::KeyBackslash;
|
||||||
|
m_keyMap[XK_bracketright] = Fw::KeyRightBracket;
|
||||||
|
m_keyMap[XK_asciicircum] = Fw::KeyCaret;
|
||||||
|
m_keyMap[XK_underscore] = Fw::KeyUnderscore;
|
||||||
|
m_keyMap[XK_grave] = Fw::KeyGrave;
|
||||||
|
m_keyMap[XK_braceleft] = Fw::KeyLeftCurly;
|
||||||
|
m_keyMap[XK_bar] = Fw::KeyBar;
|
||||||
|
m_keyMap[XK_braceright] = Fw::KeyRightCurly;
|
||||||
|
m_keyMap[XK_asciitilde] = Fw::KeyTilde;
|
||||||
|
|
||||||
|
// keypad
|
||||||
|
m_keyMap[XK_KP_Add] = Fw::KeyPlus;
|
||||||
|
m_keyMap[XK_KP_Subtract] = Fw::KeyMinus;
|
||||||
|
m_keyMap[XK_KP_Decimal] = Fw::KeyPeriod;
|
||||||
|
m_keyMap[XK_KP_Divide] = Fw::KeySlash;
|
||||||
|
m_keyMap[XK_KP_Multiply] = Fw::KeyAsterisk;
|
||||||
|
m_keyMap[XK_KP_Enter] = Fw::KeyEnter;
|
||||||
|
|
||||||
|
// keypad with numlock off
|
||||||
|
m_keyMap[XK_KP_Insert] = Fw::KeyNumpad0;
|
||||||
|
m_keyMap[XK_KP_End] = Fw::KeyNumpad1;
|
||||||
|
m_keyMap[XK_KP_Down] = Fw::KeyNumpad2;
|
||||||
|
m_keyMap[XK_KP_Page_Down] = Fw::KeyNumpad3;
|
||||||
|
m_keyMap[XK_KP_Left] = Fw::KeyNumpad4;
|
||||||
|
m_keyMap[XK_KP_Begin] = Fw::KeyNumpad5;
|
||||||
|
m_keyMap[XK_KP_Right] = Fw::KeyNumpad6;
|
||||||
|
m_keyMap[XK_KP_Home] = Fw::KeyNumpad7;
|
||||||
|
m_keyMap[XK_KP_Up] = Fw::KeyNumpad8;
|
||||||
|
m_keyMap[XK_KP_Page_Up] = Fw::KeyNumpad9;
|
||||||
|
m_keyMap[XK_KP_Delete] = Fw::KeyDelete;
|
||||||
|
|
||||||
|
// keypad with numlock on
|
||||||
|
m_keyMap[XK_KP_0] = Fw::Key0;
|
||||||
|
m_keyMap[XK_KP_1] = Fw::Key1;
|
||||||
|
m_keyMap[XK_KP_2] = Fw::Key2;
|
||||||
|
m_keyMap[XK_KP_3] = Fw::Key3;
|
||||||
|
m_keyMap[XK_KP_4] = Fw::Key4;
|
||||||
|
m_keyMap[XK_KP_5] = Fw::Key5;
|
||||||
|
m_keyMap[XK_KP_6] = Fw::Key6;
|
||||||
|
m_keyMap[XK_KP_7] = Fw::Key7;
|
||||||
|
m_keyMap[XK_KP_8] = Fw::Key8;
|
||||||
|
m_keyMap[XK_KP_9] = Fw::Key9;
|
||||||
|
|
||||||
|
m_keyMap[XK_F1] = Fw::KeyF1;
|
||||||
|
m_keyMap[XK_F2] = Fw::KeyF2;
|
||||||
|
m_keyMap[XK_F3] = Fw::KeyF3;
|
||||||
|
m_keyMap[XK_F4] = Fw::KeyF4;
|
||||||
|
m_keyMap[XK_F5] = Fw::KeyF5;
|
||||||
|
m_keyMap[XK_F6] = Fw::KeyF6;
|
||||||
|
m_keyMap[XK_F7] = Fw::KeyF7;
|
||||||
|
m_keyMap[XK_F8] = Fw::KeyF8;
|
||||||
|
m_keyMap[XK_F9] = Fw::KeyF9;
|
||||||
|
m_keyMap[XK_F10] = Fw::KeyF10;
|
||||||
|
m_keyMap[XK_F11] = Fw::KeyF11;
|
||||||
|
m_keyMap[XK_F12] = Fw::KeyF12;
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::init()
|
||||||
|
{
|
||||||
|
m_size = Size(200, 200);
|
||||||
|
internalOpenDisplay();
|
||||||
|
internalCheckGL();
|
||||||
|
internalChooseGLVisual();
|
||||||
|
internalCreateGLContext();
|
||||||
|
internalCreateWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::terminate()
|
||||||
|
{
|
||||||
|
XDestroyWindow(m_display, m_window);
|
||||||
|
|
||||||
|
if(m_colormap)
|
||||||
|
XFreeColormap(m_display, m_colormap);
|
||||||
|
|
||||||
|
internalDestroyGLContext();
|
||||||
|
|
||||||
|
if(m_visual)
|
||||||
|
XFree(m_visual);
|
||||||
|
|
||||||
|
if(m_xic)
|
||||||
|
XDestroyIC(m_xic);
|
||||||
|
|
||||||
|
if(m_xim)
|
||||||
|
XCloseIM(m_xim);
|
||||||
|
|
||||||
|
XCloseDisplay(m_display);
|
||||||
|
|
||||||
|
m_visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::internalOpenDisplay()
|
||||||
|
{
|
||||||
|
m_display = XOpenDisplay(NULL);
|
||||||
|
if(!m_display)
|
||||||
|
logFatal("Unable to open X11 display");
|
||||||
|
m_screen = DefaultScreen(m_display);
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::internalCreateWindow()
|
||||||
|
{
|
||||||
|
Visual *vis;
|
||||||
|
int depth;
|
||||||
|
unsigned int attrsMask = CWEventMask;
|
||||||
|
XSetWindowAttributes attrs = {0};
|
||||||
|
|
||||||
|
attrs.event_mask = KeyPressMask | KeyReleaseMask |
|
||||||
|
ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
|
||||||
|
ExposureMask | VisibilityChangeMask |
|
||||||
|
StructureNotifyMask | FocusChangeMask;
|
||||||
|
|
||||||
|
if(m_visual) {
|
||||||
|
m_colormap = XCreateColormap(m_display, m_rootWindow, m_visual->visual, AllocNone);
|
||||||
|
attrs.colormap = m_colormap;
|
||||||
|
attrs.border_pixel = 0;
|
||||||
|
attrsMask |= CWBorderPixel | CWColormap;
|
||||||
|
vis = m_visual->visual;
|
||||||
|
depth = m_visual->depth;
|
||||||
|
} else {
|
||||||
|
attrs.override_redirect = False;
|
||||||
|
attrsMask |= CWOverrideRedirect;
|
||||||
|
depth = CopyFromParent;
|
||||||
|
vis = CopyFromParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_window = XCreateWindow(m_display, m_rootWindow,
|
||||||
|
m_pos.x, m_pos.y, m_size.width(), m_size.height(),
|
||||||
|
0,
|
||||||
|
depth,
|
||||||
|
InputOutput,
|
||||||
|
vis,
|
||||||
|
attrsMask, &attrs);
|
||||||
|
if(!m_window)
|
||||||
|
logFatal("Unable to create X11 window!");
|
||||||
|
|
||||||
|
// ensure window input focus
|
||||||
|
XWMHints hints;
|
||||||
|
hints.input = True;
|
||||||
|
hints.flags = InputHint;
|
||||||
|
XSetWMHints(m_display, m_window, &hints);
|
||||||
|
|
||||||
|
// ensure window position
|
||||||
|
XMoveWindow(m_display, m_window, m_pos.x, m_pos.y);
|
||||||
|
|
||||||
|
// handle wm_delete events
|
||||||
|
m_wmDelete = XInternAtom(m_display, "WM_DELETE_WINDOW", True);
|
||||||
|
XSetWMProtocols(m_display, m_window, &m_wmDelete , 1);
|
||||||
|
|
||||||
|
if(!internalSetupWindowInput())
|
||||||
|
logWarning("Input of special keys may be messed up, because window input initialization failed");
|
||||||
|
|
||||||
|
internalConnectGLContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X11Window::internalSetupWindowInput()
|
||||||
|
{
|
||||||
|
// try to set a latin1 locales, otherwise fallback to standard C locale
|
||||||
|
static char locales[4][32] = { "en_US.iso88591", "iso88591", "en_US", "C" };
|
||||||
|
for(int i=0;i<4;++i) {
|
||||||
|
if(setlocale(LC_ALL, locales[i]))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create input context (to have better key input handling)
|
||||||
|
if(!XSupportsLocale()) {
|
||||||
|
logError("X11 doesn't support the current locale");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
XSetLocaleModifiers("");
|
||||||
|
m_xim = XOpenIM(m_display, NULL, NULL, NULL);
|
||||||
|
if(!m_xim) {
|
||||||
|
logError("XOpenIM failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_xic = XCreateIC(m_xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, m_window, NULL);
|
||||||
|
if(!m_xic) {
|
||||||
|
logError("Unable to create the input context");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::internalCheckGL()
|
||||||
|
{
|
||||||
|
#ifndef OPENGL_ES2
|
||||||
|
if(!glXQueryExtension(m_display, NULL, NULL))
|
||||||
|
logFatal("GLX not supported");
|
||||||
|
#else
|
||||||
|
m_eglDisplay = eglGetDisplay((EGLNativeDisplayType)m_display);
|
||||||
|
if(m_eglDisplay == EGL_NO_DISPLAY)
|
||||||
|
logFatal("EGL not supported");
|
||||||
|
|
||||||
|
if(!eglInitialize(m_eglDisplay, NULL, NULL))
|
||||||
|
logFatal("Unable to initialize EGL");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::internalChooseGLVisual()
|
||||||
|
{
|
||||||
|
#ifndef OPENGL_ES2
|
||||||
|
static int attrList[] = {
|
||||||
|
GLX_USE_GL,
|
||||||
|
GLX_RGBA,
|
||||||
|
GLX_DOUBLEBUFFER,
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
m_visual = glXChooseVisual(m_display, m_screen, attrList);
|
||||||
|
if(!m_visual)
|
||||||
|
logFatal("Couldn't choose RGBA, double buffered visual");
|
||||||
|
|
||||||
|
m_rootWindow = RootWindow(m_display, m_visual->screen);
|
||||||
|
#else
|
||||||
|
static int attrList[] = {
|
||||||
|
EGL_BUFFER_SIZE, 16,
|
||||||
|
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||||
|
EGL_NONE
|
||||||
|
};
|
||||||
|
|
||||||
|
EGLint numConfig;
|
||||||
|
if(!eglChooseConfig(m_eglDisplay, attrList, &m_eglConfig, 1, &numConfig))
|
||||||
|
logFatal("Failed to choose EGL config");
|
||||||
|
|
||||||
|
if(numConfig != 1)
|
||||||
|
logWarning("Didn't got the exact EGL config");
|
||||||
|
|
||||||
|
m_rootWindow = DefaultRootWindow(m_display);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::internalCreateGLContext()
|
||||||
|
{
|
||||||
|
#ifndef OPENGL_ES2
|
||||||
|
m_glxContext = glXCreateContext(m_display, m_visual, NULL, True);
|
||||||
|
if(!m_glxContext)
|
||||||
|
logFatal("Unable to create GLX context");
|
||||||
|
|
||||||
|
if(!glXIsDirect(m_display, m_glxContext))
|
||||||
|
logWarning("GL direct rendering is not possible");
|
||||||
|
#else
|
||||||
|
EGLint attrList[] = {
|
||||||
|
EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||||
|
EGL_NONE
|
||||||
|
};
|
||||||
|
|
||||||
|
m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, attrList);
|
||||||
|
if(m_eglContext == EGL_NO_CONTEXT )
|
||||||
|
logFatal("Unable to create EGL context: ", eglGetError());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::internalDestroyGLContext()
|
||||||
|
{
|
||||||
|
#ifndef OPENGL_ES2
|
||||||
|
glXMakeCurrent(m_display, None, NULL);
|
||||||
|
glXDestroyContext(m_display, m_glxContext);
|
||||||
|
#else
|
||||||
|
eglDestroyContext(m_eglDisplay, m_eglContext);
|
||||||
|
eglDestroySurface(m_eglDisplay, m_eglSurface);
|
||||||
|
eglTerminate(m_eglDisplay);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::internalConnectGLContext()
|
||||||
|
{
|
||||||
|
#ifndef OPENGL_ES2
|
||||||
|
if(!glXMakeCurrent(m_display, m_window, m_glxContext))
|
||||||
|
logFatal("Unable to set GLX context on X11 window");
|
||||||
|
#else
|
||||||
|
m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, m_window, NULL);
|
||||||
|
if(m_eglSurface == EGL_NO_SURFACE)
|
||||||
|
logFatal("Unable to create EGL surface: ", eglGetError());
|
||||||
|
if(!eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext))
|
||||||
|
logFatal("Unable to connect EGL context into X11 window");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void *X11Window::getExtensionProcAddress(const char *ext)
|
||||||
|
{
|
||||||
|
#ifndef OPENGL_ES2
|
||||||
|
return (void *)glXGetProcAddressARB((const GLubyte*)ext);
|
||||||
|
#else
|
||||||
|
//TODO
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X11Window::isExtensionSupported(const char *ext)
|
||||||
|
{
|
||||||
|
#ifndef OPENGL_ES2
|
||||||
|
const char *exts = glXQueryExtensionsString(m_display, m_screen);
|
||||||
|
if(strstr(exts, ext))
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
//TODO
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::move(const Point& pos)
|
||||||
|
{
|
||||||
|
XMoveWindow(m_display, m_window, pos.x, pos.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::resize(const Size& size)
|
||||||
|
{
|
||||||
|
XResizeWindow(m_display, m_window, size.width(), size.height());
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::show()
|
||||||
|
{
|
||||||
|
XMapWindow(m_display, m_window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::hide()
|
||||||
|
{
|
||||||
|
XUnmapWindow(m_display, m_window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::maximize()
|
||||||
|
{
|
||||||
|
Atom wmState = XInternAtom(m_display, "_NET_WM_STATE", False);
|
||||||
|
Atom wmStateMaximizedVert = XInternAtom(m_display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
|
||||||
|
Atom wmStateMaximizedHorz = XInternAtom(m_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
|
||||||
|
|
||||||
|
XEvent e = {0};
|
||||||
|
e.xany.type = ClientMessage;
|
||||||
|
e.xclient.send_event = True;
|
||||||
|
e.xclient.message_type = wmState;
|
||||||
|
e.xclient.format = 32;
|
||||||
|
e.xclient.window = m_window;
|
||||||
|
e.xclient.data.l[0] = 1;
|
||||||
|
e.xclient.data.l[1] = wmStateMaximizedVert;
|
||||||
|
e.xclient.data.l[2] = wmStateMaximizedHorz;
|
||||||
|
e.xclient.data.l[3] = 0;
|
||||||
|
|
||||||
|
XSendEvent(m_display, m_rootWindow, 0, SubstructureNotifyMask | SubstructureRedirectMask, &e);
|
||||||
|
XFlush(m_display);
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::poll()
|
||||||
|
{
|
||||||
|
bool needsResizeUpdate = false;
|
||||||
|
|
||||||
|
XEvent event, peekEvent;
|
||||||
|
while(XPending(m_display) > 0) {
|
||||||
|
XNextEvent(m_display, &event);
|
||||||
|
|
||||||
|
// call filter because xim will discard KeyPress events when keys still composing
|
||||||
|
if(XFilterEvent(&event, m_window))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// discard events of repeated key releases
|
||||||
|
if(event.type == KeyRelease && XPending(m_display)) {
|
||||||
|
XPeekEvent(m_display, &peekEvent);
|
||||||
|
if((peekEvent.type == KeyPress) &&
|
||||||
|
(peekEvent.xkey.keycode == event.xkey.keycode) &&
|
||||||
|
((peekEvent.xkey.time-event.xkey.time) < 2))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset inputEvent values, except keyboardModifiers and mousePos
|
||||||
|
m_inputEvent.type = Fw::NoInputEvent;
|
||||||
|
m_inputEvent.mouseButton = Fw::MouseNoButton;
|
||||||
|
m_inputEvent.keyCode = Fw::KeyUnknown;
|
||||||
|
m_inputEvent.keyText = "";
|
||||||
|
m_inputEvent.mouseMoved = Point();
|
||||||
|
m_inputEvent.wheelDirection = Fw::MouseNoWheel;
|
||||||
|
|
||||||
|
switch(event.type) {
|
||||||
|
case ClientMessage: {
|
||||||
|
// close event
|
||||||
|
if((Atom)event.xclient.data.l[0] == m_wmDelete && m_onClose)
|
||||||
|
m_onClose();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ConfigureNotify: {
|
||||||
|
Size newSize(event.xconfigure.width, event.xconfigure.height);
|
||||||
|
Point newPos(event.xconfigure.x, event.xconfigure.y);
|
||||||
|
|
||||||
|
// updates window size
|
||||||
|
if(m_size != newSize) {
|
||||||
|
m_size = newSize;
|
||||||
|
needsResizeUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// updates window pos
|
||||||
|
if(m_pos != newPos && !isMaximized())
|
||||||
|
m_pos = newPos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SelectionRequest: {
|
||||||
|
XEvent respond;
|
||||||
|
XSelectionRequestEvent *req = &(event.xselectionrequest);
|
||||||
|
|
||||||
|
Atom targets = XInternAtom(m_display, "TARGETS", False);
|
||||||
|
if(req->target == targets) {
|
||||||
|
Atom typeList[] = { XInternAtom(m_display, "UTF8_STRING", False),
|
||||||
|
XInternAtom(m_display, "TEXT", False),
|
||||||
|
XInternAtom(m_display, "COMPOUND_TEXT", False),
|
||||||
|
XA_STRING };
|
||||||
|
|
||||||
|
XChangeProperty(m_display, req->requestor,
|
||||||
|
req->property, req->target,
|
||||||
|
8, PropModeReplace,
|
||||||
|
(uchar *)&typeList,
|
||||||
|
sizeof(typeList));
|
||||||
|
respond.xselection.property = req->property;
|
||||||
|
} else {
|
||||||
|
XChangeProperty(m_display,
|
||||||
|
req->requestor,
|
||||||
|
req->property, req->target,
|
||||||
|
8,
|
||||||
|
PropModeReplace,
|
||||||
|
(uchar *)m_clipboardText.c_str(),
|
||||||
|
m_clipboardText.length());
|
||||||
|
respond.xselection.property = req->property;
|
||||||
|
}
|
||||||
|
|
||||||
|
respond.xselection.type = SelectionNotify;
|
||||||
|
respond.xselection.display = req->display;
|
||||||
|
respond.xselection.requestor = req->requestor;
|
||||||
|
respond.xselection.selection = req->selection;
|
||||||
|
respond.xselection.target = req->target;
|
||||||
|
respond.xselection.time = req->time;
|
||||||
|
XSendEvent(m_display, req->requestor, 0, 0, &respond);
|
||||||
|
XFlush(m_display);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case KeyPress:
|
||||||
|
case KeyRelease: {
|
||||||
|
KeySym keysym;
|
||||||
|
char buf[32];
|
||||||
|
int len;
|
||||||
|
|
||||||
|
m_inputEvent.keyboardModifiers = 0;
|
||||||
|
if(event.xkey.state & ControlMask)
|
||||||
|
m_inputEvent.keyboardModifiers |= Fw::KeyboardCtrlModifier;
|
||||||
|
if(event.xkey.state & ShiftMask)
|
||||||
|
m_inputEvent.keyboardModifiers |= Fw::KeyboardShiftModifier;
|
||||||
|
if(event.xkey.state & Mod1Mask)
|
||||||
|
m_inputEvent.keyboardModifiers |= Fw::KeyboardAltModifier;
|
||||||
|
|
||||||
|
// lookup for keyText
|
||||||
|
if(event.type == KeyPress && !(event.xkey.state & ControlMask) && !(event.xkey.state & Mod1Mask)) {
|
||||||
|
if(m_xic) { // with xim we can get latin1 input correctly
|
||||||
|
Status status;
|
||||||
|
len = XmbLookupString(m_xic, &event.xkey, buf, sizeof(buf), &keysym, &status);
|
||||||
|
} else { // otherwise use XLookupString, but often it doesn't work right with dead keys
|
||||||
|
static XComposeStatus compose = {NULL, 0};
|
||||||
|
len = XLookupString(&event.xkey, buf, sizeof(buf), &keysym, &compose);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(len > 0 &&
|
||||||
|
// these keys produces characters that we don't want to capture
|
||||||
|
keysym != XK_BackSpace &&
|
||||||
|
keysym != XK_Return &&
|
||||||
|
keysym != XK_Delete &&
|
||||||
|
keysym != XK_Escape &&
|
||||||
|
(uchar)(buf[0]) >= 32
|
||||||
|
) {
|
||||||
|
//logDebug("char: ", buf[0], " code: ", (uint)buf[0]);
|
||||||
|
m_inputEvent.keyText = buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_keyMap.find(keysym) != m_keyMap.end())
|
||||||
|
m_inputEvent.keyCode = m_keyMap[keysym];
|
||||||
|
|
||||||
|
m_inputEvent.type = (event.type == KeyPress) ? Fw::KeyPressInputEvent : Fw::KeyReleaseInputEvent;
|
||||||
|
if(m_inputEvent.keyCode != Fw::KeyUnknown || !m_inputEvent.keyText.empty())
|
||||||
|
m_onInputEvent(m_inputEvent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ButtonPress:
|
||||||
|
case ButtonRelease: {
|
||||||
|
m_inputEvent.type = (event.type == ButtonPress) ? Fw::MousePressInputEvent : Fw::MouseReleaseInputEvent;
|
||||||
|
switch(event.xbutton.button) {
|
||||||
|
case Button1:
|
||||||
|
m_inputEvent.mouseButton = Fw::MouseLeftButton;
|
||||||
|
break;
|
||||||
|
case Button3:
|
||||||
|
m_inputEvent.mouseButton = Fw::MouseRightButton;
|
||||||
|
break;
|
||||||
|
case Button2:
|
||||||
|
m_inputEvent.mouseButton = Fw::MouseMidButton;
|
||||||
|
break;
|
||||||
|
case Button4:
|
||||||
|
m_inputEvent.type = Fw::MouseWheelInputEvent;
|
||||||
|
m_inputEvent.mouseButton = Fw::MouseMidButton;
|
||||||
|
m_inputEvent.wheelDirection = Fw::MouseWheelUp;
|
||||||
|
break;
|
||||||
|
case Button5:
|
||||||
|
m_inputEvent.type = Fw::MouseWheelInputEvent;
|
||||||
|
m_inputEvent.mouseButton = Fw::MouseMidButton;
|
||||||
|
m_inputEvent.wheelDirection = Fw::MouseWheelDown;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
m_inputEvent.type = Fw::NoInputEvent;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(m_inputEvent.type != Fw::NoInputEvent && m_onInputEvent)
|
||||||
|
m_onInputEvent(m_inputEvent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MotionNotify: {
|
||||||
|
m_inputEvent.type = Fw::MouseMoveInputEvent;
|
||||||
|
Point newMousePos(event.xbutton.x, event.xbutton.y);
|
||||||
|
m_inputEvent.mouseMoved = newMousePos - m_inputEvent.mousePos;
|
||||||
|
m_inputEvent.mousePos = newMousePos;
|
||||||
|
if(m_onInputEvent)
|
||||||
|
m_onInputEvent(m_inputEvent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MapNotify:
|
||||||
|
m_visible = true;
|
||||||
|
break;
|
||||||
|
case UnmapNotify:
|
||||||
|
m_visible = false;
|
||||||
|
break;
|
||||||
|
case FocusIn:
|
||||||
|
m_focused = true;
|
||||||
|
break;
|
||||||
|
case FocusOut:
|
||||||
|
m_focused = false;
|
||||||
|
break;
|
||||||
|
case Expose:
|
||||||
|
// window needs redraw
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(needsResizeUpdate && m_onResize)
|
||||||
|
m_onResize(m_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::swapBuffers()
|
||||||
|
{
|
||||||
|
#ifndef OPENGL_ES2
|
||||||
|
glXSwapBuffers(m_display, m_window);
|
||||||
|
#else
|
||||||
|
eglSwapBuffers(m_eglDisplay, m_eglSurface);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::showMouse()
|
||||||
|
{
|
||||||
|
XUndefineCursor(m_display, m_window);
|
||||||
|
if(m_cursor != None) {
|
||||||
|
XFreeCursor(m_display, m_cursor);
|
||||||
|
m_cursor = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::hideMouse()
|
||||||
|
{
|
||||||
|
if(m_cursor == None) {
|
||||||
|
char bm[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||||
|
Pixmap pix = XCreateBitmapFromData(m_display, m_window, bm, 8, 8);
|
||||||
|
XColor black = {0};
|
||||||
|
black.flags = DoRed | DoGreen | DoBlue;
|
||||||
|
m_cursor = XCreatePixmapCursor(m_display, pix, pix, &black, &black, 0, 0);
|
||||||
|
XFreePixmap(m_display, pix);
|
||||||
|
}
|
||||||
|
XDefineCursor(m_display, m_window, m_cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::setTitle(const std::string& title)
|
||||||
|
{
|
||||||
|
XStoreName(m_display, m_window, title.c_str());
|
||||||
|
XSetIconName(m_display, m_window, title.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::setMinimumSize(const Size& minimumSize)
|
||||||
|
{
|
||||||
|
XSizeHints sizeHints = {0};
|
||||||
|
sizeHints.flags = PMinSize;
|
||||||
|
sizeHints.min_width = minimumSize.width();
|
||||||
|
sizeHints.min_height= minimumSize.height();
|
||||||
|
XSetWMSizeHints(m_display, m_window, &sizeHints, XA_WM_NORMAL_HINTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::setFullscreen(bool fullscreen)
|
||||||
|
{
|
||||||
|
if(m_fullscreen != fullscreen) {
|
||||||
|
Atom wmState = XInternAtom(m_display, "_NET_WM_STATE", False);
|
||||||
|
Atom wmStateFullscreen = XInternAtom(m_display, "_NET_WM_STATE_FULLSCREEN", False);
|
||||||
|
|
||||||
|
XEvent xev;
|
||||||
|
xev.xclient.type = ClientMessage;
|
||||||
|
xev.xclient.serial = 0;
|
||||||
|
xev.xclient.send_event = True;
|
||||||
|
xev.xclient.window = m_window;
|
||||||
|
xev.xclient.message_type = wmState;
|
||||||
|
xev.xclient.format = 32;
|
||||||
|
xev.xclient.data.l[0] = fullscreen ? 1 : 0;
|
||||||
|
xev.xclient.data.l[1] = wmStateFullscreen;
|
||||||
|
xev.xclient.data.l[2] = 0;
|
||||||
|
|
||||||
|
XSendEvent(m_display, m_rootWindow, False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
|
||||||
|
XFlush(m_display);
|
||||||
|
|
||||||
|
m_fullscreen = fullscreen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::setVerticalSync(bool enable)
|
||||||
|
{
|
||||||
|
#ifndef OPENGL_ES2
|
||||||
|
typedef GLint (*glSwapIntervalProc)(GLint);
|
||||||
|
glSwapIntervalProc glSwapInterval = NULL;
|
||||||
|
|
||||||
|
if(isExtensionSupported("GLX_MESA_swap_control"))
|
||||||
|
glSwapInterval = (glSwapIntervalProc)getExtensionProcAddress("glXSwapIntervalMESA");
|
||||||
|
else if(isExtensionSupported("GLX_SGI_swap_control"))
|
||||||
|
glSwapInterval = (glSwapIntervalProc)getExtensionProcAddress("glXSwapIntervalSGI");
|
||||||
|
|
||||||
|
if(glSwapInterval)
|
||||||
|
glSwapInterval(enable ? 1 : 0);
|
||||||
|
#else
|
||||||
|
//TODO
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::setIcon(const std::string& iconFile)
|
||||||
|
{
|
||||||
|
std::stringstream fin;
|
||||||
|
g_resources.loadFile(iconFile, fin);
|
||||||
|
|
||||||
|
apng_data apng;
|
||||||
|
if(load_apng(fin, &apng) != 0) {
|
||||||
|
logError("Unable to load window icon");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(apng.bpp != 4) {
|
||||||
|
logError("Could not set window icon, icon image must have 4 channels");
|
||||||
|
free_apng(&apng);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int n = apng.width * apng.height;
|
||||||
|
std::vector<unsigned long int> iconData(n + 2);
|
||||||
|
iconData[0] = apng.width;
|
||||||
|
iconData[1] = apng.height;
|
||||||
|
for(int i=0; i < n;++i) {
|
||||||
|
uint8 *pixel = (uint8*)&iconData[2 + i];
|
||||||
|
pixel[2] = *(apng.pdata + (i * 4) + 0);
|
||||||
|
pixel[1] = *(apng.pdata + (i * 4) + 1);
|
||||||
|
pixel[0] = *(apng.pdata + (i * 4) + 2);
|
||||||
|
pixel[3] = *(apng.pdata + (i * 4) + 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
Atom property = XInternAtom(m_display, "_NET_WM_ICON", 0);
|
||||||
|
if(!XChangeProperty(m_display, m_window, property, XA_CARDINAL, 32, PropModeReplace, (const unsigned char*)&iconData[0], iconData.size()))
|
||||||
|
logError("Couldn't set app icon");
|
||||||
|
|
||||||
|
free_apng(&apng);
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11Window::setClipboardText(const std::string& text)
|
||||||
|
{
|
||||||
|
m_clipboardText = text;
|
||||||
|
Atom clipboard = XInternAtom(m_display, "CLIPBOARD", False);
|
||||||
|
XSetSelectionOwner(m_display, clipboard, m_window, CurrentTime);
|
||||||
|
XFlush(m_display);
|
||||||
|
}
|
||||||
|
|
||||||
|
Size X11Window::getDisplaySize()
|
||||||
|
{
|
||||||
|
return Size(XDisplayWidth(m_display, m_screen), XDisplayHeight(m_display, m_screen));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string X11Window::getClipboardText()
|
||||||
|
{
|
||||||
|
Atom clipboard = XInternAtom(m_display, "CLIPBOARD", False);
|
||||||
|
Window ownerWindow = XGetSelectionOwner(m_display, clipboard);
|
||||||
|
if(ownerWindow == m_window)
|
||||||
|
return m_clipboardText;
|
||||||
|
|
||||||
|
std::string clipboardText;
|
||||||
|
if(ownerWindow != None) {
|
||||||
|
XConvertSelection(m_display, clipboard, XA_STRING, 0, ownerWindow, CurrentTime);
|
||||||
|
XFlush(m_display);
|
||||||
|
|
||||||
|
// hack to wait SelectioNotify event, otherwise we will get wrong clipboard pastes
|
||||||
|
// TODO: fix this in a correct way
|
||||||
|
usleep(100 * 1000);
|
||||||
|
|
||||||
|
// check for data
|
||||||
|
Atom type;
|
||||||
|
int format;
|
||||||
|
ulong numItems, bytesLeft, dummy;
|
||||||
|
uchar *data;
|
||||||
|
XGetWindowProperty(m_display, ownerWindow,
|
||||||
|
XA_STRING,
|
||||||
|
0, 0, 0,
|
||||||
|
AnyPropertyType,
|
||||||
|
&type,
|
||||||
|
&format,
|
||||||
|
&numItems,
|
||||||
|
&bytesLeft,
|
||||||
|
&data);
|
||||||
|
if(bytesLeft > 0) {
|
||||||
|
// get the data get
|
||||||
|
int result = XGetWindowProperty(m_display, ownerWindow,
|
||||||
|
XA_STRING,
|
||||||
|
0,
|
||||||
|
bytesLeft,
|
||||||
|
0,
|
||||||
|
AnyPropertyType,
|
||||||
|
&type,
|
||||||
|
&format,
|
||||||
|
&numItems,
|
||||||
|
&dummy,
|
||||||
|
&data);
|
||||||
|
if(result == Success)
|
||||||
|
clipboardText = (const char*)data;
|
||||||
|
XFree(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return clipboardText;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X11Window::isMaximized()
|
||||||
|
{
|
||||||
|
Atom wmState = XInternAtom(m_display, "_NET_WM_STATE", False);
|
||||||
|
Atom wmStateMaximizedVert = XInternAtom(m_display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
|
||||||
|
Atom wmStateMaximizedHorz = XInternAtom(m_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
|
||||||
|
Atom actualType;
|
||||||
|
ulong i, numItems, bytesAfter;
|
||||||
|
uchar *propertyValue = NULL;
|
||||||
|
int actualFormat;
|
||||||
|
bool maximized = false;
|
||||||
|
|
||||||
|
if(XGetWindowProperty(m_display, m_window, wmState,
|
||||||
|
0, 1024, False, XA_ATOM, &actualType,
|
||||||
|
&actualFormat, &numItems, &bytesAfter,
|
||||||
|
&propertyValue) == Success) {
|
||||||
|
Atom *atoms = (Atom*)propertyValue;
|
||||||
|
int maximizedMask = 0;
|
||||||
|
|
||||||
|
for(i=0; i<numItems; ++i) {
|
||||||
|
if(atoms[i] == wmStateMaximizedVert)
|
||||||
|
maximizedMask |= 1;
|
||||||
|
else if(atoms[i] == wmStateMaximizedHorz)
|
||||||
|
maximizedMask |= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(maximizedMask == 3)
|
||||||
|
maximizedMask = true;
|
||||||
|
|
||||||
|
XFree(propertyValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return maximized;
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/otclient>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef X11WINDOW_H
|
||||||
|
#define X11WINDOW_H
|
||||||
|
|
||||||
|
#include "platformwindow.h"
|
||||||
|
#include <framework/graphics/glutil.h>
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xatom.h>
|
||||||
|
|
||||||
|
#ifndef OPENGL_ES2
|
||||||
|
#include <GL/glx.h>
|
||||||
|
#else
|
||||||
|
#include <EGL/egl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class X11Window : public PlatformWindow
|
||||||
|
{
|
||||||
|
void internalOpenDisplay();
|
||||||
|
void internalCreateWindow();
|
||||||
|
bool internalSetupWindowInput();
|
||||||
|
|
||||||
|
void internalCheckGL();
|
||||||
|
void internalChooseGLVisual();
|
||||||
|
void internalCreateGLContext();
|
||||||
|
void internalDestroyGLContext();
|
||||||
|
void internalConnectGLContext();
|
||||||
|
|
||||||
|
void *getExtensionProcAddress(const char *ext);
|
||||||
|
bool isExtensionSupported(const char *ext);
|
||||||
|
|
||||||
|
public:
|
||||||
|
X11Window();
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void terminate();
|
||||||
|
|
||||||
|
void move(const Point& pos);
|
||||||
|
void resize(const Size& size);
|
||||||
|
void show();
|
||||||
|
void hide();
|
||||||
|
void maximize();
|
||||||
|
void poll();
|
||||||
|
void swapBuffers();
|
||||||
|
void showMouse();
|
||||||
|
void hideMouse();
|
||||||
|
|
||||||
|
void setTitle(const std::string& title);
|
||||||
|
void setMinimumSize(const Size& minimumSize);
|
||||||
|
void setFullscreen(bool fullscreen);
|
||||||
|
void setVerticalSync(bool enable);
|
||||||
|
void setIcon(const std::string& iconFile);
|
||||||
|
void setClipboardText(const std::string& text);
|
||||||
|
|
||||||
|
Size getDisplaySize();
|
||||||
|
std::string getClipboardText();
|
||||||
|
|
||||||
|
bool isMaximized();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Display *m_display;
|
||||||
|
XVisualInfo *m_visual;
|
||||||
|
Window m_window;
|
||||||
|
Window m_rootWindow;
|
||||||
|
Colormap m_colormap;
|
||||||
|
Cursor m_cursor;
|
||||||
|
XIM m_xim;
|
||||||
|
XIC m_xic;
|
||||||
|
int m_screen;
|
||||||
|
Atom m_wmDelete;
|
||||||
|
std::string m_clipboardText;
|
||||||
|
std::map<int, Fw::Key> m_keyMap;
|
||||||
|
|
||||||
|
#ifndef OPENGL_ES2
|
||||||
|
GLXContext m_glxContext;
|
||||||
|
#else
|
||||||
|
EGLConfig m_eglConfig;
|
||||||
|
EGLContext m_eglContext;
|
||||||
|
EGLDisplay m_eglDisplay;
|
||||||
|
EGLSurface m_eglSurface;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -40,13 +40,12 @@ void UIFrameCounter::render()
|
||||||
{
|
{
|
||||||
UIWidget::render();
|
UIWidget::render();
|
||||||
|
|
||||||
int now = g_clock.ticks();
|
if(g_clock.ticksElapsed(m_lastFrameTicks) >= 1000) {
|
||||||
if(now - m_lastFrameTicks >= 1000) {
|
|
||||||
m_fpsText = Fw::mkstr("FPS: ", m_frameCount);
|
m_fpsText = Fw::mkstr("FPS: ", m_frameCount);
|
||||||
m_lastFrameTicks = now;
|
m_lastFrameTicks = g_clock.ticks();
|
||||||
m_frameCount = 0;
|
m_frameCount = 0;
|
||||||
} else
|
}
|
||||||
m_frameCount++;
|
m_frameCount++;
|
||||||
|
|
||||||
m_font->renderText(m_fpsText, m_rect, m_align, Fw::white);
|
m_font->renderText(m_fpsText, m_rect, m_align, Fw::white);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ protected:
|
||||||
private:
|
private:
|
||||||
Fw::AlignmentFlag m_align;
|
Fw::AlignmentFlag m_align;
|
||||||
int m_frameCount;
|
int m_frameCount;
|
||||||
int m_lastFrameTicks;
|
ticks_t m_lastFrameTicks;
|
||||||
std::string m_fpsText;
|
std::string m_fpsText;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include "uilineedit.h"
|
#include "uilineedit.h"
|
||||||
#include <framework/graphics/font.h>
|
#include <framework/graphics/font.h>
|
||||||
#include <framework/graphics/graphics.h>
|
#include <framework/graphics/graphics.h>
|
||||||
#include <framework/platform/platform.h>
|
#include <framework/platform/platformwindow.h>
|
||||||
#include <framework/core/clock.h>
|
#include <framework/core/clock.h>
|
||||||
#include <framework/otml/otmlnode.h>
|
#include <framework/otml/otmlnode.h>
|
||||||
|
|
||||||
|
@ -56,8 +56,7 @@ void UILineEdit::render()
|
||||||
assert(m_cursorPos <= textLength);
|
assert(m_cursorPos <= textLength);
|
||||||
// draw every 333ms
|
// draw every 333ms
|
||||||
const int delay = 333;
|
const int delay = 333;
|
||||||
int ticks = g_clock.ticks();
|
if(g_clock.ticksElapsed(m_cursorTicks) <= delay) {
|
||||||
if(ticks - m_cursorTicks <= delay) {
|
|
||||||
Rect cursorRect;
|
Rect cursorRect;
|
||||||
// when cursor is at 0 or is the first visible element
|
// when cursor is at 0 or is the first visible element
|
||||||
if(m_cursorPos == 0 || m_cursorPos == m_startRenderPos)
|
if(m_cursorPos == 0 || m_cursorPos == m_startRenderPos)
|
||||||
|
@ -65,8 +64,8 @@ void UILineEdit::render()
|
||||||
else
|
else
|
||||||
cursorRect = Rect(m_glyphsCoords[m_cursorPos-1].right(), m_glyphsCoords[m_cursorPos-1].top(), 1, m_font->getGlyphHeight());
|
cursorRect = Rect(m_glyphsCoords[m_cursorPos-1].right(), m_glyphsCoords[m_cursorPos-1].top(), 1, m_font->getGlyphHeight());
|
||||||
g_graphics.drawFilledRect(cursorRect);
|
g_graphics.drawFilledRect(cursorRect);
|
||||||
} else if(ticks - m_cursorTicks >= 2*delay) {
|
} else if(g_clock.ticksElapsed(m_cursorTicks) >= 2*delay) {
|
||||||
m_cursorTicks = ticks;
|
m_cursorTicks = g_clock.ticks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -407,7 +406,7 @@ void UILineEdit::onFocusChange(bool focused, Fw::FocusReason reason)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UILineEdit::onKeyPress(uchar keyCode, char keyChar, int keyboardModifiers)
|
bool UILineEdit::onKeyPress(uchar keyCode, std::string keyText, int keyboardModifiers)
|
||||||
{
|
{
|
||||||
if(keyCode == Fw::KeyDelete) // erase right character
|
if(keyCode == Fw::KeyDelete) // erase right character
|
||||||
removeCharacter(true);
|
removeCharacter(true);
|
||||||
|
@ -422,14 +421,14 @@ bool UILineEdit::onKeyPress(uchar keyCode, char keyChar, int keyboardModifiers)
|
||||||
else if(keyCode == Fw::KeyEnd) // move cursor to last character
|
else if(keyCode == Fw::KeyEnd) // move cursor to last character
|
||||||
setCursorPos(m_text.length());
|
setCursorPos(m_text.length());
|
||||||
else if(keyCode == Fw::KeyV && keyboardModifiers == Fw::KeyboardCtrlModifier)
|
else if(keyCode == Fw::KeyV && keyboardModifiers == Fw::KeyboardCtrlModifier)
|
||||||
appendText(g_platform.getClipboardText());
|
appendText(g_window.getClipboardText());
|
||||||
else if(keyCode == Fw::KeyTab) {
|
else if(keyCode == Fw::KeyTab) {
|
||||||
if(!m_alwaysActive) {
|
if(!m_alwaysActive) {
|
||||||
if(UIWidgetPtr parent = getParent())
|
if(UIWidgetPtr parent = getParent())
|
||||||
parent->focusNextChild(Fw::TabFocusReason);
|
parent->focusNextChild(Fw::TabFocusReason);
|
||||||
}
|
}
|
||||||
} else if(keyChar != 0)
|
} else if(!keyText.empty())
|
||||||
appendCharacter(keyChar);
|
appendText(keyText);
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ protected:
|
||||||
virtual void onStyleApply(const OTMLNodePtr& styleNode);
|
virtual void onStyleApply(const OTMLNodePtr& styleNode);
|
||||||
virtual void onGeometryUpdate(const Rect& oldRect, const Rect& newRect);
|
virtual void onGeometryUpdate(const Rect& oldRect, const Rect& newRect);
|
||||||
virtual void onFocusChange(bool focused, Fw::FocusReason reason);
|
virtual void onFocusChange(bool focused, Fw::FocusReason reason);
|
||||||
virtual bool onKeyPress(uchar keyCode, char keyChar, int keyboardModifiers);
|
virtual bool onKeyPress(uchar keyCode, std::string keyText, int keyboardModifiers);
|
||||||
virtual bool onMousePress(const Point& mousePos, Fw::MouseButton button);
|
virtual bool onMousePress(const Point& mousePos, Fw::MouseButton button);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -68,7 +68,7 @@ private:
|
||||||
int m_cursorPos;
|
int m_cursorPos;
|
||||||
Point m_startInternalPos;
|
Point m_startInternalPos;
|
||||||
int m_startRenderPos;
|
int m_startRenderPos;
|
||||||
int m_cursorTicks;
|
ticks_t m_cursorTicks;
|
||||||
int m_textHorizontalMargin;
|
int m_textHorizontalMargin;
|
||||||
bool m_textHidden;
|
bool m_textHidden;
|
||||||
bool m_alwaysActive;
|
bool m_alwaysActive;
|
||||||
|
|
|
@ -50,56 +50,32 @@ void UIManager::render()
|
||||||
|
|
||||||
void UIManager::resize(const Size& size)
|
void UIManager::resize(const Size& size)
|
||||||
{
|
{
|
||||||
if(m_rootWidget)
|
m_rootWidget->resize(g_graphics.getScreenSize());
|
||||||
m_rootWidget->resize(g_graphics.getScreenSize());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UIManager::inputEvent(const PlatformEvent& event)
|
void UIManager::inputEvent(const InputEvent& event)
|
||||||
{
|
{
|
||||||
// translate input event to ui events
|
switch(event.type) {
|
||||||
if(m_rootWidget) {
|
case Fw::KeyPressInputEvent:
|
||||||
if(event.type & EventKeyboardAction) {
|
m_rootWidget->onKeyPress(event.keyCode, event.keyText, event.keyboardModifiers);
|
||||||
int keyboardModifiers = Fw::KeyboardNoModifier;
|
break;
|
||||||
if(event.ctrl)
|
case Fw::KeyReleaseInputEvent:
|
||||||
keyboardModifiers |= Fw::KeyboardCtrlModifier;
|
m_rootWidget->onKeyRelease(event.keyCode, event.keyText, event.keyboardModifiers);
|
||||||
if(event.shift)
|
break;
|
||||||
keyboardModifiers |= Fw::KeyboardShiftModifier;
|
case Fw::MousePressInputEvent:
|
||||||
if(event.alt)
|
m_rootWidget->onMousePress(event.mousePos, event.mouseButton);
|
||||||
keyboardModifiers |= Fw::KeyboardAltModifier;
|
break;
|
||||||
|
case Fw::MouseReleaseInputEvent:
|
||||||
if(event.type == EventKeyDown)
|
m_rootWidget->onMouseRelease(event.mousePos, event.mouseButton);
|
||||||
m_rootWidget->onKeyPress(event.keycode, event.keychar, keyboardModifiers);
|
break;
|
||||||
else
|
case Fw::MouseMoveInputEvent:
|
||||||
m_rootWidget->onKeyRelease(event.keycode, event.keychar, keyboardModifiers);
|
m_rootWidget->updateState(Fw::HoverState);
|
||||||
} else if(event.type & EventMouseAction) {
|
m_rootWidget->onMouseMove(event.mousePos, event.mouseMoved);
|
||||||
if(event.type == EventMouseMove) {
|
break;
|
||||||
m_rootWidget->updateState(Fw::HoverState);
|
case Fw::MouseWheelInputEvent:
|
||||||
m_rootWidget->onMouseMove(event.mousePos, event.mouseMoved);
|
m_rootWidget->onMouseWheel(event.mousePos, event.wheelDirection);
|
||||||
}
|
break;
|
||||||
else if(event.type & EventMouseWheel) {
|
};
|
||||||
Fw::MouseWheelDirection dir = Fw::MouseNoWheel;
|
|
||||||
if(event.type & EventDown)
|
|
||||||
dir = Fw::MouseWheelDown;
|
|
||||||
else if(event.type & EventUp)
|
|
||||||
dir = Fw::MouseWheelUp;
|
|
||||||
|
|
||||||
m_rootWidget->onMouseWheel(event.mousePos, dir);
|
|
||||||
} else {
|
|
||||||
Fw::MouseButton button = Fw::MouseNoButton;
|
|
||||||
if(event.type & EventMouseLeftButton)
|
|
||||||
button = Fw::MouseLeftButton;
|
|
||||||
else if(event.type & EventMouseMidButton)
|
|
||||||
button = Fw::MouseMidButton;
|
|
||||||
else if(event.type & EventMouseRightButton)
|
|
||||||
button = Fw::MouseRightButton;
|
|
||||||
|
|
||||||
if(event.type & EventDown)
|
|
||||||
m_rootWidget->onMousePress(event.mousePos, button);
|
|
||||||
else if(event.type & EventUp)
|
|
||||||
m_rootWidget->onMouseRelease(event.mousePos, button);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UIManager::importStyles(const std::string& file)
|
bool UIManager::importStyles(const std::string& file)
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#define UIMANAGER_H
|
#define UIMANAGER_H
|
||||||
|
|
||||||
#include "declarations.h"
|
#include "declarations.h"
|
||||||
#include <framework/platform/platformevent.h>
|
#include <framework/core/inputevent.h>
|
||||||
#include <framework/otml/declarations.h>
|
#include <framework/otml/declarations.h>
|
||||||
|
|
||||||
class UIManager
|
class UIManager
|
||||||
|
@ -35,7 +35,7 @@ public:
|
||||||
|
|
||||||
void render();
|
void render();
|
||||||
void resize(const Size& size);
|
void resize(const Size& size);
|
||||||
void inputEvent(const PlatformEvent& event);
|
void inputEvent(const InputEvent& event);
|
||||||
|
|
||||||
bool importStyles(const std::string& file);
|
bool importStyles(const std::string& file);
|
||||||
void importStyleFromOTML(const OTMLNodePtr& styleNode);
|
void importStyleFromOTML(const OTMLNodePtr& styleNode);
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
#include <framework/graphics/fontmanager.h>
|
#include <framework/graphics/fontmanager.h>
|
||||||
#include <framework/otml/otmlnode.h>
|
#include <framework/otml/otmlnode.h>
|
||||||
#include <framework/graphics/graphics.h>
|
#include <framework/graphics/graphics.h>
|
||||||
#include <framework/platform/platform.h>
|
#include <framework/platform/platformwindow.h>
|
||||||
|
|
||||||
UIWidget::UIWidget()
|
UIWidget::UIWidget()
|
||||||
{
|
{
|
||||||
|
@ -670,7 +670,7 @@ void UIWidget::updateState(Fw::WidgetState state)
|
||||||
}
|
}
|
||||||
else if(state == Fw::HoverState) {
|
else if(state == Fw::HoverState) {
|
||||||
updateChildren = true;
|
updateChildren = true;
|
||||||
Point mousePos = g_platform.getMouseCursorPos();
|
Point mousePos = g_window.getMousePos();
|
||||||
UIWidgetPtr widget = asUIWidget();
|
UIWidgetPtr widget = asUIWidget();
|
||||||
UIWidgetPtr parent;
|
UIWidgetPtr parent;
|
||||||
do {
|
do {
|
||||||
|
@ -971,9 +971,9 @@ void UIWidget::onHoverChange(bool hovered)
|
||||||
g_ui.getRootWidget()->updateState(Fw::HoverState);
|
g_ui.getRootWidget()->updateState(Fw::HoverState);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UIWidget::onKeyPress(uchar keyCode, char keyChar, int keyboardModifiers)
|
bool UIWidget::onKeyPress(uchar keyCode, std::string keyText, int keyboardModifiers)
|
||||||
{
|
{
|
||||||
if(callLuaField<bool>("onKeyPress", keyCode, keyChar, keyboardModifiers))
|
if(callLuaField<bool>("onKeyPress", keyCode, keyText, keyboardModifiers))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// do a backup of children list, because it may change while looping it
|
// do a backup of children list, because it may change while looping it
|
||||||
|
@ -989,16 +989,16 @@ bool UIWidget::onKeyPress(uchar keyCode, char keyChar, int keyboardModifiers)
|
||||||
}
|
}
|
||||||
|
|
||||||
for(const UIWidgetPtr& child : children) {
|
for(const UIWidgetPtr& child : children) {
|
||||||
if(child->onKeyPress(keyCode, keyChar, keyboardModifiers))
|
if(child->onKeyPress(keyCode, keyText, keyboardModifiers))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UIWidget::onKeyRelease(uchar keyCode, char keyChar, int keyboardModifiers)
|
bool UIWidget::onKeyRelease(uchar keyCode, std::string keyText, int keyboardModifiers)
|
||||||
{
|
{
|
||||||
if(callLuaField<bool>("onKeyRelease", keyCode, keyChar, keyboardModifiers))
|
if(callLuaField<bool>("onKeyRelease", keyCode, keyText, keyboardModifiers))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// do a backup of children list, because it may change while looping it
|
// do a backup of children list, because it may change while looping it
|
||||||
|
@ -1014,7 +1014,7 @@ bool UIWidget::onKeyRelease(uchar keyCode, char keyChar, int keyboardModifiers)
|
||||||
}
|
}
|
||||||
|
|
||||||
for(const UIWidgetPtr& child : children) {
|
for(const UIWidgetPtr& child : children) {
|
||||||
if(child->onKeyRelease(keyCode, keyChar, keyboardModifiers))
|
if(child->onKeyRelease(keyCode, keyText, keyboardModifiers))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -166,9 +166,9 @@ protected:
|
||||||
/// Triggered when the mouse enters or leaves widget area
|
/// Triggered when the mouse enters or leaves widget area
|
||||||
virtual void onHoverChange(bool hovered);
|
virtual void onHoverChange(bool hovered);
|
||||||
/// Triggered when user presses key while widget has focus
|
/// Triggered when user presses key while widget has focus
|
||||||
virtual bool onKeyPress(uchar keyCode, char keyChar, int keyboardModifiers);
|
virtual bool onKeyPress(uchar keyCode, std::string keyText, int keyboardModifiers);
|
||||||
/// Triggered when user releases key while widget has focus
|
/// Triggered when user releases key while widget has focus
|
||||||
virtual bool onKeyRelease(uchar keyCode, char keyChar, int keyboardModifiers);
|
virtual bool onKeyRelease(uchar keyCode, std::string keyText, int keyboardModifiers);
|
||||||
/// Triggered when a mouse button is pressed down while mouse pointer is inside widget area
|
/// Triggered when a mouse button is pressed down while mouse pointer is inside widget area
|
||||||
virtual bool onMousePress(const Point& mousePos, Fw::MouseButton button);
|
virtual bool onMousePress(const Point& mousePos, Fw::MouseButton button);
|
||||||
/// Triggered when a mouse button is released
|
/// Triggered when a mouse button is released
|
||||||
|
|
|
@ -146,7 +146,7 @@ bool UIWindow::onMouseMove(const Point& mousePos, const Point& mouseMoved)
|
||||||
return UIWidget::onMouseMove(mousePos, mouseMoved);
|
return UIWidget::onMouseMove(mousePos, mouseMoved);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UIWindow::onKeyPress(uchar keyCode, char keyChar, int keyboardModifiers)
|
bool UIWindow::onKeyPress(uchar keyCode, std::string keyText, int keyboardModifiers)
|
||||||
{
|
{
|
||||||
if(keyboardModifiers == Fw::KeyboardNoModifier) {
|
if(keyboardModifiers == Fw::KeyboardNoModifier) {
|
||||||
if(keyCode == Fw::KeyReturn || keyCode == Fw::KeyEnter) {
|
if(keyCode == Fw::KeyReturn || keyCode == Fw::KeyEnter) {
|
||||||
|
@ -157,5 +157,5 @@ bool UIWindow::onKeyPress(uchar keyCode, char keyChar, int keyboardModifiers)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return UIWidget::onKeyPress(keyCode, keyChar, keyboardModifiers);
|
return UIWidget::onKeyPress(keyCode, keyText, keyboardModifiers);
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ protected:
|
||||||
virtual bool onMousePress(const Point& mousePos, Fw::MouseButton button);
|
virtual bool onMousePress(const Point& mousePos, Fw::MouseButton button);
|
||||||
virtual void onMouseRelease(const Point& mousePos, Fw::MouseButton button);
|
virtual void onMouseRelease(const Point& mousePos, Fw::MouseButton button);
|
||||||
virtual bool onMouseMove(const Point& mousePos, const Point& mouseMoved);
|
virtual bool onMouseMove(const Point& mousePos, const Point& mouseMoved);
|
||||||
virtual bool onKeyPress(uchar keyCode, char keyChar, int keyboardModifiers);
|
virtual bool onKeyPress(uchar keyCode, std::string keyText, int keyboardModifiers);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_title;
|
std::string m_title;
|
||||||
|
|
|
@ -35,10 +35,13 @@ typedef uint64_t uint64;
|
||||||
typedef uint32_t uint32;
|
typedef uint32_t uint32;
|
||||||
typedef uint16_t uint16;
|
typedef uint16_t uint16;
|
||||||
typedef uint8_t uint8;
|
typedef uint8_t uint8;
|
||||||
|
typedef int64_t int64;
|
||||||
typedef int32_t int32;
|
typedef int32_t int32;
|
||||||
typedef int16_t int16;
|
typedef int16_t int16;
|
||||||
typedef int8_t int8;
|
typedef int8_t int8;
|
||||||
|
|
||||||
|
typedef int64 ticks_t;
|
||||||
|
|
||||||
typedef std::function<void()> SimpleCallback;
|
typedef std::function<void()> SimpleCallback;
|
||||||
typedef std::function<bool()> BooleanCallback;
|
typedef std::function<bool()> BooleanCallback;
|
||||||
|
|
||||||
|
|
35
src/main.cpp
35
src/main.cpp
|
@ -21,39 +21,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <otclient/otclient.h>
|
#include <otclient/otclient.h>
|
||||||
#include <framework/core/eventdispatcher.h>
|
|
||||||
|
|
||||||
#include <csignal>
|
|
||||||
|
|
||||||
void signal_handler(int sig)
|
|
||||||
{
|
|
||||||
static bool signaled = false;
|
|
||||||
switch(sig) {
|
|
||||||
case SIGTERM:
|
|
||||||
case SIGINT:
|
|
||||||
if(!signaled) {
|
|
||||||
signaled = true;
|
|
||||||
g_dispatcher.addEvent(std::bind(&OTClient::onClose, &g_client));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef WIN32_NO_CONSOLE
|
|
||||||
#include <windows.h>
|
|
||||||
int WINAPI WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
|
|
||||||
{
|
|
||||||
std::vector<std::string> args;
|
|
||||||
boost::split(args, lpszArgument, boost::is_any_of(std::string(" ")));
|
|
||||||
#else
|
|
||||||
int main(int argc, const char* argv[])
|
int main(int argc, const char* argv[])
|
||||||
{
|
{
|
||||||
std::vector<std::string> args;
|
std::vector<std::string> args(argv, argv + argc);
|
||||||
for(int i=0; i<argc; ++i)
|
g_otclient.init(args);
|
||||||
args.push_back(argv[i]);
|
g_otclient.run();
|
||||||
#endif
|
g_otclient.terminate();
|
||||||
g_client.init(args);
|
|
||||||
g_client.run();
|
|
||||||
g_client.terminate();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
namespace Otc
|
namespace Otc
|
||||||
{
|
{
|
||||||
static const char* AppName = "OTClient";
|
static const char* AppName = "OTClient";
|
||||||
static const char* AppPathName = "otclient";
|
static const char* AppIdentifierName = "otclient";
|
||||||
static const char* AppVersion = "0.4.0";
|
static const char* AppVersion = "0.4.0";
|
||||||
|
|
||||||
static const char* CipsoftPublicRSA = "1321277432058722840622950990822933849527763264961655079678763618"
|
static const char* CipsoftPublicRSA = "1321277432058722840622950990822933849527763264961655079678763618"
|
||||||
|
|
|
@ -207,7 +207,7 @@ void Creature::walk(const Position& position, bool inverse)
|
||||||
void Creature::updateWalk()
|
void Creature::updateWalk()
|
||||||
{
|
{
|
||||||
if(m_walking) {
|
if(m_walking) {
|
||||||
int elapsedTicks = g_clock.ticks() - m_walkStartTicks;
|
int elapsedTicks = g_clock.ticksElapsed(m_walkStartTicks);
|
||||||
int totalPixelsWalked = std::min((int)round(elapsedTicks / m_walkTimePerPixel), 32);
|
int totalPixelsWalked = std::min((int)round(elapsedTicks / m_walkTimePerPixel), 32);
|
||||||
|
|
||||||
if(m_inverseWalking) {
|
if(m_inverseWalking) {
|
||||||
|
|
|
@ -88,7 +88,7 @@ protected:
|
||||||
FontPtr m_informationFont;
|
FontPtr m_informationFont;
|
||||||
Color m_informationColor;
|
Color m_informationColor;
|
||||||
|
|
||||||
int m_walkStartTicks;
|
ticks_t m_walkStartTicks;
|
||||||
bool m_walking, m_inverseWalking;
|
bool m_walking, m_inverseWalking;
|
||||||
float m_walkTimePerPixel;
|
float m_walkTimePerPixel;
|
||||||
Position m_walkingFromPosition;
|
Position m_walkingFromPosition;
|
||||||
|
|
|
@ -45,7 +45,7 @@ public:
|
||||||
EffectPtr asEffect() { return std::static_pointer_cast<Effect>(shared_from_this()); }
|
EffectPtr asEffect() { return std::static_pointer_cast<Effect>(shared_from_this()); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_animationStartTicks;
|
ticks_t m_animationStartTicks;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -27,17 +27,6 @@
|
||||||
|
|
||||||
Game g_game;
|
Game g_game;
|
||||||
|
|
||||||
void Game::init()
|
|
||||||
{
|
|
||||||
m_online = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Game::terminate()
|
|
||||||
{
|
|
||||||
if(m_online)
|
|
||||||
logout(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Game::loginWorld(const std::string& account, const std::string& password, const std::string& worldHost, int worldPort, const std::string& characterName)
|
void Game::loginWorld(const std::string& account, const std::string& password, const std::string& worldHost, int worldPort, const std::string& characterName)
|
||||||
{
|
{
|
||||||
m_protocolGame = ProtocolGamePtr(new ProtocolGame);
|
m_protocolGame = ProtocolGamePtr(new ProtocolGame);
|
||||||
|
@ -51,12 +40,13 @@ void Game::cancelLogin()
|
||||||
|
|
||||||
void Game::logout(bool force)
|
void Game::logout(bool force)
|
||||||
{
|
{
|
||||||
if(m_protocolGame) {
|
if(!m_protocolGame || !m_online)
|
||||||
m_protocolGame->sendLogout();
|
return;
|
||||||
|
|
||||||
if(force)
|
m_protocolGame->sendLogout();
|
||||||
processLogout();
|
|
||||||
}
|
if(force)
|
||||||
|
processLogout();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::processLoginError(const std::string& error)
|
void Game::processLoginError(const std::string& error)
|
||||||
|
|
|
@ -31,9 +31,6 @@
|
||||||
class Game
|
class Game
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void init();
|
|
||||||
void terminate();
|
|
||||||
|
|
||||||
// login/logout related
|
// login/logout related
|
||||||
void loginWorld(const std::string& account,
|
void loginWorld(const std::string& account,
|
||||||
const std::string& password,
|
const std::string& password,
|
||||||
|
|
|
@ -47,7 +47,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_data;
|
int m_data;
|
||||||
int m_lastTicks;
|
ticks_t m_lastTicks;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -46,7 +46,7 @@ public:
|
||||||
MissilePtr asMissile() { return std::static_pointer_cast<Missile>(shared_from_this()); }
|
MissilePtr asMissile() { return std::static_pointer_cast<Missile>(shared_from_this()); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_startTicks;
|
ticks_t m_startTicks;
|
||||||
Position m_positionDelta;
|
Position m_positionDelta;
|
||||||
float m_duration;
|
float m_duration;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,27 +1,6 @@
|
||||||
/*
|
#include "otclient.h"
|
||||||
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/otclient>
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <otclient/otclient.h>
|
|
||||||
#include <framework/luascript/luainterface.h>
|
#include <framework/luascript/luainterface.h>
|
||||||
|
#include <otclient/luascript/luavaluecasts.h>
|
||||||
#include <otclient/core/game.h>
|
#include <otclient/core/game.h>
|
||||||
#include <otclient/core/tile.h>
|
#include <otclient/core/tile.h>
|
||||||
#include <otclient/core/item.h>
|
#include <otclient/core/item.h>
|
||||||
|
@ -39,12 +18,11 @@
|
||||||
#include <otclient/ui/uigame.h>
|
#include <otclient/ui/uigame.h>
|
||||||
#include <otclient/core/outfit.h>
|
#include <otclient/core/outfit.h>
|
||||||
|
|
||||||
#include "luavaluecasts.h"
|
|
||||||
|
|
||||||
void OTClient::registerLuaFunctions()
|
void OTClient::registerLuaFunctions()
|
||||||
{
|
{
|
||||||
g_lua.bindGlobalFunction("exit", std::bind(&OTClient::exit, &g_client));
|
Application::registerLuaFunctions();
|
||||||
g_lua.bindGlobalFunction("setOnClose", std::bind(&OTClient::setOnClose, &g_client, _1));
|
|
||||||
|
g_lua.bindGlobalFunction("exit", std::bind(&Application::exit, &g_app));
|
||||||
g_lua.bindGlobalFunction("importDat", std::bind(&ThingsType::load, &g_thingsType, _1));
|
g_lua.bindGlobalFunction("importDat", std::bind(&ThingsType::load, &g_thingsType, _1));
|
||||||
g_lua.bindGlobalFunction("importSpr", std::bind(&SpriteManager::load, &g_sprites, _1));
|
g_lua.bindGlobalFunction("importSpr", std::bind(&SpriteManager::load, &g_sprites, _1));
|
||||||
g_lua.bindGlobalFunction("getOufitColor", Outfit::getColor);
|
g_lua.bindGlobalFunction("getOufitColor", Outfit::getColor);
|
|
@ -35,5 +35,4 @@ bool luavalue_cast(int index, Outfit& outfit);
|
||||||
void push_luavalue(const Position& pos);
|
void push_luavalue(const Position& pos);
|
||||||
bool luavalue_cast(int index, Position& pos);
|
bool luavalue_cast(int index, Position& pos);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -251,7 +251,7 @@ void ProtocolGame::parseMessage(InputMessage& msg)
|
||||||
//case Otc::GameServerObjectInfo:
|
//case Otc::GameServerObjectInfo:
|
||||||
//case Otc::GameServerPlayerInventory:
|
//case Otc::GameServerPlayerInventory:
|
||||||
default:
|
default:
|
||||||
Fw::throwException("unknown opt byte ", opt);
|
Fw::throwException("unknown opt byte ", (int)opt);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,304 +1,10 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/otclient>
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "otclient.h"
|
#include "otclient.h"
|
||||||
|
|
||||||
#include <framework/core/modulemanager.h>
|
OTClient g_otclient;
|
||||||
#include <framework/core/configmanager.h>
|
Application& g_app = g_otclient;
|
||||||
#include <framework/core/resourcemanager.h>
|
|
||||||
#include <framework/core/eventdispatcher.h>
|
|
||||||
#include <framework/core/clock.h>
|
|
||||||
#include <framework/luascript/luainterface.h>
|
|
||||||
#include <framework/graphics/graphics.h>
|
|
||||||
#include <framework/graphics/fontmanager.h>
|
|
||||||
#include <framework/ui/uimanager.h>
|
|
||||||
#include <framework/ui/uiwidget.h>
|
|
||||||
#include <framework/net/connection.h>
|
|
||||||
#include <framework/platform/platform.h>
|
|
||||||
#include <otclient/net/protocolgame.h>
|
|
||||||
#include <otclient/core/game.h>
|
|
||||||
#include <otclient/core/map.h>
|
|
||||||
|
|
||||||
OTClient g_client;
|
void OTClient::init(const std::vector<std::string>& args)
|
||||||
|
|
||||||
void OTClient::init(std::vector<std::string> args)
|
|
||||||
{
|
{
|
||||||
m_running = false;
|
|
||||||
m_stopping = false;
|
|
||||||
|
|
||||||
// print client information
|
|
||||||
logInfo(Otc::AppName, " ", Otc::AppVersion);
|
logInfo(Otc::AppName, " ", Otc::AppVersion);
|
||||||
|
Application::init(Otc::AppName, args);
|
||||||
// initialize platform related stuff
|
|
||||||
g_platform.init(this, Otc::AppName);
|
|
||||||
|
|
||||||
// initialize script environment
|
|
||||||
g_lua.init();
|
|
||||||
|
|
||||||
// register otclient lua functions
|
|
||||||
registerLuaFunctions();
|
|
||||||
|
|
||||||
// initialize resources
|
|
||||||
g_resources.init(args[0].c_str(), Otc::AppPathName);
|
|
||||||
|
|
||||||
// load configurations
|
|
||||||
loadConfigurations();
|
|
||||||
|
|
||||||
// create the client window
|
|
||||||
//TODO: bind these functions and move to otclient module
|
|
||||||
int minWidth = 550;
|
|
||||||
int minHeight = 450;
|
|
||||||
int windowX = Fw::fromstring(g_configs.get("window x"), 0);
|
|
||||||
int windowY = Fw::fromstring(g_configs.get("window y"), 0);
|
|
||||||
int windowWidth = Fw::fromstring(g_configs.get("window width"), minWidth);
|
|
||||||
int windowHeight = Fw::fromstring(g_configs.get("window height"), minHeight);
|
|
||||||
bool maximized = Fw::fromstring(g_configs.get("window maximized"), false);
|
|
||||||
g_platform.createWindow(windowX, windowY, windowWidth, windowHeight, minWidth, minHeight, maximized);
|
|
||||||
g_platform.setWindowTitle(Otc::AppName);
|
|
||||||
g_platform.setWindowIcon("otclient/otcicon.png");
|
|
||||||
|
|
||||||
// initialize graphics
|
|
||||||
g_graphics.init();
|
|
||||||
|
|
||||||
// initialize the ui
|
|
||||||
g_ui.init();
|
|
||||||
|
|
||||||
g_game.init();
|
|
||||||
|
|
||||||
// discover and load modules
|
|
||||||
g_modules.discoverAndLoadModules();
|
|
||||||
g_modules.getModule("otclient")->load();
|
|
||||||
ModulePtr tibiaFilesModule = g_modules.getModule("tibiafiles");
|
|
||||||
if(!tibiaFilesModule || !tibiaFilesModule->isLoaded()) {
|
|
||||||
logFatal("Could not find or load 'tibiafiles' module, this module contains SPR and DAT files.\n"
|
|
||||||
"Please download it and place in modules directory, then try running again.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// now that everything is initialized, setup configurations
|
|
||||||
setupConfigurations();
|
|
||||||
|
|
||||||
// now that everything is loaded, show the window
|
|
||||||
g_platform.showWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OTClient::run()
|
|
||||||
{
|
|
||||||
int frameTicks = g_clock.ticks();
|
|
||||||
int lastPollTicks = frameTicks;
|
|
||||||
int frameCount = 0;
|
|
||||||
|
|
||||||
m_stopping = false;
|
|
||||||
m_running = true;
|
|
||||||
|
|
||||||
if(g_ui.getRootWidget()->getChildCount() == 0) {
|
|
||||||
logError("There is no root widgets to display, the app will close");
|
|
||||||
m_stopping = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// run the first poll
|
|
||||||
poll();
|
|
||||||
|
|
||||||
while(!m_stopping) {
|
|
||||||
//g_platform.sleep(150);
|
|
||||||
frameTicks = g_clock.updateTicks();
|
|
||||||
|
|
||||||
// poll events every POLL_CYCLE_DELAY
|
|
||||||
// this delay exists to avoid massive polling thus increasing framerate
|
|
||||||
if(frameTicks - lastPollTicks >= POLL_CYCLE_DELAY) {
|
|
||||||
poll();
|
|
||||||
lastPollTicks = frameTicks;
|
|
||||||
}
|
|
||||||
|
|
||||||
// only render when the windows is visible
|
|
||||||
if(g_platform.isWindowVisible()) {
|
|
||||||
// render begin
|
|
||||||
g_graphics.beginRender();
|
|
||||||
|
|
||||||
// render everything
|
|
||||||
render();
|
|
||||||
|
|
||||||
// render end
|
|
||||||
g_graphics.endRender();
|
|
||||||
|
|
||||||
// swap the old buffer with the new rendered
|
|
||||||
g_platform.swapBuffers();
|
|
||||||
} else {
|
|
||||||
// sleeps until next poll to avoid massive cpu usage
|
|
||||||
g_clock.sleep(POLL_CYCLE_DELAY+1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_stopping = false;
|
|
||||||
m_running = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OTClient::terminate()
|
|
||||||
{
|
|
||||||
// hide the window because there is no render anymore
|
|
||||||
g_platform.hideWindow();
|
|
||||||
|
|
||||||
g_game.terminate();
|
|
||||||
|
|
||||||
// run modules unload event
|
|
||||||
g_modules.unloadModules();
|
|
||||||
|
|
||||||
// terminate ui
|
|
||||||
g_ui.terminate();
|
|
||||||
|
|
||||||
// release remaining lua object references
|
|
||||||
g_lua.collectGarbage();
|
|
||||||
|
|
||||||
// poll remaining events
|
|
||||||
poll();
|
|
||||||
|
|
||||||
// terminate network
|
|
||||||
Connection::terminate();
|
|
||||||
|
|
||||||
// flush remaining dispatcher events
|
|
||||||
g_dispatcher.flush();
|
|
||||||
|
|
||||||
// terminate graphics
|
|
||||||
g_graphics.terminate();
|
|
||||||
|
|
||||||
// save configurations
|
|
||||||
saveConfigurations();
|
|
||||||
|
|
||||||
// release resources
|
|
||||||
g_resources.terminate();
|
|
||||||
|
|
||||||
// terminate script environment
|
|
||||||
g_lua.terminate();
|
|
||||||
|
|
||||||
// end platform related stuff
|
|
||||||
g_platform.terminate();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void OTClient::exit()
|
|
||||||
{
|
|
||||||
// stops the main loop
|
|
||||||
m_stopping = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OTClient::poll()
|
|
||||||
{
|
|
||||||
// poll platform events
|
|
||||||
g_platform.poll();
|
|
||||||
|
|
||||||
// poll network events
|
|
||||||
Connection::poll();
|
|
||||||
|
|
||||||
// poll dispatcher events
|
|
||||||
g_dispatcher.poll();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OTClient::render()
|
|
||||||
{
|
|
||||||
// everything is rendered by UI components
|
|
||||||
g_ui.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OTClient::loadConfigurations()
|
|
||||||
{
|
|
||||||
// default window size
|
|
||||||
int defWidth = 550;
|
|
||||||
int defHeight = 450;
|
|
||||||
|
|
||||||
// sets default window configuration
|
|
||||||
g_configs.set("window x", Fw::tostring((g_platform.getDisplayWidth() - defWidth)/2));
|
|
||||||
g_configs.set("window y", Fw::tostring((g_platform.getDisplayHeight() - defHeight)/2));
|
|
||||||
g_configs.set("window width", Fw::tostring(defWidth));
|
|
||||||
g_configs.set("window height", Fw::tostring(defHeight));
|
|
||||||
g_configs.set("window maximized", Fw::tostring(false));
|
|
||||||
g_configs.set("vsync", Fw::tostring(true));
|
|
||||||
|
|
||||||
// loads user configuration
|
|
||||||
if(!g_configs.load("config.otml"))
|
|
||||||
logInfo("Using default configurations.");
|
|
||||||
}
|
|
||||||
|
|
||||||
void OTClient::setupConfigurations()
|
|
||||||
{
|
|
||||||
// activate vertical synchronization?
|
|
||||||
bool vsync = Fw::fromstring(g_configs.get("vsync"), true);
|
|
||||||
g_platform.setVerticalSync(vsync);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OTClient::saveConfigurations()
|
|
||||||
{
|
|
||||||
g_configs.set("window x", Fw::tostring(g_platform.getWindowX()));
|
|
||||||
g_configs.set("window y", Fw::tostring(g_platform.getWindowY()));
|
|
||||||
g_configs.set("window width", Fw::tostring(g_platform.getWindowWidth()));
|
|
||||||
g_configs.set("window height", Fw::tostring(g_platform.getWindowHeight()));
|
|
||||||
g_configs.set("window maximized", Fw::tostring(g_platform.isWindowMaximized()));
|
|
||||||
|
|
||||||
// saves user configuration
|
|
||||||
if(!g_configs.save())
|
|
||||||
logError("Configurations are lost because it couldn't be saved");
|
|
||||||
}
|
|
||||||
|
|
||||||
void OTClient::onClose()
|
|
||||||
{
|
|
||||||
//TODO: make and use g_lua.callGlobalField
|
|
||||||
if(m_onCloseCallback)
|
|
||||||
m_onCloseCallback();
|
|
||||||
else
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OTClient::onResize(const Size& size)
|
|
||||||
{
|
|
||||||
static bool eventScheduled = false;
|
|
||||||
static Size newSize;
|
|
||||||
newSize = size;
|
|
||||||
|
|
||||||
// avoid massive resize updates
|
|
||||||
if(!eventScheduled) {
|
|
||||||
g_dispatcher.addEvent([&] {
|
|
||||||
g_graphics.resize(newSize);
|
|
||||||
g_ui.resize(newSize);
|
|
||||||
eventScheduled = false;
|
|
||||||
});
|
|
||||||
eventScheduled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OTClient::onPlatformEvent(const PlatformEvent& event)
|
|
||||||
{
|
|
||||||
bool fireUi = true;
|
|
||||||
|
|
||||||
if(event.type == EventKeyDown && event.ctrl && !event.alt && !event.shift && event.keycode == Fw::KeyF8) {
|
|
||||||
// TODO: move this events to lua
|
|
||||||
UIWidgetPtr console = g_ui.getRootWidget()->getChildById("consolePanel");
|
|
||||||
if(!console->isExplicitlyVisible()) {
|
|
||||||
console->lock();
|
|
||||||
console->show();
|
|
||||||
} else {
|
|
||||||
console->unlock();
|
|
||||||
console->hide();
|
|
||||||
}
|
|
||||||
fireUi = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fireUi)
|
|
||||||
g_ui.inputEvent(event);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,79 +1,16 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2010-2011 OTClient <https://github.com/edubart/otclient>
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef OTCLIENT_H
|
#ifndef OTCLIENT_H
|
||||||
#define OTCLIENT_H
|
#define OTCLIENT_H
|
||||||
|
|
||||||
#include <framework/ui/declarations.h>
|
#include <framework/application.h>
|
||||||
#include <framework/platform/platformlistener.h>
|
#include <otclient/global.h>
|
||||||
|
|
||||||
class OTClient : public PlatformListener
|
class OTClient : public Application
|
||||||
{
|
{
|
||||||
enum {
|
|
||||||
POLL_CYCLE_DELAY = 10
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Where everything begins...
|
void init(const std::vector<std::string>& args);
|
||||||
void init(std::vector<std::string> args);
|
void registerLuaFunctions();
|
||||||
/// Main loop
|
|
||||||
void run();
|
|
||||||
/// Called when the client is terminating
|
|
||||||
void terminate();
|
|
||||||
|
|
||||||
/// Stop running
|
|
||||||
void exit();
|
|
||||||
/// Poll platform, dispatcher and network events
|
|
||||||
void poll();
|
|
||||||
/// Render each frame
|
|
||||||
void render();
|
|
||||||
|
|
||||||
/// Fired when user tryes to close the window
|
|
||||||
void onClose();
|
|
||||||
/// Fired when user resize the window
|
|
||||||
void onResize(const Size& size);
|
|
||||||
/// Fired on an user input event
|
|
||||||
void onPlatformEvent(const PlatformEvent& event);
|
|
||||||
|
|
||||||
bool isRunning() const { return m_running; }
|
|
||||||
|
|
||||||
void setOnClose(const SimpleCallback& onCloseCallback) { m_onCloseCallback = onCloseCallback; }
|
|
||||||
SimpleCallback getOnClose() const { return m_onCloseCallback; }
|
|
||||||
|
|
||||||
static void registerLuaFunctions();
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// Set default configurations and load the user configurations
|
|
||||||
void loadConfigurations();
|
|
||||||
/// Use the loaded configurations to setup other classes
|
|
||||||
void setupConfigurations();
|
|
||||||
void saveConfigurations();
|
|
||||||
|
|
||||||
bool m_running;
|
|
||||||
bool m_stopping;
|
|
||||||
|
|
||||||
SimpleCallback m_onCloseCallback;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern OTClient g_client;
|
extern OTClient g_otclient;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#include <otclient/core/game.h>
|
#include <otclient/core/game.h>
|
||||||
#include <framework/ui/uilineedit.h>
|
#include <framework/ui/uilineedit.h>
|
||||||
|
|
||||||
bool UIGame::onKeyPress(uchar keyCode, char keyChar, int keyboardModifiers)
|
bool UIGame::onKeyPress(uchar keyCode, std::string keyText, int keyboardModifiers)
|
||||||
{
|
{
|
||||||
UILineEditPtr chatLineEdit = std::dynamic_pointer_cast<UILineEdit>(getParent()->recursiveGetChildById("chatLineEdit"));
|
UILineEditPtr chatLineEdit = std::dynamic_pointer_cast<UILineEdit>(getParent()->recursiveGetChildById("chatLineEdit"));
|
||||||
|
|
||||||
|
@ -100,10 +100,10 @@ bool UIGame::onKeyPress(uchar keyCode, char keyChar, int keyboardModifiers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(keyChar != 0) {
|
if(!keyText.empty()) {
|
||||||
chatLineEdit->appendText(std::string(1, keyChar));
|
chatLineEdit->appendText(keyText);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return UIWidget::onKeyPress(keyCode, keyChar, keyboardModifiers);
|
return UIWidget::onKeyPress(keyCode, keyText, keyboardModifiers);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
class UIGame : public UIWidget
|
class UIGame : public UIWidget
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
virtual bool onKeyPress(uchar keyCode, char keyChar, int keyboardModifiers);
|
virtual bool onKeyPress(uchar keyCode, std::string keyText, int keyboardModifiers);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue