Commit 85eae645 authored by twanvl's avatar twanvl

debuged some horrible race conditions & deadlocks

parent 418e9bb9
...@@ -144,6 +144,8 @@ void resample_and_clip(const Image& img_in, Image& img_out, wxRect rect) { ...@@ -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) { ...@@ -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 { ...@@ -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() { ...@@ -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() { ...@@ -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() ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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() { ...@@ -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 { ...@@ -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 { ...@@ -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 ...@@ -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() { ...@@ -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() { ...@@ -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 @@ ...@@ -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() { ...@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment