346 lines
8.9 KiB
C++
346 lines
8.9 KiB
C++
/* Copyright (c) 2012 Research In Motion Limited.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#include "RetroArch-Cascades.h"
|
|
#include "general.h"
|
|
#include "conf/config_file.h"
|
|
#include "file.h"
|
|
#include "core_info.h"
|
|
|
|
#ifdef HAVE_RGUI
|
|
#include "frontend/menu/rgui.h"
|
|
#endif
|
|
|
|
#include "../../frontend_qnx.h"
|
|
|
|
#include <bb/cascades/AbsoluteLayoutProperties>
|
|
#include <bb/cascades/ForeignWindowControl>
|
|
#include <bb/cascades/AbstractPane>
|
|
#include <bb/cascades/QmlDocument>
|
|
#include <bb/cascades/Window>
|
|
#include <bb/cascades/pickers/FilePicker>
|
|
#include <bb/data/JsonDataAccess>
|
|
#include <bb/device/HardwareInfo>
|
|
#include <bb/cascades/ListView>
|
|
|
|
|
|
#include <screen/screen.h>
|
|
#include <bps/screen.h>
|
|
#include <bps/navigator.h>
|
|
#include <bps/bps.h>
|
|
|
|
#include <math.h>
|
|
#include <dirent.h>
|
|
#include <bb/cascades/DropDown>
|
|
|
|
using namespace bb::cascades;
|
|
using namespace bb::data;
|
|
using namespace bb::device;
|
|
|
|
extern screen_window_t screen_win;
|
|
extern screen_context_t screen_ctx;
|
|
|
|
RetroArch::RetroArch()
|
|
{
|
|
qmlRegisterType<bb::cascades::pickers::FilePicker>("bb.cascades.pickers", 1, 0, "FilePicker");
|
|
qmlRegisterUncreatableType<bb::cascades::pickers::FileType>("bb.cascades.pickers", 1, 0, "FileType", "");
|
|
|
|
// Create channel to signal threads on
|
|
chid = ChannelCreate(0);
|
|
coid = ConnectAttach(0, 0, chid, _NTO_SIDE_CHANNEL, 0);
|
|
|
|
bool res = connect(
|
|
OrientationSupport::instance(), SIGNAL(rotationCompleted()),
|
|
this, SLOT(onRotationCompleted()));
|
|
|
|
rarch_main_clear_state();
|
|
strlcpy(g_extern.config_path, "app/native/retroarch.cfg", sizeof(g_extern.config_path));
|
|
config_load();
|
|
|
|
strlcpy(g_settings.libretro, "app/native/lib", sizeof(g_settings.libretro));
|
|
coreSelectedIndex = -1;
|
|
|
|
//Stop config overwritting values
|
|
g_extern.block_config_read = true;
|
|
|
|
QmlDocument *qml = QmlDocument::create("asset:///main.qml");
|
|
|
|
if (!qml->hasErrors())
|
|
{
|
|
qml->setContextProperty("RetroArch", this);
|
|
|
|
AbstractPane *mAppPane = qml->createRootObject<AbstractPane>();
|
|
|
|
if (mAppPane)
|
|
{
|
|
//Get core DropDown reference to populate it in C++
|
|
coreSelection = mAppPane->findChild<DropDown*>("dropdown_core");
|
|
connect(coreSelection, SIGNAL(selectedValueChanged(QVariant)), this, SLOT(onCoreSelected(QVariant)));
|
|
core_info_list = core_info_list_new(g_settings.libretro);
|
|
populateCores(core_info_list);
|
|
|
|
Application::instance()->setScene(mAppPane);
|
|
|
|
screen_create_context(&screen_ctx, 0);
|
|
input_qnx.init();
|
|
buttonMap = new ButtonMap(screen_ctx, (const char*)Application::instance()->mainWindow()->groupId().toAscii().constData(), coid);
|
|
qml->setContextProperty("ButtonMap", buttonMap);
|
|
|
|
deviceSelection = mAppPane->findChild<DropDown*>("dropdown_devices");
|
|
buttonMap->deviceSelection = deviceSelection;
|
|
findDevices();
|
|
|
|
//Setup the datamodel for button mapping.
|
|
mAppPane->findChild<ListView*>("buttonMapList")->setDataModel(buttonMap->buttonDataModel);
|
|
|
|
// Start the thread in which we render to the custom window.
|
|
start();
|
|
}
|
|
}
|
|
}
|
|
|
|
RetroArch::~RetroArch()
|
|
{
|
|
core_info_list_free(core_info_list);
|
|
}
|
|
|
|
void RetroArch::aboutToQuit()
|
|
{
|
|
recv_msg msg;
|
|
|
|
msg.code = RETROARCH_EXIT;
|
|
|
|
MsgSend(coid, (void*)&msg, sizeof(msg), (void*)NULL, 0);
|
|
|
|
wait();
|
|
}
|
|
|
|
void RetroArch::run()
|
|
{
|
|
int rcvid = -1;
|
|
recv_msg msg;
|
|
|
|
bps_initialize();
|
|
|
|
if (screen_request_events(screen_ctx) != BPS_SUCCESS)
|
|
{
|
|
RARCH_ERR("screen_request_events failed.\n");
|
|
}
|
|
|
|
if (navigator_request_events(0) != BPS_SUCCESS)
|
|
{
|
|
RARCH_ERR("navigator_request_events failed.\n");
|
|
}
|
|
|
|
if (navigator_rotation_lock(false) != BPS_SUCCESS)
|
|
{
|
|
RARCH_ERR("navigator_location_lock failed.\n");
|
|
}
|
|
|
|
while (true)
|
|
{
|
|
rcvid = MsgReceive(chid, &msg, sizeof(msg), 0);
|
|
|
|
if (rcvid > 0)
|
|
{
|
|
switch (msg.code)
|
|
{
|
|
case RETROARCH_START_REQUESTED:
|
|
{
|
|
MsgReply(rcvid,0,NULL,0);
|
|
|
|
if (screen_create_window_type(&screen_win, screen_ctx, SCREEN_CHILD_WINDOW) != BPS_SUCCESS)
|
|
{
|
|
RARCH_ERR("Screen create window failed.\n");
|
|
}
|
|
if (screen_join_window_group(screen_win, (const char*)Application::instance()->mainWindow()->groupId().toAscii().constData()) != BPS_SUCCESS)
|
|
{
|
|
RARCH_ERR("Screen join window group failed.\n");
|
|
}
|
|
|
|
char *win_id = "RetroArch_Emulator_Window";
|
|
screen_set_window_property_cv(screen_win, SCREEN_PROPERTY_ID_STRING, strlen(win_id), win_id);
|
|
|
|
int z = 10;
|
|
if (screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_ZORDER, &z) != 0) {
|
|
return;
|
|
}
|
|
|
|
initRASettings();
|
|
|
|
rarch_main(0, NULL);
|
|
Application::instance()->exit();
|
|
break;
|
|
}
|
|
//The class should probably be it's own QThread, simplify things
|
|
case RETROARCH_BUTTON_MAP:
|
|
MsgReply(rcvid, buttonMap->mapNextButtonPressed(), NULL, 0);
|
|
break;
|
|
case RETROARCH_EXIT:
|
|
MsgReply(rcvid,0,NULL,0);
|
|
goto exit;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
exit:
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* Properties
|
|
*/
|
|
QString RetroArch::getRom()
|
|
{
|
|
return rom;
|
|
}
|
|
|
|
void RetroArch::setRom(QString rom)
|
|
{
|
|
this->rom = rom;
|
|
}
|
|
|
|
QString RetroArch::getCore()
|
|
{
|
|
return core;
|
|
}
|
|
|
|
void RetroArch::setCore(QString core)
|
|
{
|
|
this->core = core;
|
|
}
|
|
|
|
QString RetroArch::getRomExtensions()
|
|
{
|
|
return romExtensions;
|
|
}
|
|
|
|
/*
|
|
* Slots
|
|
*/
|
|
void RetroArch::onRotationCompleted()
|
|
{
|
|
if (OrientationSupport::instance()->orientation() == UIOrientation::Landscape)
|
|
{
|
|
if (state == RETROARCH_START_REQUESTED)
|
|
{
|
|
startEmulator();
|
|
}
|
|
}
|
|
}
|
|
|
|
void RetroArch::onCoreSelected(QVariant value)
|
|
{
|
|
coreSelectedIndex = value.toInt();
|
|
|
|
core.clear();
|
|
core.append(core_info_list->list[coreSelectedIndex].path);
|
|
emit coreChanged(core);
|
|
|
|
romExtensions = QString("*.%1").arg(core_info_list->list[coreSelectedIndex].supported_extensions);
|
|
romExtensions.replace("|", "|*.");
|
|
emit romExtensionsChanged(romExtensions);
|
|
|
|
qDebug() << "Core Selected: " << core;
|
|
qDebug() << "Supported Extensions: " << romExtensions;
|
|
}
|
|
|
|
/*
|
|
* Functions
|
|
*/
|
|
void RetroArch::startEmulator()
|
|
{
|
|
state = RETROARCH_START_REQUESTED;
|
|
|
|
if (OrientationSupport::instance()->orientation() == UIOrientation::Portrait &&
|
|
OrientationSupport::instance()->supportedDisplayOrientation() != SupportedDisplayOrientation::DeviceNorth)
|
|
{
|
|
OrientationSupport::instance()->setSupportedDisplayOrientation(SupportedDisplayOrientation::DisplayLandscape);
|
|
}
|
|
else
|
|
{
|
|
recv_msg msg;
|
|
msg.code = RETROARCH_START_REQUESTED;
|
|
|
|
MsgSend(coid, (void*)&msg, sizeof(msg), (void*)NULL, 0);
|
|
|
|
state = RETROARCH_RUNNING;
|
|
}
|
|
}
|
|
|
|
void RetroArch::populateCores(core_info_list_t * info)
|
|
{
|
|
int i;
|
|
Option *tmp;
|
|
|
|
//Populate DropDown
|
|
for (i = 0; i < info->count; ++i)
|
|
{
|
|
qDebug() << info->list[i].display_name;
|
|
|
|
tmp = Option::create().text(QString(info->list[i].display_name))
|
|
.value(i);
|
|
|
|
coreSelection->add(tmp);
|
|
}
|
|
}
|
|
|
|
void RetroArch::findDevices()
|
|
{
|
|
//Find all connected devices.
|
|
Option *tmp;
|
|
|
|
deviceSelection->removeAll();
|
|
|
|
//Populate DropDown
|
|
for (int i = 0; i < pads_connected; ++i)
|
|
{
|
|
tmp = Option::create().text(devices[i].device_name)
|
|
.value(i);
|
|
|
|
deviceSelection->add(tmp);
|
|
|
|
//QML shows player 1 by default, so set dropdown to their controller.
|
|
if(devices[i].port == 0 || devices[i].device == DEVICE_KEYPAD)
|
|
{
|
|
deviceSelection->setSelectedIndex(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
extern "C" void discoverControllers();
|
|
void RetroArch::discoverController(int player)
|
|
{
|
|
//TODO: Check device, gamepad/keyboard and return accordingly.
|
|
discoverControllers();
|
|
findDevices();
|
|
buttonMap->refreshButtonMap(player);
|
|
return;
|
|
}
|
|
|
|
void RetroArch::initRASettings()
|
|
{
|
|
strlcpy(g_settings.libretro,(char *)core.toAscii().constData(), sizeof(g_settings.libretro));
|
|
strlcpy(g_extern.fullpath, (char *)rom.toAscii().constData(), sizeof(g_extern.fullpath));
|
|
|
|
HardwareInfo *hwInfo = new HardwareInfo();
|
|
|
|
//If Physical keyboard or a device mapped to player 1, hide overlay
|
|
//TODO: Should there be a minimized/quick settings only overlay?
|
|
if(hwInfo->isPhysicalKeyboardDevice() || port_device[0])
|
|
*g_settings.input.overlay = '\0';
|
|
}
|