feat: wxWidgets gui

This commit is contained in:
CLARATION committed 2026-06-19 17:51:51 -07:00
1 parent 7ee6976c7d
commit fa05fd34e1
53 files changed
+2494 -296

No files matched your search

+186
View File
@@ -0,0 +1,186 @@
#ifdef WITH_GUI
#include "event.hpp"
#include "wx/AppFrame.hpp"
#include "state.hpp"
#include "sequence.hpp"
#include "utils/log.h"
#include <wx/wx.h>
#include <thread>
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
#include <libirecovery.h>
static inline DeviceState make_fresh_state()
{
return DeviceState{};
}
void normal_device_event_cb(
const idevice_event_t* event,
void* user_data)
{
#ifdef WITH_GUI
auto* frame = static_cast<MainFrame*>(user_data);
if (!frame || !event)
return;
#endif
DeviceState state = make_fresh_state();
if (event->event == IDEVICE_DEVICE_REMOVE)
{
#ifdef WITH_GUI
send_device_state(frame, state);
#endif
return;
}
if (event->event != IDEVICE_DEVICE_ADD)
return;
idevice_t device = nullptr;
if (idevice_new(&device, event->udid) != IDEVICE_E_SUCCESS)
return;
state.connected = true;
state.mode = DeviceMode::Normal;
state.udid = event->udid ? event->udid : "";
lockdownd_client_t client = nullptr;
if (lockdownd_client_new_with_handshake(device, &client, "palera1n") == LOCKDOWN_E_SUCCESS)
{
plist_t product = nullptr;
plist_t version = nullptr;
plist_t ecid = nullptr;
char *p = nullptr, *v = nullptr;
uint64_t ecid_val = 0;
lockdownd_get_value(client, nullptr, "ProductType", &product);
lockdownd_get_value(client, nullptr, "ProductVersion", &version);
lockdownd_get_value(client, nullptr, "UniqueChipID", &ecid);
if (product) plist_get_string_val(product, &p);
if (version) plist_get_string_val(version, &v);
if (ecid) plist_get_uint_val(ecid, &ecid_val);
state.productType = p ? p : "";
state.productVersion = v ? v : "";
state.ecid = ecid_val;
free(p);
free(v);
if (product) plist_free(product);
if (version) plist_free(version);
if (ecid) plist_free(ecid);
lockdownd_client_free(client);
}
idevice_free(device);
state.isSupported = SequenceIsSupported(state.productType);
#ifdef WITH_GUI
send_device_state(frame, state);
#endif
}
void recovery_device_event_cb(
const irecv_device_event_t* event,
void* user_data)
{
#ifdef WITH_GUI
auto* frame = static_cast<MainFrame*>(user_data);
if (!frame || !event)
return;
#endif
DeviceState state = make_fresh_state();
if (event->type == IRECV_DEVICE_REMOVE)
{
#ifdef WITH_GUI
send_device_state(frame, state);
#endif
return;
}
if (event->type != IRECV_DEVICE_ADD)
return;
state.connected = true;
if (event->mode == IRECV_K_DFU_MODE)
{
state.mode = DeviceMode::DFU;
#ifdef WITH_GUI
send_device_state(frame, state);
#endif
return;
}
if (!(event->mode == IRECV_K_RECOVERY_MODE_1 ||
event->mode == IRECV_K_RECOVERY_MODE_2 ||
event->mode == IRECV_K_RECOVERY_MODE_3 ||
event->mode == IRECV_K_RECOVERY_MODE_4))
{
return;
}
state.mode = DeviceMode::Recovery;
uint64_t ecid_val = 0;
if (event->device_info && event->device_info->ecid)
ecid_val = event->device_info->ecid;
state.ecid = ecid_val;
irecv_client_t client = nullptr;
int attempts = 0;
const int max_attempts = 10;
while (attempts < max_attempts)
{
if (irecv_open_with_ecid(&client, state.ecid) == IRECV_E_SUCCESS)
break;
attempts++;
std::this_thread::sleep_for(std::chrono::milliseconds(300));
}
if (client)
{
LOG("Opened client after %d attempts", attempts);
irecv_device_t device = nullptr;
if (irecv_devices_get_device_by_client(client, &device) == IRECV_E_SUCCESS && device)
{
LOG("device product type: %s", device->product_type);
LOG("device display name: %s", device->display_name);
state.productType = device->product_type ? device->product_type : "";
state.displayName = device->display_name ? device->display_name : "";
}
irecv_close(client);
}
else
{
LOG("Failed to open irecv client after retries");
}
state.isSupported = SequenceIsSupported(state.productType);
#ifdef WITH_GUI
send_device_state(frame, state);
#endif
}
#endif // WITH_GUI
+21
View File
@@ -0,0 +1,21 @@
#ifdef WITH_GUI
#ifndef EVENT_H
#define EVENT_H
#include "state.hpp"
#include <wx/wx.h>
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
#include <libirecovery.h>
class MainFrame;
void normal_device_event_cb(const idevice_event_t* event, void* user_data);
void recovery_device_event_cb(const irecv_device_event_t* event, void* user_data);
#endif // EVENT_H
#endif // WITH_GUI
+10 -9
View File
@@ -5,12 +5,6 @@
#include <cstdio>
#include <cstdlib>
#if defined(__APPLE__)
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/usb/IOUSBLib.h>
#endif
#ifdef WITH_GUI
# include <wx/wx.h>
#endif
@@ -21,9 +15,16 @@
void print_credits() {
printf(
":: ========================== ::\n"
":: palera1n: " PALERAIN_VERSION "\n"
":: ========================== ::\n\n"
"#\n"
"# palera1n: " PALERAIN_VERSION "\n"
"#\n"
"# ======== Made by =======\n"
"# Made by: asdfugil, kok3shidoll, claration, mineek, staturnz\n"
"# ======== Thanks to =======\n"
"# Thanks to: llsc12, Nebula, Lrdsnow, nikias (libimobiledevice),\n"
"# checkra1n team (Siguza, axi0mx, littlelailo et al.),\n"
"# Procursus Team (Hayden Seay, Cameron Katri, Keto et.al)\n"
"# ==========================\n\n"
);
}
+88
View File
@@ -0,0 +1,88 @@
#ifdef WITH_GUI
#include <nlohmann/json.hpp>
#include "gen/DFUHelperDeviceInfo.h"
#include "sequence.hpp"
DfuSequence ParseSequence(const std::string& deviceKey)
{
DfuSequence seq;
static nlohmann::json j = nlohmann::json::parse(
DFUHelperDeviceInfo,
DFUHelperDeviceInfo + DFUHelperDeviceInfo_len
);
auto itMap = j["devicemap"].find(deviceKey);
if (itMap == j["devicemap"].end())
return seq;
const std::string deviceType = itMap.value();
auto itLayout = j["devicelayout"].find(deviceType);
if (itLayout == j["devicelayout"].end())
return seq;
const auto& layout = itLayout.value();
seq.imageName = layout.value("image_name", "");
seq.imageWidth = layout.value("image_width", 0);
seq.imageHeight = layout.value("image_height", 0);
seq.imageOffsetX = layout.value("image_offset_x", 0);
if (layout.contains("buttons"))
{
for (auto it = layout["buttons"].begin();
it != layout["buttons"].end();
++it)
{
DfuButton btn;
btn.id = it.key();
const auto& b = it.value();
btn.name = b.value("name", "");
btn.x = b.value("x", 0);
btn.y = b.value("y", 0);
seq.buttons.push_back(std::move(btn));
}
}
const std::string sequenceKey =
layout.value("sequence", "");
auto itSeq = j["sequences"].find(sequenceKey);
if (itSeq == j["sequences"].end())
return seq;
for (const auto& s : itSeq.value())
{
DfuStep step;
step.description = s.value("description", "");
step.duration = s.value("duration", 0);
step.action = s.value("action", "");
if (s.contains("buttons"))
{
for (const auto& b : s["buttons"])
step.activeButtons.push_back(
b.get<std::string>()
);
}
seq.steps.push_back(std::move(step));
}
return seq;
}
bool SequenceIsSupported(const std::string& deviceKey)
{
DfuSequence seq = ParseSequence(deviceKey);
return !seq.steps.empty();
}
#endif // WITH_GUI
+40
View File
@@ -0,0 +1,40 @@
#ifdef WITH_GUI
#ifndef SEQUENCE_H
#define SEQUENCE_H
#include <string>
struct DfuButton
{
std::string id;
std::string name;
int x = 0;
int y = 0;
};
struct DfuStep
{
std::string description;
int duration = 0;
std::vector<std::string> activeButtons;
std::string action;
};
struct DfuSequence
{
std::string imageName;
int imageWidth = 0;
int imageHeight = 0;
int imageOffsetX = 0;
std::vector<DfuButton> buttons;
std::vector<DfuStep> steps;
};
DfuSequence ParseSequence(const std::string& deviceKey);
bool SequenceIsSupported(const std::string& deviceKey);
#endif // SEQUENCE_H
#endif // WITH_GUI
+26
View File
@@ -0,0 +1,26 @@
#ifndef STATE_H
#define STATE_H
#include <string>
enum class DeviceMode
{
None,
Normal,
Recovery,
DFU
};
struct DeviceState
{
bool connected = false;
bool isSupported = false;
DeviceMode mode = DeviceMode::None;
std::string productVersion;
std::string productType;
std::string displayName;
std::string udid;
uint64_t ecid;
};
#endif // STATE_H
-209
View File
@@ -1,209 +0,0 @@
#ifdef WITH_GUI
#include "app.hpp"
#include <wx/wx.h>
#include <wx/mstream.h>
#include <wx/image.h>
#include <wx/bitmap.h>
#include <wx/statline.h>
#include <string>
#include "../utils/constants.h"
#include "../utils/paleinfo.h"
#include "../utils/log.h"
#include "../exploit/logo.h"
class MainFrame;
class MainPanel : public wxPanel
{
public:
explicit MainPanel(MainFrame* frame, wxWindow* parent);
};
class SettingsPanel : public wxPanel
{
public:
explicit SettingsPanel(MainFrame* frame, wxWindow* parent);
};
class MainFrame : public wxFrame
{
public:
MainFrame()
: wxFrame(
nullptr,
wxID_ANY,
"palera1n – Version beta " + wxString(PALERAIN_VERSION),
wxDefaultPosition,
wxSize(480, 360),
wxDEFAULT_FRAME_STYLE & ~(wxMAXIMIZE_BOX | wxRESIZE_BORDER))
{
auto* root = new wxBoxSizer(wxVERTICAL);
m_main = new MainPanel(this, this);
m_settings = new SettingsPanel(this, this);
root->Add(m_main, 1, wxEXPAND);
root->Add(m_settings, 1, wxEXPAND);
SetSizer(root);
ShowMain();
}
void ShowMain()
{
m_main->Show();
m_settings->Hide();
Layout();
}
void ShowSettings()
{
m_main->Hide();
m_settings->Show();
Layout();
}
private:
MainPanel* m_main;
SettingsPanel* m_settings;
};
MainPanel::MainPanel(MainFrame* frame, wxWindow* parent)
: wxPanel(parent)
{
auto* root = new wxBoxSizer(wxVERTICAL);
wxInitAllImageHandlers();
wxMemoryInputStream stream(resources_logo_png, resources_logo_png_len);
wxImage img(stream, wxBITMAP_TYPE_PNG);
wxBitmap bmp(img);
auto* logo = new wxStaticBitmap(this, wxID_ANY, bmp);
auto* titletext = new wxStaticText(this, wxID_ANY, "Welcome to palera1n!");
wxFont titlefont = titletext->GetFont();
titlefont.SetWeight(wxFONTWEIGHT_BOLD);
titletext->SetFont(titlefont);
auto* left = new wxBoxSizer(wxVERTICAL);
left->Add(titletext, 0, wxTOP | wxLEFT, 10);
auto* row = new wxBoxSizer(wxHORIZONTAL);
row->Add(left, 0, wxALIGN_TOP);
row->AddStretchSpacer();
row->Add(logo, 0, wxTOP | wxRIGHT, 10);
root->Add(row, 0, wxEXPAND);
root->Add(new wxStaticLine(this), 0, wxEXPAND | wxALL, 10);
auto* credtext = new wxStaticText(this, wxID_ANY, "Made by: asdfugil, kok3shidoll, claration, mineek, staturnz\n\nThanks to: itsnebulalol, llsc12, lrdsnow, nikias (libimobiledevice), Checkra1n\n(Siguza, axi0mx, littlelailo et al.), Procursus (Hayden Seay, Cameron Katri,\nKeto et al.)\n\nWith 💖 from C (claration)");
root->Add(credtext, 0, wxLEFT | wxRIGHT, 10);
root->Add(new wxStaticLine(this), 0, wxEXPAND | wxALL, 10);
auto* notetext = new wxStaticText(this, wxID_ANY, "NOTE: Please ensure you have a backup of your device before applying the\njailbreak. While data loss is unlikely, we won't be responsible if something goes\nwrong. Use at your own risk.");
wxFont notefont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
notefont.SetPointSize(12);
notefont.SetStyle(wxFONTSTYLE_ITALIC);
notetext->SetFont(notefont);
root->Add(notetext, 0, wxLEFT | wxRIGHT, 10);
root->AddStretchSpacer();
auto* btn = new wxButton(this, wxID_ANY, "Options");
auto* sbtn = new wxButton(this, wxID_ANY, "Start");
sbtn->Disable();
btn->Bind(wxEVT_BUTTON, [frame](wxCommandEvent&)
{
frame->ShowSettings();
});
auto* bottomRow = new wxBoxSizer(wxHORIZONTAL);
bottomRow->AddStretchSpacer();
bottomRow->Add(btn, 0, wxALL, 10);
bottomRow->Add(sbtn, 0, wxALL, 10);
root->Add(bottomRow, 0, wxEXPAND);
SetSizer(root);
}
SettingsPanel::SettingsPanel(MainFrame* frame, wxWindow* parent)
: wxPanel(parent)
{
auto* root = new wxBoxSizer(wxVERTICAL);
root->Add(new wxStaticText(this, wxID_ANY,
"You may set the following options. If you don't know what they mean you'll\n"
"probably have no reason to set them."), 0, wxALL, 10);
auto* option_safemode = new wxCheckBox(this, wxID_ANY, "Safe Mode");
auto* option_verbose = new wxCheckBox(this, wxID_ANY, "Verbose Boot");
auto* option_revert = new wxCheckBox(this, wxID_ANY, "Restore System");
auto* option_dark_blockchain = new wxCheckBox(this, wxID_ANY, "Dark Blockchain");
option_safemode->SetValue(palerain_flags & palerain_option_safemode);
option_verbose->SetValue(palerain_flags & palerain_option_verbose_boot);
option_revert->SetValue(palerain_flags & palerain_option_force_revert);
option_dark_blockchain->SetValue(true);
option_safemode->Bind(wxEVT_CHECKBOX, [&](wxCommandEvent& e)
{
if (e.IsChecked())
palerain_flags |= palerain_option_safemode;
else
palerain_flags &= ~palerain_option_safemode;
});
option_verbose->Bind(wxEVT_CHECKBOX, [&](wxCommandEvent& e)
{
if (e.IsChecked())
palerain_flags |= palerain_option_verbose_boot;
else
palerain_flags &= ~palerain_option_verbose_boot;
});
option_revert->Bind(wxEVT_CHECKBOX, [&](wxCommandEvent& e)
{
if (e.IsChecked())
palerain_flags |= palerain_option_force_revert;
else
palerain_flags &= ~palerain_option_force_revert;
});
root->Add(option_safemode, 0, wxLEFT | wxRIGHT, 10);
root->Add(option_verbose, 0, wxLEFT | wxRIGHT | wxTOP, 10);
root->Add(new wxStaticText(this, wxID_ANY, "Boot Arguments:"), 0, wxALL, 10);
auto* bootArgs = new wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize);
root->Add(bootArgs, 0, wxLEFT | wxRIGHT | wxEXPAND, 30);
root->Add(option_revert, 0, wxLEFT | wxRIGHT | wxTOP, 10);
root->Add(option_dark_blockchain, 0, wxLEFT | wxRIGHT | wxTOP, 10);
root->AddStretchSpacer();
auto* back = new wxButton(this, wxID_ANY, "Back");
back->Bind(wxEVT_BUTTON, [frame](wxCommandEvent&)
{
frame->ShowMain();
});
auto* bottomRow = new wxBoxSizer(wxHORIZONTAL);
bottomRow->AddStretchSpacer();
bottomRow->Add(back, 0, wxALL, 10);
root->Add(bottomRow, 0, wxEXPAND);
SetSizer(root);
}
bool PalerainApp::OnInit()
{
auto* frame = new MainFrame();
frame->Show(true);
return true;
}
wxIMPLEMENT_APP_NO_MAIN(PalerainApp);
#endif // WITH_GUI
-10
View File
@@ -1,10 +0,0 @@
#ifdef WITH_GUI
#pragma once
#include <wx/wx.h>
class PalerainApp : public wxApp {
public:
bool OnInit() override;
};
#endif // WITH_GUI
+1 -1
View File
@@ -1,7 +1,7 @@
#ifndef CONSTANTS_H
#define CONSTANTS_H
#define PALERAIN_VERSION "2.4.0"
#define PALERAIN_VERSION "3.0.0"
#include <cstdint>
+165
View File
@@ -0,0 +1,165 @@
#ifdef WITH_GUI
#include "AppFrame.hpp"
#include <wx/wx.h>
#include "../utils/constants.h"
#include "../event.hpp"
#include <thread>
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
#include <libirecovery.h>
wxDEFINE_EVENT(EVT_DEVICE_STATE_UPDATE, wxCommandEvent);
void send_device_state(MainFrame* frame, const DeviceState& state)
{
wxTheApp->CallAfter([frame, state]() {
auto* evt = new wxCommandEvent(EVT_DEVICE_STATE_UPDATE);
evt->SetClientData(new DeviceState(state));
wxPostEvent(frame, *evt);
});
}
MainFrame::MainFrame()
: wxFrame(nullptr,
wxID_ANY,
"palera1n – Version beta " + wxString(PALERAIN_VERSION),
wxDefaultPosition,
wxSize(480, 360),
wxDEFAULT_FRAME_STYLE & ~(wxMAXIMIZE_BOX | wxRESIZE_BORDER))
{
auto* root = new wxBoxSizer(wxVERTICAL);
m_main = new MainPanel(this, this);
m_settings = new SettingsPanel(this, this);
m_recovery = new RecoveryPanel(this, this);
m_dfu = new DfuPanel(this, this);
m_exploit = new ExploitPanel(this, this);
root->Add(m_main, 1, wxEXPAND);
root->Add(m_settings, 1, wxEXPAND);
root->Add(m_recovery, 1, wxEXPAND);
root->Add(m_dfu, 1, wxEXPAND);
root->Add(m_exploit, 1, wxEXPAND);
SetSizer(root);
Bind(EVT_DEVICE_STATE_UPDATE, [this](wxCommandEvent& e)
{
auto* state = static_cast<DeviceState*>(e.GetClientData());
if (!state)
return;
UpdateDeviceState(*state);
delete state;
});
ShowMain();
std::thread([this]()
{
idevice_event_subscribe(normal_device_event_cb, this);
while (true)
sleep(1);
}).detach();
std::thread([this]()
{
static irecv_device_event_context_t ctx = nullptr;
irecv_device_event_subscribe(
&ctx,
recovery_device_event_cb,
this
);
while (true)
sleep(1);
}).detach();
}
void MainFrame::ShowMain()
{
m_main->Show();
m_settings->Hide();
m_recovery->Hide();
m_dfu->Hide();
m_exploit->Hide();
Layout();
}
void MainFrame::ShowSettings()
{
m_main->Hide();
m_settings->Show();
m_recovery->Hide();
m_dfu->Hide();
m_exploit->Hide();
Layout();
}
void MainFrame::ShowRecovery()
{
m_main->Hide();
m_settings->Hide();
m_recovery->Show();
m_dfu->Hide();
m_exploit->Hide();
Layout();
}
void MainFrame::ShowDfu()
{
m_main->Hide();
m_settings->Hide();
m_recovery->Hide();
m_dfu->Show();
m_dfu->LoadDevice(m_state.productType);
m_exploit->Hide();
Layout();
}
void MainFrame::ShowExploit()
{
m_main->Hide();
m_settings->Hide();
m_recovery->Hide();
m_dfu->Hide();
m_exploit->Show();
m_exploit->StartExploit();
Layout();
}
void MainFrame::UpdateDeviceState(const DeviceState& state)
{
m_state = state;
if (m_main)
m_main->SetDeviceState(m_state);
if (m_recovery)
m_recovery->SetDeviceState(m_state);
if (m_dfu)
m_dfu->SetDeviceState(m_state);
if (m_exploit)
m_exploit->SetDeviceState(m_state);
}
bool PalerainApp::OnInit()
{
auto* frame = new MainFrame();
frame->Show(true);
return true;
}
wxIMPLEMENT_APP_NO_MAIN(PalerainApp);
#endif
+53
View File
@@ -0,0 +1,53 @@
#ifndef APPFRAME_H
#define APPFRAME_H
#ifdef WITH_GUI
#include <wx/wx.h>
#include "../state.hpp"
#include "MainPanel.hpp"
#include "SettingsPanel.hpp"
#include "RecoveryPanel.hpp"
#include "DfuPanel.hpp"
#include "ExploitPanel.hpp"
void send_device_state(MainFrame* frame, const DeviceState& state);
class MainFrame : public wxFrame
{
public:
MainFrame();
void ShowMain();
void ShowSettings();
void ShowRecovery();
void ShowDfu();
void ShowExploit();
const DeviceState& GetDeviceState() const { return m_state; }
void UpdateDeviceState(const DeviceState& state);
MainPanel* GetMainPanel() const { return m_main; }
SettingsPanel* GetSettingsPanel() const { return m_settings; }
RecoveryPanel* GetRecoveryPanel() const { return m_recovery; }
DfuPanel* GetDfuPanel() const { return m_dfu; }
ExploitPanel* GetExploitPanel() const { return m_exploit; }
private:
MainPanel* m_main = nullptr;
SettingsPanel* m_settings = nullptr;
RecoveryPanel* m_recovery = nullptr;
DfuPanel* m_dfu = nullptr;
ExploitPanel* m_exploit = nullptr;
DeviceState m_state;
};
class PalerainApp : public wxApp {
public:
bool OnInit() override;
};
#endif // WITH_GUI
#endif // APPFRAME_H
+38
View File
@@ -0,0 +1,38 @@
#ifndef DEVICEPANEL_H
#define DEVICEPANEL_H
#include <wx/wx.h>
#include "../state.hpp"
class MainFrame;
class DevicePanel : public wxPanel
{
public:
DevicePanel(MainFrame* frame, wxWindow* parent)
: wxPanel(parent),
m_frame(frame)
{
}
virtual void SetDeviceState(const DeviceState& state)
{
m_deviceState = state;
}
protected:
MainFrame* GetMainFrame() const
{
return m_frame;
}
const DeviceState& GetDeviceState() const
{
return m_deviceState;
}
private:
MainFrame* m_frame;
DeviceState m_deviceState;
};
#endif // DEVICEPANEL_H
+427
View File
@@ -0,0 +1,427 @@
#ifdef WITH_GUI
#include "DfuPanel.hpp"
#include "AppFrame.hpp"
#include "DevicePanel.hpp"
#include "../state.hpp"
#include "../sequence.hpp"
#include "../utils/log.h"
#include <thread>
#include <wx/wx.h>
#include <wx/mstream.h>
#include <wx/image.h>
#include <wx/bitmap.h>
#include "../gen/images/atv_std_brd.h"
#include "../gen/images/ipad.h"
#include "../gen/images/ipadmini.h"
#include "../gen/images/iphone6s.h"
#include "../gen/images/iphone7.h"
#include "../gen/images/iphone8.h"
#include "../gen/images/iphonese.h"
#include "../gen/images/iphonex.h"
#include "../gen/images/ipodtouch.h"
#include "../gen/images/siriremote.h"
#include <libirecovery.h>
static const wxColour kActive =
wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
static const wxColour kInactive =
wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT);
DfuPanel::DfuPanel(MainFrame* frame, wxWindow* parent)
: DevicePanel(frame, parent)
{
auto* root = new wxBoxSizer(wxVERTICAL);
m_headerText = new wxStaticText(this, wxID_ANY, "Time to put the device into DFU mode. Locate the buttons as marked below\non your device and check the instructions on the right.");
root->Add(m_headerText, 0, wxALL, 10);
auto* contentRow = new wxBoxSizer(wxHORIZONTAL);
m_devicePanel = new wxPanel(this);
m_devicePanel->SetMinSize(wxSize(310, 260));
m_deviceImage = new wxStaticBitmap(
m_devicePanel,
wxID_ANY,
wxBitmap()
);
contentRow->Add(m_devicePanel, 1, wxTOP, 10);
m_stepsSizer = new wxBoxSizer(wxVERTICAL);
contentRow->Add(m_stepsSizer, 2, wxEXPAND | wxALL, 0);
root->Add(contentRow, 1, wxEXPAND);
m_backButton = new wxButton(this, wxID_ANY, "Back");
m_startButton = new wxButton(this, wxID_ANY, "Start");
m_backButton->Bind(wxEVT_BUTTON, [frame](wxCommandEvent&)
{
frame->ShowMain();
});
m_startButton->Bind(wxEVT_BUTTON, [this](wxCommandEvent&)
{
m_isEnteringDfu = true;
m_backButton->Disable();
m_startButton->Disable();
StartSequence(m_sequence);
});
m_timer.Bind(wxEVT_TIMER, [this](wxTimerEvent&)
{
RunStep();
});
m_stagnentTimer.Bind(wxEVT_TIMER, [this](wxTimerEvent&)
{
m_backButton->Enable();
m_startButton->Enable();
GetMainFrame()->ShowExploit();
});
auto* bottomRow = new wxBoxSizer(wxHORIZONTAL);
bottomRow->AddStretchSpacer();
bottomRow->Add(m_backButton, 0, wxALL, 10);
bottomRow->Add(m_startButton, 0, wxALL, 10);
root->Add(bottomRow, 0, wxEXPAND);
SetSizer(root);
}
void DfuPanel::SetDeviceState(const DeviceState& state)
{
DevicePanel::SetDeviceState(state);
if (!(this->IsShown()))
return;
if (m_isEnteringDfu && state.mode == DeviceMode::DFU)
{
m_isEnteringDfu = false;
m_headerText->SetLabel("Device entered DFU mode successfully.\n");
if (!m_stagnentTimer.IsRunning())
m_stagnentTimer.StartOnce(3000);
}
if (m_isEnteringDfu && state.mode == DeviceMode::Normal)
{
m_isEnteringDfu = false;
m_backButton->Enable();
m_startButton->Enable();
GetMainFrame()->ShowRecovery();
GetMainFrame()->GetRecoveryPanel()->SetStatusText("Hmm... It seems like the device didn't enter DFU mode.");
}
if (m_isEnteringDfu && state.mode == DeviceMode::Recovery)
{
m_isEnteringDfu = false;
m_backButton->Enable();
m_startButton->Enable();
GetMainFrame()->ShowMain();
}
}
void DfuPanel::LoadDevice(const std::string& productType)
{
m_sequence = ParseSequence(productType);
m_index = 0;
m_deviceImage->SetBitmap(wxBitmap());
for (auto* lbl : m_stepLabels)
lbl->Destroy();
m_stepLabels.clear();
m_stepsSizer->Clear(false);
for (auto* lbl : m_buttonLabels)
lbl->Destroy();
m_buttonLabels.clear();
const unsigned char* imageData = nullptr;
size_t imageSize = 0;
if (m_sequence.imageName == "ipadmini")
{
imageData = ipadmini;
imageSize = ipadmini_len;
}
else if (m_sequence.imageName == "ipad")
{
imageData = ipad;
imageSize = ipad_len;
}
else if (m_sequence.imageName == "iphonese")
{
imageData = iphonese;
imageSize = iphonese_len;
}
else if (m_sequence.imageName == "iphone6s")
{
imageData = iphone6s;
imageSize = iphone6s_len;
}
else if (m_sequence.imageName == "iphone7")
{
imageData = iphone7;
imageSize = iphone7_len;
}
else if (m_sequence.imageName == "iphone8")
{
imageData = iphone8;
imageSize = iphone8_len;
}
else if (m_sequence.imageName == "iphonex")
{
imageData = iphonex;
imageSize = iphonex_len;
}
else if (m_sequence.imageName == "ipodtouch")
{
imageData = ipodtouch;
imageSize = ipodtouch_len;
}
else if (m_sequence.imageName == "siriremote")
{
imageData = siriremote;
imageSize = siriremote_len;
}
else if (m_sequence.imageName == "atv_std_brd")
{
imageData = atv_std_brd;
imageSize = atv_std_brd_len;
}
if (imageData)
{
wxMemoryInputStream stream(imageData, imageSize);
wxImage img(stream, wxBITMAP_TYPE_PNG);
if (img.IsOk())
{
img = img.Scale(
m_sequence.imageWidth,
m_sequence.imageHeight,
wxIMAGE_QUALITY_HIGH
);
m_deviceImage->SetBitmap(wxBitmap(img));
m_deviceImage->SetPosition(wxPoint(m_sequence.imageOffsetX, 0));
}
}
for (const auto& button : m_sequence.buttons)
{
auto* lbl = new wxStaticText(
m_devicePanel,
wxID_ANY,
button.name
);
lbl->SetPosition(wxPoint(button.x, button.y));
m_buttonLabels.push_back(lbl);
}
for (size_t i = 0; i < m_sequence.steps.size(); i++)
{
const auto& step = m_sequence.steps[i];
wxString label = wxString::Format(
"%zu. %s (%d)",
i + 1,
step.description,
step.duration
);
auto* lbl = new wxStaticText(
this,
wxID_ANY,
label
);
lbl->SetForegroundColour(i == 0 ? kActive : kInactive);
m_stepsSizer->Add(lbl, 0, wxBOTTOM, 5);
m_stepLabels.push_back(lbl);
}
m_devicePanel->Layout();
m_stepsSizer->Layout();
Layout();
Fit();
Refresh();
}
void DfuPanel::StartSequence(const DfuSequence& seq)
{
m_sequence = seq;
m_index = 0;
m_stepRemaining = -1;
m_actionExecutedIndex = -1;
RunStep();
m_timer.StartOnce(1000);
}
void DfuPanel::RunStep()
{
if (m_sequence.steps.empty())
return;
if (m_index >= m_sequence.steps.size())
{
for (auto* lbl : m_stepLabels)
lbl->SetForegroundColour(kInactive);
Layout();
Refresh();
m_timer.Stop();
return;
}
const auto& step = m_sequence.steps[m_index];
if (m_stepRemaining < 0)
m_stepRemaining = step.duration;
if (m_stepRemaining > 0)
--m_stepRemaining;
bool finished = (m_stepRemaining == 0);
size_t completedIndex = m_index;
if (finished)
{
++m_index;
m_stepRemaining = -1;
}
for (size_t i = 0; i < m_stepLabels.size(); i++)
{
auto* lbl = m_stepLabels[i];
if (i == m_index)
{
lbl->SetForegroundColour(kActive);
lbl->SetLabel(wxString::Format(
"%zu. %s (%d)",
i + 1,
m_sequence.steps[i].description,
m_stepRemaining < 0 ? m_sequence.steps[i].duration : m_stepRemaining
));
}
else if (finished && i == completedIndex)
{
lbl->SetForegroundColour(kInactive);
lbl->SetLabel(wxString::Format(
"%zu. %s (0)",
i + 1,
m_sequence.steps[i].description
));
}
else
{
lbl->SetForegroundColour(kInactive);
}
}
for (auto* lbl : m_buttonLabels)
lbl->SetForegroundColour(kInactive);
const auto& activeStep =
(m_index < m_sequence.steps.size())
? m_sequence.steps[m_index]
: m_sequence.steps.back();
for (const auto& buttonId : activeStep.activeButtons)
{
for (const auto& btn : m_sequence.buttons)
{
if (btn.id == buttonId)
{
for (auto* lbl : m_buttonLabels)
{
if (lbl->GetLabel() == btn.name)
lbl->SetForegroundColour(kActive);
}
}
}
}
if (m_index < m_sequence.steps.size())
{
const auto& activeStep = m_sequence.steps[m_index];
if (!activeStep.action.empty() && m_actionExecutedIndex != m_index)
{
m_actionExecutedIndex = m_index;
if (activeStep.action == "reboot")
{
Reboot();
}
}
}
Layout();
Refresh();
Update();
m_timer.StartOnce(1000);
}
void DfuPanel::Reboot()
{
std::thread([this]()
{
const auto state = GetDeviceState();
if (!state.connected || state.mode != DeviceMode::Recovery)
return;
irecv_client_t client = nullptr;
int attempts = 0;
const int max_attempts = 8;
while (attempts < max_attempts)
{
if (irecv_open_with_ecid(&client, state.ecid) == IRECV_E_SUCCESS)
break;
attempts++;
std::this_thread::sleep_for(std::chrono::milliseconds(250));
}
if (!client)
{
return;
}
irecv_setenv(client, "auto-boot", "true");
irecv_saveenv(client);
irecv_reboot(client);
irecv_close(client);
}).detach();
}
#endif // WITH_GUI
+47
View File
@@ -0,0 +1,47 @@
#ifndef DFUPANEL_H
#define DFUPANEL_H
#ifdef WITH_GUI
#include <wx/wx.h>
#include "DevicePanel.hpp"
#include "../state.hpp"
#include "../sequence.hpp"
class DfuPanel;
class DfuPanel : public DevicePanel
{
public:
explicit DfuPanel(MainFrame* frame, wxWindow* parent);
void SetDeviceState(const DeviceState& state) override;
void LoadDevice(const std::string& productType);
void StartSequence(const DfuSequence& seq);
void RunStep();
void Reboot();
private:
wxStaticText* m_headerText = nullptr;
wxButton* m_backButton = nullptr;
wxButton* m_startButton = nullptr;
wxBoxSizer* m_stepsSizer = nullptr;
std::vector<wxStaticText*> m_stepLabels;
DfuSequence m_sequence;
size_t m_index = 0;
int m_stepRemaining = 0;
wxTimer m_timer;
wxTimer m_stagnentTimer;
bool m_isEnteringDfu = false;
wxPanel* m_devicePanel = nullptr;
wxStaticBitmap* m_deviceImage = nullptr;
std::vector<wxStaticText*> m_buttonLabels;
size_t m_actionExecutedIndex = std::numeric_limits<size_t>::max();
};
#endif // WITH_GUI
#endif // DFUPANEL_H
+72
View File
@@ -0,0 +1,72 @@
#ifdef WITH_GUI
#include "ExploitPanel.hpp"
#include <thread>
#include <wx/wx.h>
#include "AppFrame.hpp"
#include "DevicePanel.hpp"
#include "../state.hpp"
#include "../utils/log.h"
ExploitPanel::ExploitPanel(MainFrame* frame, wxWindow* parent)
: DevicePanel(frame, parent)
{
auto* root = new wxBoxSizer(wxVERTICAL);
auto* text = new wxStaticText(this, wxID_ANY,
"Installing jailbreak, this will take a moment. If the device asks for a passcode\nplease enter it. Do not disconnect the device until finished.");
m_statusText = new wxStaticText(this, wxID_ANY, "");
root->Add(text, 0, wxALL, 10);
root->Add(m_statusText, 0, wxALL, 10);
m_backButton = new wxButton(this, wxID_ANY, "Back");
m_backButton->Disable();
m_backButton->Bind(wxEVT_BUTTON, [frame](wxCommandEvent&)
{
frame->ShowMain();
});
auto* bottomRow = new wxBoxSizer(wxHORIZONTAL);
bottomRow->AddStretchSpacer();
bottomRow->Add(m_backButton, 0, wxALL, 10);
root->AddStretchSpacer();
root->Add(bottomRow, 0, wxEXPAND);
SetSizer(root);
}
void ExploitPanel::SetDeviceState(const DeviceState& state)
{
DevicePanel::SetDeviceState(state);
if (!(this->IsShown()))
return;
if (state.mode == DeviceMode::Normal)
{
m_statusText->SetLabel("Done.");
m_backButton->Enable();
}
}
void ExploitPanel::StartExploit()
{
m_statusText->SetLabel("Exploiting device...");
m_backButton->Disable();
std::thread([this]()
{
const auto state = GetDeviceState();
if (!state.connected || state.mode != DeviceMode::DFU)
return;
LOG("Starting exploit on worker thread...");
}).detach();
}
#endif // WITH_GUI
+24
View File
@@ -0,0 +1,24 @@
#ifndef EXPLOITPANEL_HPP
#define EXPLOITPANEL_HPP
#ifdef WITH_GUI
#include <wx/wx.h>
#include "DevicePanel.hpp"
#include "../state.hpp"
class ExploitPanel;
class ExploitPanel : public DevicePanel
{
public:
explicit ExploitPanel(MainFrame* frame, wxWindow* parent);
void SetDeviceState(const DeviceState& state) override;
void StartExploit();
private:
wxButton* m_backButton = nullptr;
wxStaticText* m_statusText = nullptr;
};
#endif // WITH_GUI
#endif // EXPLOITPANEL_HPP
+164
View File
@@ -0,0 +1,164 @@
#ifdef WITH_GUI
#include "MainPanel.hpp"
#include <wx/wx.h>
#include <wx/mstream.h>
#include <wx/image.h>
#include <wx/bitmap.h>
#include <wx/statline.h>
#include "AppFrame.hpp"
#include "DevicePanel.hpp"
#include "../state.hpp"
#include "../gen/images/logo.h"
const char* deviceTextString = "Connect your iPhone, iPod touch, iPad, or AppleTV to begin.";
MainPanel::MainPanel(MainFrame* frame, wxWindow* parent)
: DevicePanel(frame, parent)
{
auto* root = new wxBoxSizer(wxVERTICAL);
wxInitAllImageHandlers();
wxMemoryInputStream stream(logo, logo_len);
wxImage img(stream, wxBITMAP_TYPE_PNG);
wxBitmap bmp(img);
auto* logo = new wxStaticBitmap(this, wxID_ANY, bmp);
auto* titletext = new wxStaticText(this, wxID_ANY, "Welcome to palera1n!");
wxFont titlefont = titletext->GetFont();
titlefont.SetWeight(wxFONTWEIGHT_BOLD);
titletext->SetFont(titlefont);
m_deviceText = new wxStaticText(
this,
wxID_ANY,
deviceTextString
);
auto* left = new wxBoxSizer(wxVERTICAL);
left->Add(titletext, 0, wxTOP | wxLEFT, 10);
left->Add(m_deviceText, 0, wxTOP | wxLEFT, 10);
auto* row = new wxBoxSizer(wxHORIZONTAL);
row->Add(left, 0, wxALIGN_TOP);
row->AddStretchSpacer();
row->Add(logo, 0, wxTOP | wxRIGHT, 10);
root->Add(row, 0, wxEXPAND);
root->Add(new wxStaticLine(this), 0, wxEXPAND | wxALL, 10);
auto* credtext = new wxStaticText(this, wxID_ANY,
"Made by: asdfugil, kok3shidoll, claration, mineek, staturnz\n\n"
"Thanks to: itsnebulalol, llsc12, lrdsnow, nikias (libimobiledevice), Checkra1n\n"
"(Siguza, axi0mx, littlelailo et al.), Procursus (Hayden Seay, Cameron Katri,\n"
"Keto et al.)\n\n"
"With 💖 from C (claration)");
root->Add(credtext, 0, wxLEFT | wxRIGHT, 10);
root->Add(new wxStaticLine(this), 0, wxEXPAND | wxALL, 10);
auto* notetext = new wxStaticText(this, wxID_ANY,
"NOTE: Please ensure you have a backup of your device before applying the\n"
"jailbreak. While data loss is unlikely, we won't be responsible if something goes\n"
"wrong. Use at your own risk.");
wxFont notefont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
notefont.SetPointSize(12);
notefont.SetStyle(wxFONTSTYLE_ITALIC);
notetext->SetFont(notefont);
root->Add(notetext, 0, wxLEFT | wxRIGHT, 10);
root->AddStretchSpacer();
auto* btn = new wxButton(this, wxID_ANY, "Options");
m_startButton = new wxButton(this, wxID_ANY, "Start");
m_startButton->Disable();
btn->Bind(wxEVT_BUTTON, [frame](wxCommandEvent&)
{
frame->ShowSettings();
});
m_startButton->Bind(wxEVT_BUTTON, [frame](wxCommandEvent&)
{
if (frame->GetDeviceState().mode == DeviceMode::Normal)
{
frame->ShowRecovery();
}
else if (frame->GetDeviceState().mode == DeviceMode::Recovery)
{
frame->ShowDfu();
}
});
auto* bottomRow = new wxBoxSizer(wxHORIZONTAL);
bottomRow->AddStretchSpacer();
bottomRow->Add(btn, 0, wxALL, 10);
bottomRow->Add(m_startButton, 0, wxALL, 10);
root->Add(bottomRow, 0, wxEXPAND);
SetSizer(root);
}
void MainPanel::SetDeviceState(const DeviceState& state)
{
DevicePanel::SetDeviceState(state);
if (m_deviceText)
{
if (!state.connected)
{
m_deviceText->SetLabel(deviceTextString);
m_startButton->Enable(false);
}
else
{
const std::string versionString =
state.productVersion.empty() ? "Unknown" : state.productVersion;
const std::string productString =
state.productType.empty() ? "Unknown" : state.productType;
const std::string ecidString = state.ecid != 0 ? ("ECID: " + std::to_string(state.ecid)) : "ECID: Unknown";
switch (state.mode)
{
case DeviceMode::Normal:
if (state.isSupported) {
m_deviceText->SetLabel("Connected " + productString + " (iOS " + versionString + ") in normal mode.\n" + ecidString);
m_startButton->Enable();
} else {
m_deviceText->SetLabel("Sorry, " + productString + " (iOS " + versionString + ") is not supported.\n" + ecidString);
m_startButton->Enable(false);
}
break;
case DeviceMode::Recovery:
if (state.isSupported) {
m_deviceText->SetLabel("Connected " + productString + " in recovery mode.\n" + ecidString);
m_startButton->Enable();
} else {
m_deviceText->SetLabel("Sorry, " + productString + " is not supported.\n" + ecidString);
m_startButton->Enable(false);
}
break;
case DeviceMode::DFU:
m_deviceText->SetLabel("Sorry, DFU mode is not supported.");
m_startButton->Enable(false);
break;
case DeviceMode::None:
m_deviceText->SetLabel(deviceTextString);
m_startButton->Enable(false);
break;
}
}
}
}
#endif
+23
View File
@@ -0,0 +1,23 @@
#ifndef MAINPANEL_H
#define MAINPANEL_H
#ifdef WITH_GUI
#include <wx/wx.h>
#include "DevicePanel.hpp"
#include "../state.hpp"
class MainPanel;
class MainPanel : public DevicePanel
{
public:
explicit MainPanel(MainFrame* frame, wxWindow* parent);
void SetDeviceState(const DeviceState& state) override;
private:
wxStaticText* m_deviceText = nullptr;
wxButton* m_startButton = nullptr;
};
#endif // WITH_GUI
#endif // MAINPANEL_H
+130
View File
@@ -0,0 +1,130 @@
#ifdef WITH_GUI
#include "RecoveryPanel.hpp"
#include <wx/wx.h>
#include "AppFrame.hpp"
#include "DevicePanel.hpp"
#include "../state.hpp"
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
#include <libirecovery.h>
RecoveryPanel::RecoveryPanel(MainFrame* frame, wxWindow* parent)
: DevicePanel(frame, parent)
{
auto* root = new wxBoxSizer(wxVERTICAL);
root->Add(new wxStaticText(this, wxID_ANY,
"The device needs to be put into DFU mode to apply the jailbreak. This is a\n"
"manual process and we will guide you through it.\n\n"
"In order to prevent filesystem corruption through hard reset, the device will\n"
"be put into recovery mode first. Click next when you are ready."), 0, wxALL, 10);
m_statusText = new wxStaticText(this, wxID_ANY, "");
root->Add(m_statusText, 0, wxALL, 10);
m_backButton = new wxButton(this, wxID_ANY, "Back");
m_nextButton = new wxButton(this, wxID_ANY, "Next");
m_backButton->Bind(wxEVT_BUTTON, [frame](wxCommandEvent&)
{
frame->ShowMain();
});
m_nextButton->Bind(wxEVT_BUTTON, [this](wxCommandEvent&)
{
m_statusText->SetLabel("Entering recovery mode...");
m_backButton->Disable();
m_nextButton->Disable();
EnterRecoveryMode();
});
m_timer.Bind(wxEVT_TIMER, [this](wxTimerEvent&)
{
m_backButton->Enable();
m_nextButton->Enable();
m_isEnteringRecovery = false;
GetMainFrame()->ShowDfu();
m_statusText->SetLabel("");
});
auto* bottomRow = new wxBoxSizer(wxHORIZONTAL);
bottomRow->AddStretchSpacer();
bottomRow->Add(m_backButton, 0, wxALL, 10);
bottomRow->Add(m_nextButton, 0, wxALL, 10);
root->AddStretchSpacer();
root->Add(bottomRow, 0, wxEXPAND);
SetSizer(root);
}
void RecoveryPanel::SetDeviceState(const DeviceState& state)
{
DevicePanel::SetDeviceState(state);
if (!(this->IsShown()))
return;
if (m_isEnteringRecovery && state.mode == DeviceMode::Recovery)
{
m_statusText->SetLabel("Device is now in recovery mode.");
m_timer.StartOnce(3000);
}
if (m_isEnteringRecovery && state.mode == DeviceMode::Normal)
{
m_isEnteringRecovery = false;
m_statusText->SetLabel("Hmm... It seems like the device didn't enter recovery mode. Please try again.");
m_backButton->Enable();
m_nextButton->Enable();
}
if (!m_isEnteringRecovery && state.mode == DeviceMode::None)
{
m_backButton->Enable();
m_nextButton->Enable();
GetMainFrame()->ShowMain();
}
}
void RecoveryPanel::EnterRecoveryMode()
{
const auto& state = GetDeviceState();
if (!state.connected)
return;
idevice_t device = nullptr;
lockdownd_client_t client = nullptr;
if (idevice_new(&device, state.udid.c_str()) != IDEVICE_E_SUCCESS)
return;
if (lockdownd_client_new_with_handshake(
device,
&client,
"palera1n") != LOCKDOWN_E_SUCCESS)
{
idevice_free(device);
return;
}
m_isEnteringRecovery = true;
lockdownd_enter_recovery(client);
lockdownd_client_free(client);
idevice_free(device);
}
void RecoveryPanel::SetStatusText(const wxString& text)
{
m_statusText->SetLabel(text);
}
#endif
+28
View File
@@ -0,0 +1,28 @@
#ifndef RECOVERYPANEL_H
#define RECOVERYPANEL_H
#ifdef WITH_GUI
#include <wx/wx.h>
#include "DevicePanel.hpp"
class RecoveryPanel;
class RecoveryPanel : public DevicePanel
{
public:
explicit RecoveryPanel(MainFrame* frame, wxWindow* parent);
void SetDeviceState(const DeviceState& state) override;
void SetStatusText(const wxString& text);
void EnterRecoveryMode();
private:
wxButton* m_backButton = nullptr;
wxButton* m_nextButton = nullptr;
wxStaticText* m_statusText = nullptr;
wxTimer m_timer;
bool m_isEnteringRecovery = false;
};
#endif // WITH_GUI
#endif // RECOVERYPANEL_H
+84
View File
@@ -0,0 +1,84 @@
#ifdef WITH_GUI
#include "SettingsPanel.hpp"
#include <wx/wx.h>
#include "AppFrame.hpp"
#include "DevicePanel.hpp"
#include "../utils/constants.h"
#include "../utils/paleinfo.h"
SettingsPanel::SettingsPanel(MainFrame* frame, wxWindow* parent)
: DevicePanel(frame, parent)
{
auto* root = new wxBoxSizer(wxVERTICAL);
root->Add(new wxStaticText(this, wxID_ANY,
"You may set the following options. If you don't know what they mean you'll\n"
"probably have no reason to set them."), 0, wxALL, 10);
auto* option_safemode = new wxCheckBox(this, wxID_ANY, "Safe Mode");
auto* option_verbose = new wxCheckBox(this, wxID_ANY, "Verbose Boot");
auto* option_revert = new wxCheckBox(this, wxID_ANY, "Restore System");
auto* option_dark_blockchain = new wxCheckBox(this, wxID_ANY, "Dark Blockchain");
option_safemode->SetValue(palerain_flags & palerain_option_safemode);
option_verbose->SetValue(palerain_flags & palerain_option_verbose_boot);
option_revert->SetValue(palerain_flags & palerain_option_force_revert);
option_dark_blockchain->SetValue(true);
option_safemode->Bind(wxEVT_CHECKBOX, [&](wxCommandEvent& e)
{
if (e.IsChecked())
palerain_flags |= palerain_option_safemode;
else
palerain_flags &= ~palerain_option_safemode;
});
option_verbose->Bind(wxEVT_CHECKBOX, [&](wxCommandEvent& e)
{
if (e.IsChecked())
palerain_flags |= palerain_option_verbose_boot;
else
palerain_flags &= ~palerain_option_verbose_boot;
});
option_revert->Bind(wxEVT_CHECKBOX, [&](wxCommandEvent& e)
{
if (e.IsChecked())
palerain_flags |= palerain_option_force_revert;
else
palerain_flags &= ~palerain_option_force_revert;
});
root->Add(option_safemode, 0, wxLEFT | wxRIGHT, 10);
root->Add(option_verbose, 0, wxLEFT | wxRIGHT | wxTOP, 10);
root->Add(new wxStaticText(this, wxID_ANY, "Boot Arguments:"), 0, wxALL, 10);
auto* bootArgs = new wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize);
root->Add(bootArgs, 0, wxLEFT | wxRIGHT | wxEXPAND, 30);
root->Add(option_revert, 0, wxLEFT | wxRIGHT | wxTOP, 10);
root->Add(option_dark_blockchain, 0, wxLEFT | wxRIGHT | wxTOP, 10);
root->AddStretchSpacer();
auto* back = new wxButton(this, wxID_ANY, "Back");
back->Bind(wxEVT_BUTTON, [frame](wxCommandEvent&)
{
frame->ShowMain();
});
auto* bottomRow = new wxBoxSizer(wxHORIZONTAL);
bottomRow->AddStretchSpacer();
bottomRow->Add(back, 0, wxALL, 10);
root->Add(bottomRow, 0, wxEXPAND);
SetSizer(root);
}
#endif // WITH_GUI
+18
View File
@@ -0,0 +1,18 @@
#ifndef SETTINGSPANEL_H
#define SETTINGSPANEL_H
#ifdef WITH_GUI
#include <wx/wx.h>
#include "DevicePanel.hpp"
class SettingsPanel;
class SettingsPanel : public DevicePanel
{
public:
explicit SettingsPanel(MainFrame* frame, wxWindow* parent);
};
#endif // WITH_GUI
#endif // SETTINGSPANEL_H