mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-12 21:47:00 -04:00
debuged some horrible race conditions & deadlocks
git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@160 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -144,6 +144,8 @@ void resample_and_clip(const Image& img_in, Image& img_out, wxRect rect) {
|
|||||||
// fill an image with 100% transparent, except for the given rectangle
|
// fill an image with 100% transparent, except for the given rectangle
|
||||||
void fill_transparent(Image& img, int dx, int dy, int w, int h) {
|
void fill_transparent(Image& img, int dx, int dy, int w, int h) {
|
||||||
if (!img.HasAlpha()) img.InitAlpha();
|
if (!img.HasAlpha()) img.InitAlpha();
|
||||||
|
memset(img.GetAlpha(), 0, img.GetWidth() * img.GetHeight());
|
||||||
|
/*/?
|
||||||
int iw = img.GetWidth(), ih = img.GetHeight();
|
int iw = img.GetWidth(), ih = img.GetHeight();
|
||||||
Byte* data = img.GetAlpha();
|
Byte* data = img.GetAlpha();
|
||||||
// fill
|
// fill
|
||||||
@@ -160,6 +162,7 @@ void fill_transparent(Image& img, int dx, int dy, int w, int h) {
|
|||||||
for (; y < ih ; ++y) {
|
for (; y < ih ; ++y) {
|
||||||
for (int x = 0 ; x < iw ; ++x) *data++ = 0;
|
for (int x = 0 ; x < iw ; ++x) *data++ = 0;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void resample_preserve_aspect(const Image& img_in, Image& img_out) {
|
void resample_preserve_aspect(const Image& img_in, Image& img_out) {
|
||||||
|
|||||||
@@ -37,8 +37,10 @@ class DropDownHider : public wxEvtHandler {
|
|||||||
// don't just use ev.Skip(), because this event handler will be removed by hiding,
|
// don't just use ev.Skip(), because this event handler will be removed by hiding,
|
||||||
// so there will be no next handler to skip to
|
// so there will be no next handler to skip to
|
||||||
wxEvtHandler* nh = GetNextHandler();
|
wxEvtHandler* nh = GetNextHandler();
|
||||||
|
wxLogDebug(L"close to %p", nh);
|
||||||
list.hide(false);
|
list.hide(false);
|
||||||
if (nh) nh->ProcessEvent(ev);
|
if (nh) nh->ProcessEvent(ev);
|
||||||
|
wxLogDebug(L"/close to %p", nh);
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
// if (t !=10093 && t !=10098 && t !=10097 && t !=10099 && t !=10004 && t !=10062
|
// if (t !=10093 && t !=10098 && t !=10097 && t !=10099 && t !=10004 && t !=10062
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ wxThread::ExitCode ThumbnailThreadWorker::Entry() {
|
|||||||
while (true) {
|
while (true) {
|
||||||
do {
|
do {
|
||||||
Sleep(1);
|
Sleep(1);
|
||||||
if (TestDestroy()) return 0;
|
|
||||||
} while (stop);
|
} while (stop);
|
||||||
// get a request
|
// get a request
|
||||||
{
|
{
|
||||||
@@ -71,9 +70,7 @@ wxThread::ExitCode ThumbnailThreadWorker::Entry() {
|
|||||||
parent->open_requests.pop_front();
|
parent->open_requests.pop_front();
|
||||||
}
|
}
|
||||||
// perform request
|
// perform request
|
||||||
if (TestDestroy()) return 0;
|
|
||||||
Image img = current->generate();
|
Image img = current->generate();
|
||||||
if (TestDestroy()) return 0;
|
|
||||||
// store in cache
|
// store in cache
|
||||||
if (img.Ok()) {
|
if (img.Ok()) {
|
||||||
String filename = image_cache_dir() + safe_filename(current->cache_name) + _(".png");
|
String filename = image_cache_dir() + safe_filename(current->cache_name) + _(".png");
|
||||||
@@ -107,10 +104,6 @@ ThumbnailThread::ThumbnailThread()
|
|||||||
, worker(nullptr)
|
, worker(nullptr)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
ThumbnailThread::~ThumbnailThread() {
|
|
||||||
abortAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ThumbnailThread::request(const ThumbnailRequestP& request) {
|
void ThumbnailThread::request(const ThumbnailRequestP& request) {
|
||||||
assert(wxThread::IsMain());
|
assert(wxThread::IsMain());
|
||||||
// Is the request in progress?
|
// Is the request in progress?
|
||||||
@@ -172,7 +165,7 @@ bool ThumbnailThread::done(void* owner) {
|
|||||||
void ThumbnailThread::abort(void* owner) {
|
void ThumbnailThread::abort(void* owner) {
|
||||||
assert(wxThread::IsMain());
|
assert(wxThread::IsMain());
|
||||||
mutex.Lock();
|
mutex.Lock();
|
||||||
if (worker && worker->current->owner == owner) {
|
if (worker && worker->current && worker->current->owner == owner) {
|
||||||
// a request for this owner is in progress, wait until it is done
|
// a request for this owner is in progress, wait until it is done
|
||||||
worker->stop = true;
|
worker->stop = true;
|
||||||
completed.Wait();
|
completed.Wait();
|
||||||
@@ -183,8 +176,8 @@ void ThumbnailThread::abort(void* owner) {
|
|||||||
for (size_t i = 0 ; i < open_requests.size() ; ) {
|
for (size_t i = 0 ; i < open_requests.size() ; ) {
|
||||||
if (open_requests[i]->owner == owner) {
|
if (open_requests[i]->owner == owner) {
|
||||||
// remove
|
// remove
|
||||||
open_requests.erase(open_requests.begin() + i, open_requests.begin() + i + 1);
|
|
||||||
request_names.erase(open_requests[i]);
|
request_names.erase(open_requests[i]);
|
||||||
|
open_requests.erase(open_requests.begin() + i, open_requests.begin() + i + 1);
|
||||||
} else {
|
} else {
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
@@ -193,8 +186,8 @@ void ThumbnailThread::abort(void* owner) {
|
|||||||
for (size_t i = 0 ; i < closed_requests.size() ; ) {
|
for (size_t i = 0 ; i < closed_requests.size() ; ) {
|
||||||
if (closed_requests[i].first->owner == owner) {
|
if (closed_requests[i].first->owner == owner) {
|
||||||
// remove
|
// remove
|
||||||
closed_requests.erase(closed_requests.begin() + i, closed_requests.begin() + i + 1);
|
|
||||||
request_names.erase(closed_requests[i].first);
|
request_names.erase(closed_requests[i].first);
|
||||||
|
closed_requests.erase(closed_requests.begin() + i, closed_requests.begin() + i + 1);
|
||||||
} else {
|
} else {
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
@@ -208,10 +201,14 @@ void ThumbnailThread::abortAll() {
|
|||||||
open_requests.clear();
|
open_requests.clear();
|
||||||
closed_requests.clear();
|
closed_requests.clear();
|
||||||
request_names.clear();
|
request_names.clear();
|
||||||
if (worker) {
|
// end worker
|
||||||
// a request is in progress, wait until it is done, killing the worker
|
if (worker && worker->current) {
|
||||||
completed.Wait();
|
completed.Wait();
|
||||||
} else {
|
} else {
|
||||||
mutex.Unlock();
|
mutex.Unlock();
|
||||||
}
|
}
|
||||||
|
// There may still be a worker, but if there is, it has no current object, so it is
|
||||||
|
// in, before or after the stop loop. It can do nothing but end.
|
||||||
|
// An unfortunate side effect is that we might leak some memory (of the worker object),
|
||||||
|
// when the thread gets Kill()ed by wx.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ class ThumbnailRequest {
|
|||||||
class ThumbnailThread {
|
class ThumbnailThread {
|
||||||
public:
|
public:
|
||||||
ThumbnailThread();
|
ThumbnailThread();
|
||||||
~ThumbnailThread();
|
|
||||||
|
|
||||||
/// Request a thumbnail, it may be store()d immediatly if the thumbnail is cached
|
/// Request a thumbnail, it may be store()d immediatly if the thumbnail is cached
|
||||||
void request(const ThumbnailRequestP& request);
|
void request(const ThumbnailRequestP& request);
|
||||||
@@ -58,6 +57,7 @@ class ThumbnailThread {
|
|||||||
/// Abort all thumbnail requests for the given owner
|
/// Abort all thumbnail requests for the given owner
|
||||||
void abort(void* owner);
|
void abort(void* owner);
|
||||||
/// Abort all computations
|
/// Abort all computations
|
||||||
|
/** *must* be called at application exit */
|
||||||
void abortAll();
|
void abortAll();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -66,7 +66,9 @@ DropDownChoiceList::DropDownChoiceList(Window* parent, bool is_submenu, ChoiceVa
|
|||||||
, group(group)
|
, group(group)
|
||||||
, cve(cve)
|
, cve(cve)
|
||||||
{
|
{
|
||||||
icon_size.width = 16;
|
icon_size.width = 16;
|
||||||
|
icon_size.height = 16;
|
||||||
|
item_size.height = max(16., item_size.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t DropDownChoiceList::itemCount() const {
|
size_t DropDownChoiceList::itemCount() const {
|
||||||
@@ -183,7 +185,9 @@ void DropDownChoiceList::generateThumbnailImages() {
|
|||||||
|
|
||||||
void DropDownChoiceList::onIdle(wxIdleEvent& ev) {
|
void DropDownChoiceList::onIdle(wxIdleEvent& ev) {
|
||||||
if (!isRoot()) return;
|
if (!isRoot()) return;
|
||||||
thumbnail_thread.done(&cve);
|
if (thumbnail_thread.done(&cve)) {
|
||||||
|
Refresh(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BEGIN_EVENT_TABLE(DropDownChoiceList, DropDownList)
|
BEGIN_EVENT_TABLE(DropDownChoiceList, DropDownList)
|
||||||
@@ -201,6 +205,8 @@ ChoiceValueEditor::~ChoiceValueEditor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ChoiceValueEditor::onLeftDown(const RealPoint& pos, wxMouseEvent& ev) {
|
void ChoiceValueEditor::onLeftDown(const RealPoint& pos, wxMouseEvent& ev) {
|
||||||
|
//HACK TODO REMOVEME
|
||||||
|
thumbnail_thread.abortAll();
|
||||||
drop_down->onMouseInParent(ev, style().popup_style == POPUP_DROPDOWN_IN_PLACE && !nativeLook());
|
drop_down->onMouseInParent(ev, style().popup_style == POPUP_DROPDOWN_IN_PLACE && !nativeLook());
|
||||||
}
|
}
|
||||||
void ChoiceValueEditor::onChar(wxKeyEvent& ev) {
|
void ChoiceValueEditor::onChar(wxKeyEvent& ev) {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <gui/update_checker.hpp>
|
#include <gui/update_checker.hpp>
|
||||||
#include <gui/set/window.hpp>
|
#include <gui/set/window.hpp>
|
||||||
#include <gui/symbol/window.hpp>
|
#include <gui/symbol/window.hpp>
|
||||||
|
#include <gui/thumbnail_thread.hpp>
|
||||||
#include <wx/fs_inet.h>
|
#include <wx/fs_inet.h>
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Main function/class
|
// ----------------------------------------------------------------------------- : Main function/class
|
||||||
@@ -73,6 +74,7 @@ bool MSE::OnInit() {
|
|||||||
// ----------------------------------------------------------------------------- : Exit
|
// ----------------------------------------------------------------------------- : Exit
|
||||||
|
|
||||||
int MSE::OnExit() {
|
int MSE::OnExit() {
|
||||||
|
thumbnail_thread.abortAll();
|
||||||
settings.write();
|
settings.write();
|
||||||
packages.destroy();
|
packages.destroy();
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user