mirror of
https://github.com/aseprite/aseprite.git
synced 2024-10-03 13:32:27 +00:00
Fix crash when loading an extension with invalid dithering matrices (fix #3914)
Before this fix, when installing dithering matrices if Aseprite couldn't find the file of some matrix described in the json, Aseprite would crash (this happened during the installation of an erroneous dithering matrices extension, and after every reboot of Aseprite). The cause of the crash was the absence of the MainWindow instance during the ContextBar creation. When an error occurs, the console is called, but since MainWindows is not yet available, aseprite crashes.
This commit is contained in:
parent
3134bfaa30
commit
f7bc918926
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2018-2022 Igara Studio S.A.
|
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -363,6 +363,7 @@ int App::initialize(const AppOptions& options)
|
|||||||
|
|
||||||
// Create the main window.
|
// Create the main window.
|
||||||
m_mainWindow.reset(new MainWindow);
|
m_mainWindow.reset(new MainWindow);
|
||||||
|
m_mainWindow->initialize();
|
||||||
if (m_mod)
|
if (m_mod)
|
||||||
m_mod->modMainWindow(m_mainWindow.get());
|
m_mod->modMainWindow(m_mainWindow.get());
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "app/cmd/set_pixel_format.h"
|
#include "app/cmd/set_pixel_format.h"
|
||||||
#include "app/commands/command.h"
|
#include "app/commands/command.h"
|
||||||
#include "app/commands/params.h"
|
#include "app/commands/params.h"
|
||||||
|
#include "app/console.h"
|
||||||
#include "app/context_access.h"
|
#include "app/context_access.h"
|
||||||
#include "app/extensions.h"
|
#include "app/extensions.h"
|
||||||
#include "app/i18n/strings.h"
|
#include "app/i18n/strings.h"
|
||||||
@ -533,8 +534,14 @@ void ChangePixelFormatCommand::onLoadParams(const Params& params)
|
|||||||
// Then, if the matrix doesn't exist we try to load it from a file
|
// Then, if the matrix doesn't exist we try to load it from a file
|
||||||
else {
|
else {
|
||||||
render::DitheringMatrix ditMatrix;
|
render::DitheringMatrix ditMatrix;
|
||||||
if (!load_dithering_matrix_from_sprite(matrix, ditMatrix))
|
try {
|
||||||
throw std::runtime_error("Invalid matrix name");
|
load_dithering_matrix_from_sprite(matrix, ditMatrix);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e) {
|
||||||
|
LOG(ERROR, "%s\n", e.what());
|
||||||
|
Console::showException(e);
|
||||||
|
}
|
||||||
|
|
||||||
m_dithering.matrix(ditMatrix);
|
m_dithering.matrix(ditMatrix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,8 +219,8 @@ Extension::DitheringMatrixInfo::DitheringMatrixInfo(const std::string& path,
|
|||||||
const render::DitheringMatrix& Extension::DitheringMatrixInfo::matrix() const
|
const render::DitheringMatrix& Extension::DitheringMatrixInfo::matrix() const
|
||||||
{
|
{
|
||||||
if (!m_loaded) {
|
if (!m_loaded) {
|
||||||
m_loaded = true;
|
|
||||||
load_dithering_matrix_from_sprite(m_path, m_matrix);
|
load_dithering_matrix_from_sprite(m_path, m_matrix);
|
||||||
|
m_loaded = true;
|
||||||
}
|
}
|
||||||
return m_matrix;
|
return m_matrix;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
|
// Copyright (C) 2023 Igara Studio S.A.
|
||||||
// Copyright (C) 2017-2018 David Capello
|
// Copyright (C) 2017-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -15,17 +16,19 @@
|
|||||||
#include "app/file/file.h"
|
#include "app/file/file.h"
|
||||||
#include "doc/layer.h"
|
#include "doc/layer.h"
|
||||||
#include "doc/sprite.h"
|
#include "doc/sprite.h"
|
||||||
|
#include "fmt/format.h"
|
||||||
#include "render/dithering_matrix.h"
|
#include "render/dithering_matrix.h"
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
bool load_dithering_matrix_from_sprite(
|
void load_dithering_matrix_from_sprite(
|
||||||
const std::string& filename,
|
const std::string& filename,
|
||||||
render::DitheringMatrix& matrix)
|
render::DitheringMatrix& matrix)
|
||||||
{
|
{
|
||||||
std::unique_ptr<Doc> doc(load_document(nullptr, filename));
|
std::unique_ptr<Doc> doc(load_document(nullptr, filename));
|
||||||
if (!doc)
|
if (!doc)
|
||||||
return false;
|
throw std::runtime_error(
|
||||||
|
fmt::format("The dithering matrix file {} doesn't exist", filename));
|
||||||
|
|
||||||
doc::Sprite* spr = doc->sprite();
|
doc::Sprite* spr = doc->sprite();
|
||||||
const doc::Layer* lay = (spr && spr->root() ? spr->root()->firstLayer():
|
const doc::Layer* lay = (spr && spr->root() ? spr->root()->firstLayer():
|
||||||
@ -45,8 +48,6 @@ bool load_dithering_matrix_from_sprite(
|
|||||||
else {
|
else {
|
||||||
matrix = render::DitheringMatrix();
|
matrix = render::DitheringMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
|
// Copyright (C) 2023 Igara Studio S.A.
|
||||||
// Copyright (C) 2017 David Capello
|
// Copyright (C) 2017 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -16,7 +17,7 @@ namespace render {
|
|||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
bool load_dithering_matrix_from_sprite(
|
void load_dithering_matrix_from_sprite(
|
||||||
const std::string& filename,
|
const std::string& filename,
|
||||||
render::DitheringMatrix& matrix);
|
render::DitheringMatrix& matrix);
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
// Copyright (C) 2019-2023 Igara Studio S.A.
|
||||||
// Copyright (C) 2017 David Capello
|
// Copyright (C) 2017 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -12,6 +12,7 @@
|
|||||||
#include "app/ui/dithering_selector.h"
|
#include "app/ui/dithering_selector.h"
|
||||||
|
|
||||||
#include "app/app.h"
|
#include "app/app.h"
|
||||||
|
#include "app/console.h"
|
||||||
#include "app/extensions.h"
|
#include "app/extensions.h"
|
||||||
#include "app/i18n/strings.h"
|
#include "app/i18n/strings.h"
|
||||||
#include "app/modules/palettes.h"
|
#include "app/modules/palettes.h"
|
||||||
@ -210,18 +211,30 @@ void DitheringSelector::regenerate()
|
|||||||
render::DitheringMatrix(),
|
render::DitheringMatrix(),
|
||||||
Strings::dithering_selector_no_dithering()));
|
Strings::dithering_selector_no_dithering()));
|
||||||
for (const auto& it : ditheringMatrices) {
|
for (const auto& it : ditheringMatrices) {
|
||||||
|
try {
|
||||||
addItem(new DitherItem(
|
addItem(new DitherItem(
|
||||||
render::DitheringAlgorithm::Ordered,
|
render::DitheringAlgorithm::Ordered,
|
||||||
it.matrix(),
|
it.matrix(),
|
||||||
Strings::dithering_selector_ordered_dithering() + it.name()));
|
Strings::dithering_selector_ordered_dithering() + it.name()));
|
||||||
}
|
}
|
||||||
|
catch (const std::exception& e) {
|
||||||
|
LOG(ERROR, "%s\n", e.what());
|
||||||
|
Console::showException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
for (const auto& it : ditheringMatrices) {
|
for (const auto& it : ditheringMatrices) {
|
||||||
|
try {
|
||||||
addItem(
|
addItem(
|
||||||
new DitherItem(
|
new DitherItem(
|
||||||
render::DitheringAlgorithm::Old,
|
render::DitheringAlgorithm::Old,
|
||||||
it.matrix(),
|
it.matrix(),
|
||||||
Strings::dithering_selector_old_dithering() + it.name()));
|
Strings::dithering_selector_old_dithering() + it.name()));
|
||||||
}
|
}
|
||||||
|
catch (const std::exception& e) {
|
||||||
|
LOG(ERROR, "%s\n", e.what());
|
||||||
|
Console::showException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
addItem(
|
addItem(
|
||||||
new DitherItem(
|
new DitherItem(
|
||||||
render::DitheringAlgorithm::ErrorDiffusion,
|
render::DitheringAlgorithm::ErrorDiffusion,
|
||||||
@ -231,8 +244,15 @@ void DitheringSelector::regenerate()
|
|||||||
case SelectMatrix:
|
case SelectMatrix:
|
||||||
addItem(new DitherItem(render::DitheringMatrix(),
|
addItem(new DitherItem(render::DitheringMatrix(),
|
||||||
Strings::dithering_selector_no_dithering()));
|
Strings::dithering_selector_no_dithering()));
|
||||||
for (auto& it : ditheringMatrices)
|
for (auto& it : ditheringMatrices) {
|
||||||
|
try {
|
||||||
addItem(new DitherItem(it.matrix(), it.name()));
|
addItem(new DitherItem(it.matrix(), it.name()));
|
||||||
|
}
|
||||||
|
catch (const std::exception& e) {
|
||||||
|
LOG(ERROR, "%s\n", e.what());
|
||||||
|
Console::showException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2018-2022 Igara Studio S.A.
|
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -89,6 +89,18 @@ MainWindow::MainWindow()
|
|||||||
#ifdef ENABLE_SCRIPTING
|
#ifdef ENABLE_SCRIPTING
|
||||||
, m_devConsoleView(nullptr)
|
, m_devConsoleView(nullptr)
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// This 'initialize' function is a way to split the creation of the
|
||||||
|
// MainWindow. First a minimal instance of MainWindow is created, then
|
||||||
|
// all UI components that can trigger the Console to report any
|
||||||
|
// unexpected errors/warnings in the initialization. Prior to this,
|
||||||
|
// Aseprite could fail in the same constructor, and the Console didn't
|
||||||
|
// have access to the App::instance()->mainWindow() pointer.
|
||||||
|
//
|
||||||
|
// Refer to https://github.com/aseprite/aseprite/issues/3914
|
||||||
|
void MainWindow::initialize()
|
||||||
{
|
{
|
||||||
m_tooltipManager = new TooltipManager();
|
m_tooltipManager = new TooltipManager();
|
||||||
m_menuBar = new MainMenuBar();
|
m_menuBar = new MainMenuBar();
|
||||||
@ -104,13 +116,13 @@ MainWindow::MainWindow()
|
|||||||
|
|
||||||
m_notifications = new Notifications();
|
m_notifications = new Notifications();
|
||||||
m_statusBar = new StatusBar(m_tooltipManager);
|
m_statusBar = new StatusBar(m_tooltipManager);
|
||||||
m_colorBar = new ColorBar(colorBarPlaceholder()->align(),
|
|
||||||
m_tooltipManager);
|
|
||||||
m_contextBar = new ContextBar(m_tooltipManager, m_colorBar);
|
|
||||||
m_toolBar = new ToolBar();
|
m_toolBar = new ToolBar();
|
||||||
m_tabsBar = new WorkspaceTabs(this);
|
m_tabsBar = new WorkspaceTabs(this);
|
||||||
m_workspace = new Workspace();
|
m_workspace = new Workspace();
|
||||||
m_previewEditor = new PreviewEditorWindow();
|
m_previewEditor = new PreviewEditorWindow();
|
||||||
|
m_colorBar = new ColorBar(colorBarPlaceholder()->align(),
|
||||||
|
m_tooltipManager);
|
||||||
|
m_contextBar = new ContextBar(m_tooltipManager, m_colorBar);
|
||||||
|
|
||||||
// The timeline (AniControls) tooltips will use the keyboard
|
// The timeline (AniControls) tooltips will use the keyboard
|
||||||
// shortcuts loaded above.
|
// shortcuts loaded above.
|
||||||
@ -168,33 +180,37 @@ MainWindow::~MainWindow()
|
|||||||
|
|
||||||
#ifdef ENABLE_SCRIPTING
|
#ifdef ENABLE_SCRIPTING
|
||||||
if (m_devConsoleView) {
|
if (m_devConsoleView) {
|
||||||
if (m_devConsoleView->parent())
|
if (m_devConsoleView->parent() && m_workspace)
|
||||||
m_workspace->removeView(m_devConsoleView);
|
m_workspace->removeView(m_devConsoleView);
|
||||||
delete m_devConsoleView;
|
delete m_devConsoleView;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (m_browserView) {
|
if (m_browserView) {
|
||||||
if (m_browserView->parent())
|
if (m_browserView->parent() && m_workspace)
|
||||||
m_workspace->removeView(m_browserView);
|
m_workspace->removeView(m_browserView);
|
||||||
delete m_browserView;
|
delete m_browserView;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_homeView) {
|
if (m_homeView) {
|
||||||
if (m_homeView->parent())
|
if (m_homeView->parent() && m_workspace)
|
||||||
m_workspace->removeView(m_homeView);
|
m_workspace->removeView(m_homeView);
|
||||||
delete m_homeView;
|
delete m_homeView;
|
||||||
}
|
}
|
||||||
|
if (m_contextBar)
|
||||||
delete m_contextBar;
|
delete m_contextBar;
|
||||||
|
if (m_previewEditor)
|
||||||
delete m_previewEditor;
|
delete m_previewEditor;
|
||||||
|
|
||||||
// Destroy the workspace first so ~Editor can dettach slots from
|
// Destroy the workspace first so ~Editor can dettach slots from
|
||||||
// ColorBar. TODO this is a terrible hack for slot/signal stuff,
|
// ColorBar. TODO this is a terrible hack for slot/signal stuff,
|
||||||
// connections should be handle in a better/safer way.
|
// connections should be handle in a better/safer way.
|
||||||
|
if (m_workspace)
|
||||||
delete m_workspace;
|
delete m_workspace;
|
||||||
|
|
||||||
// Remove the root-menu from the menu-bar (because the rootmenu
|
// Remove the root-menu from the menu-bar (because the rootmenu
|
||||||
// module should destroy it).
|
// module should destroy it).
|
||||||
|
if (m_menuBar)
|
||||||
m_menuBar->setMenu(NULL);
|
m_menuBar->setMenu(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2018-2022 Igara Studio S.A.
|
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -70,6 +70,7 @@ namespace app {
|
|||||||
void updateConsentCheckbox();
|
void updateConsentCheckbox();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void initialize();
|
||||||
void start();
|
void start();
|
||||||
void showNotification(INotificationDelegate* del);
|
void showNotification(INotificationDelegate* del);
|
||||||
void showHomeOnOpen();
|
void showHomeOnOpen();
|
||||||
|
Loading…
Reference in New Issue
Block a user