mirror of https://github.com/OpenTTD/OpenTTD
(svn r22152) [1.1] -Backport from trunk:
- Fix: Windows video driver crashed when it could not go to full screen at the resolution of the configuration file when starting OpenTTD [FS#4521] (r22149) - Fix: Do not run savegame conversion during SlNullPointers; the pointer might not be converted or be NULL at that point (r22146) - Fix: Some valid keycodes were ignored along with the invalid ones (r22142) - Fix: When commands need to invalidate windows, process these events asynchronously before the next redraw. Calling window code directly from command scope uses wrong _current_company and might issue nested DoCommands() which interfer with the running command [FS#4523] (r22141, r22140, r22135, r22134) - Fix: [NewGRF] Skipping only the invalid part of an action14 failed, the rest of the action was skipped instead (r22138)release/1.1
parent
f2d2713f05
commit
5552c0a7e9
|
@ -75,7 +75,7 @@
|
||||||
|
|
||||||
/* Also still print to debug window */
|
/* Also still print to debug window */
|
||||||
DEBUG(ai, level, "[%d] [%c] %s", (uint)_current_company, logc, log->lines[log->pos]);
|
DEBUG(ai, level, "[%d] [%c] %s", (uint)_current_company, logc, log->lines[log->pos]);
|
||||||
InvalidateWindowData(WC_AI_DEBUG, 0, _current_company);
|
InvalidateWindowData(WC_AI_DEBUG, 0, _current_company, true); // breakpoint handling needs calling Invalidate immediately.
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ void AILog::FreeLogPointer()
|
/* static */ void AILog::FreeLogPointer()
|
||||||
|
|
|
@ -74,7 +74,8 @@ static uint16 ParseCode(const char *start, const char *end)
|
||||||
}
|
}
|
||||||
if (end - start == 1) {
|
if (end - start == 1) {
|
||||||
if (*start >= 'a' && *start <= 'z') return *start - ('a'-'A');
|
if (*start >= 'a' && *start <= 'z') return *start - ('a'-'A');
|
||||||
return *start;
|
/* Ignore invalid keycodes */
|
||||||
|
if (*(uint8*)start < 128) return *start;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -99,10 +100,6 @@ static uint16 ParseKeycode(const char *start, const char *end)
|
||||||
if (code & ~WKC_SPECIAL_KEYS) return 0;
|
if (code & ~WKC_SPECIAL_KEYS) return 0;
|
||||||
keycode |= code;
|
keycode |= code;
|
||||||
} else {
|
} else {
|
||||||
/* Ignore invalid keycodes */
|
|
||||||
if (code >= 128) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* Ignore the code if it has more then 1 letter. */
|
/* Ignore the code if it has more then 1 letter. */
|
||||||
if (keycode & ~WKC_SPECIAL_KEYS) return 0;
|
if (keycode & ~WKC_SPECIAL_KEYS) return 0;
|
||||||
keycode |= code;
|
keycode |= code;
|
||||||
|
|
|
@ -435,7 +435,7 @@ struct MainWindow : Window
|
||||||
virtual void OnInvalidateData(int data)
|
virtual void OnInvalidateData(int data)
|
||||||
{
|
{
|
||||||
/* Forward the message to the appropiate toolbar (ingame or scenario editor) */
|
/* Forward the message to the appropiate toolbar (ingame or scenario editor) */
|
||||||
InvalidateWindowData(WC_MAIN_TOOLBAR, 0, data);
|
InvalidateWindowData(WC_MAIN_TOOLBAR, 0, data, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Hotkey<MainWindow> global_hotkeys[];
|
static Hotkey<MainWindow> global_hotkeys[];
|
||||||
|
|
|
@ -198,6 +198,7 @@ public:
|
||||||
if (c != NULL) {
|
if (c != NULL) {
|
||||||
Money old_money = c->money;
|
Money old_money = c->money;
|
||||||
c->money = INT64_MAX;
|
c->money = INT64_MAX;
|
||||||
|
assert(_current_company == _local_company);
|
||||||
CommandCost costclear = DoCommand(tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR);
|
CommandCost costclear = DoCommand(tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR);
|
||||||
c->money = old_money;
|
c->money = old_money;
|
||||||
if (costclear.Succeeded()) {
|
if (costclear.Succeeded()) {
|
||||||
|
@ -329,6 +330,16 @@ public:
|
||||||
{
|
{
|
||||||
::ShowNewGRFInspectWindow(GetGrfSpecFeature(this->tile), this->tile);
|
::ShowNewGRFInspectWindow(GetGrfSpecFeature(this->tile), this->tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void OnInvalidateData(int data)
|
||||||
|
{
|
||||||
|
switch (data) {
|
||||||
|
case 1:
|
||||||
|
/* ReInit, "debug" sprite might have changed */
|
||||||
|
this->ReInit();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -6727,6 +6727,8 @@ static bool ChangeGRFParamValueNames(ByteReader *buf)
|
||||||
if (type != 'T' || id > _cur_parameter->max_value) {
|
if (type != 'T' || id > _cur_parameter->max_value) {
|
||||||
grfmsg(2, "StaticGRFInfo: all child nodes of 'INFO'->'PARA'->param_num->'VALU' should have type 't' and the value/bit number as id");
|
grfmsg(2, "StaticGRFInfo: all child nodes of 'INFO'->'PARA'->param_num->'VALU' should have type 't' and the value/bit number as id");
|
||||||
if (!SkipUnknownInfo(buf, type)) return false;
|
if (!SkipUnknownInfo(buf, type)) return false;
|
||||||
|
type = buf->ReadByte();
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte langid = buf->ReadByte();
|
byte langid = buf->ReadByte();
|
||||||
|
@ -6770,7 +6772,9 @@ static bool HandleParameterInfo(ByteReader *buf)
|
||||||
uint32 id = buf->ReadDWord();
|
uint32 id = buf->ReadDWord();
|
||||||
if (type != 'C' || id >= _cur_grfconfig->num_valid_params) {
|
if (type != 'C' || id >= _cur_grfconfig->num_valid_params) {
|
||||||
grfmsg(2, "StaticGRFInfo: all child nodes of 'INFO'->'PARA' should have type 'C' and their parameter number as id");
|
grfmsg(2, "StaticGRFInfo: all child nodes of 'INFO'->'PARA' should have type 'C' and their parameter number as id");
|
||||||
return SkipUnknownInfo(buf, type);
|
if (!SkipUnknownInfo(buf, type)) return false;
|
||||||
|
type = buf->ReadByte();
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (id >= _cur_grfconfig->param_info.Length()) {
|
if (id >= _cur_grfconfig->param_info.Length()) {
|
||||||
|
|
|
@ -518,9 +518,10 @@ void DeleteNewGRFInspectWindow(GrfSpecFeature feature, uint index)
|
||||||
WindowNumber wno = GetInspectWindowNumber(feature, index);
|
WindowNumber wno = GetInspectWindowNumber(feature, index);
|
||||||
DeleteWindowById(WC_NEWGRF_INSPECT, wno);
|
DeleteWindowById(WC_NEWGRF_INSPECT, wno);
|
||||||
|
|
||||||
/* Reinitialise the land information window to remove the "debug" sprite if needed. */
|
/* Reinitialise the land information window to remove the "debug" sprite if needed.
|
||||||
Window *w = FindWindowById(WC_LAND_INFO, 0);
|
* Note: Since we might be called from a command here, it is important to not execute
|
||||||
if (w != NULL) w->ReInit();
|
* the invalidation immediately. The landinfo window tests commands itself. */
|
||||||
|
InvalidateWindowData(WC_LAND_INFO, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -450,6 +450,11 @@ static void SlNullPointers()
|
||||||
{
|
{
|
||||||
_sl.action = SLA_NULL;
|
_sl.action = SLA_NULL;
|
||||||
|
|
||||||
|
/* We don't want any savegame conversion code to run
|
||||||
|
* during NULLing; especially those that try to get
|
||||||
|
* pointers from other pools. */
|
||||||
|
_sl_version = SAVEGAME_VERSION;
|
||||||
|
|
||||||
DEBUG(sl, 1, "Nulling pointers");
|
DEBUG(sl, 1, "Nulling pointers");
|
||||||
|
|
||||||
FOR_ALL_CHUNK_HANDLERS(ch) {
|
FOR_ALL_CHUNK_HANDLERS(ch) {
|
||||||
|
|
|
@ -264,7 +264,7 @@ void Train::ConsistChanged(bool same_length)
|
||||||
if (this->IsFrontEngine()) {
|
if (this->IsFrontEngine()) {
|
||||||
this->UpdateAcceleration();
|
this->UpdateAcceleration();
|
||||||
SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
|
SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
|
||||||
InvalidateWindowData(WC_VEHICLE_REFIT, this->index);
|
InvalidateWindowData(WC_VEHICLE_REFIT, this->index); // Important, do not invalidate immediately. The refit window tests commands.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1089,7 +1089,7 @@ static void NormaliseTrainHead(Train *head)
|
||||||
if (!head->IsFrontEngine()) return;
|
if (!head->IsFrontEngine()) return;
|
||||||
|
|
||||||
/* Update the refit button and window */
|
/* Update the refit button and window */
|
||||||
InvalidateWindowData(WC_VEHICLE_REFIT, head->index);
|
InvalidateWindowData(WC_VEHICLE_REFIT, head->index); // Important, do not invalidate immediately. The refit window tests commands.
|
||||||
SetWindowWidgetDirty(WC_VEHICLE_VIEW, head->index, VVW_WIDGET_REFIT_VEH);
|
SetWindowWidgetDirty(WC_VEHICLE_VIEW, head->index, VVW_WIDGET_REFIT_VEH);
|
||||||
|
|
||||||
/* If we don't have a unit number yet, set one. */
|
/* If we don't have a unit number yet, set one. */
|
||||||
|
|
|
@ -2270,7 +2270,7 @@ void Vehicle::RemoveFromShared()
|
||||||
} else if (were_first) {
|
} else if (were_first) {
|
||||||
/* If we were the first one, update to the new first one.
|
/* If we were the first one, update to the new first one.
|
||||||
* Note: FirstShared() is already the new first */
|
* Note: FirstShared() is already the new first */
|
||||||
InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.Pack(), this->FirstShared()->index | (1U << 31));
|
InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.Pack(), this->FirstShared()->index | (1U << 31), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->next_shared = NULL;
|
this->next_shared = NULL;
|
||||||
|
|
|
@ -585,6 +585,7 @@ struct RefitWindow : public Window {
|
||||||
*/
|
*/
|
||||||
StringID GetCapacityString(RefitOption *option) const
|
StringID GetCapacityString(RefitOption *option) const
|
||||||
{
|
{
|
||||||
|
assert(_current_company == _local_company);
|
||||||
Vehicle *v = Vehicle::Get(this->window_number);
|
Vehicle *v = Vehicle::Get(this->window_number);
|
||||||
CommandCost cost = DoCommand(v->tile, this->selected_vehicle, option->cargo | option->subtype << 8 |
|
CommandCost cost = DoCommand(v->tile, this->selected_vehicle, option->cargo | option->subtype << 8 |
|
||||||
this->num_vehicles << 16, DC_QUERY_COST, GetCmdRefitVeh(v->type));
|
this->num_vehicles << 16, DC_QUERY_COST, GetCmdRefitVeh(v->type));
|
||||||
|
@ -1119,7 +1120,7 @@ static inline void ChangeVehicleWindow(WindowClass window_class, VehicleID from_
|
||||||
_thd.window_number = to_index;
|
_thd.window_number = to_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Notify the window */
|
/* Notify the window immediately, without scheduling. */
|
||||||
w->InvalidateData();
|
w->InvalidateData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -224,7 +224,7 @@ static void CALLBACK TrackMouseTimerProc(HWND hwnd, UINT msg, UINT event, DWORD
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool MakeWindow(bool full_screen)
|
bool VideoDriver_Win32::MakeWindow(bool full_screen)
|
||||||
{
|
{
|
||||||
_fullscreen = full_screen;
|
_fullscreen = full_screen;
|
||||||
|
|
||||||
|
@ -259,11 +259,11 @@ static bool MakeWindow(bool full_screen)
|
||||||
if (ChangeDisplaySettings(&settings, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL) {
|
if (ChangeDisplaySettings(&settings, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL) {
|
||||||
RECT r;
|
RECT r;
|
||||||
GetWindowRect(GetDesktopWindow(), &r);
|
GetWindowRect(GetDesktopWindow(), &r);
|
||||||
return _video_driver->ChangeResolution(r.right - r.left, r.bottom - r.top);
|
return this->ChangeResolution(r.right - r.left, r.bottom - r.top);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ChangeDisplaySettings(&settings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
|
if (ChangeDisplaySettings(&settings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
|
||||||
MakeWindow(false); // don't care about the result
|
this->MakeWindow(false); // don't care about the result
|
||||||
return false; // the request failed
|
return false; // the request failed
|
||||||
}
|
}
|
||||||
} else if (_wnd.fullscreen) {
|
} else if (_wnd.fullscreen) {
|
||||||
|
@ -646,7 +646,7 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP
|
||||||
if (active && minimized) {
|
if (active && minimized) {
|
||||||
/* Restore the game window */
|
/* Restore the game window */
|
||||||
ShowWindow(hwnd, SW_RESTORE);
|
ShowWindow(hwnd, SW_RESTORE);
|
||||||
MakeWindow(true);
|
static_cast<VideoDriver_Win32 *>(_video_driver)->MakeWindow(true);
|
||||||
} else if (!active && !minimized) {
|
} else if (!active && !minimized) {
|
||||||
/* Minimise the window and restore desktop */
|
/* Minimise the window and restore desktop */
|
||||||
ShowWindow(hwnd, SW_MINIMIZE);
|
ShowWindow(hwnd, SW_MINIMIZE);
|
||||||
|
@ -800,7 +800,7 @@ const char *VideoDriver_Win32::Start(const char * const *parm)
|
||||||
_wnd.height_org = _cur_resolution.height;
|
_wnd.height_org = _cur_resolution.height;
|
||||||
|
|
||||||
AllocateDibSection(_cur_resolution.width, _cur_resolution.height);
|
AllocateDibSection(_cur_resolution.width, _cur_resolution.height);
|
||||||
MakeWindow(_fullscreen);
|
this->MakeWindow(_fullscreen);
|
||||||
|
|
||||||
MarkWholeScreenDirty();
|
MarkWholeScreenDirty();
|
||||||
|
|
||||||
|
@ -915,10 +915,10 @@ bool VideoDriver_Win32::ChangeResolution(int w, int h)
|
||||||
_wnd.width = _wnd.width_org = w;
|
_wnd.width = _wnd.width_org = w;
|
||||||
_wnd.height = _wnd.height_org = h;
|
_wnd.height = _wnd.height_org = h;
|
||||||
|
|
||||||
return MakeWindow(_fullscreen); // _wnd.fullscreen screws up ingame resolution switching
|
return this->MakeWindow(_fullscreen); // _wnd.fullscreen screws up ingame resolution switching
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VideoDriver_Win32::ToggleFullscreen(bool full_screen)
|
bool VideoDriver_Win32::ToggleFullscreen(bool full_screen)
|
||||||
{
|
{
|
||||||
return MakeWindow(full_screen);
|
return this->MakeWindow(full_screen);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,8 @@ public:
|
||||||
|
|
||||||
/* virtual */ bool ToggleFullscreen(bool fullscreen);
|
/* virtual */ bool ToggleFullscreen(bool fullscreen);
|
||||||
/* virtual */ const char *GetName() const { return "win32"; }
|
/* virtual */ const char *GetName() const { return "win32"; }
|
||||||
|
|
||||||
|
bool MakeWindow(bool full_screen);
|
||||||
};
|
};
|
||||||
|
|
||||||
class FVideoDriver_Win32: public VideoDriverFactory<FVideoDriver_Win32> {
|
class FVideoDriver_Win32: public VideoDriverFactory<FVideoDriver_Win32> {
|
||||||
|
|
|
@ -2420,6 +2420,7 @@ void UpdateWindows()
|
||||||
|
|
||||||
if (!(w->flags4 & WF_WHITE_BORDER_MASK)) w->SetDirty();
|
if (!(w->flags4 & WF_WHITE_BORDER_MASK)) w->SetDirty();
|
||||||
}
|
}
|
||||||
|
w->ProcessScheduledInvalidations();
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawDirtyBlocks();
|
DrawDirtyBlocks();
|
||||||
|
@ -2476,29 +2477,47 @@ void SetWindowClassesDirty(WindowClass cls)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark window data of the window of a given class and specific window number as invalid (in need of re-computing)
|
* Mark window data of the window of a given class and specific window number as invalid (in need of re-computing)
|
||||||
|
* Note that by default the invalidation is not executed immediately but is scheduled till the next redraw.
|
||||||
|
* The asynchronous execution is important to prevent GUI code being executed from command scope.
|
||||||
* @param cls Window class
|
* @param cls Window class
|
||||||
* @param number Window number within the class
|
* @param number Window number within the class
|
||||||
* @param data The data to invalidate with
|
* @param data The data to invalidate with
|
||||||
|
* @param immediately If true then do not schedule the event, but execute immediately.
|
||||||
*/
|
*/
|
||||||
void InvalidateWindowData(WindowClass cls, WindowNumber number, int data)
|
void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool immediately)
|
||||||
{
|
{
|
||||||
Window *w;
|
Window *w;
|
||||||
FOR_ALL_WINDOWS_FROM_BACK(w) {
|
FOR_ALL_WINDOWS_FROM_BACK(w) {
|
||||||
if (w->window_class == cls && w->window_number == number) w->InvalidateData(data);
|
if (w->window_class == cls && w->window_number == number) {
|
||||||
|
if (immediately) {
|
||||||
|
w->InvalidateData(data);
|
||||||
|
} else {
|
||||||
|
w->ScheduleInvalidateData(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark window data of all windows of a given class as invalid (in need of re-computing)
|
* Mark window data of all windows of a given class as invalid (in need of re-computing)
|
||||||
|
* Note that by default the invalidation is not executed immediately but is scheduled till the next redraw.
|
||||||
|
* The asynchronous execution is important to prevent GUI code being executed from command scope.
|
||||||
* @param cls Window class
|
* @param cls Window class
|
||||||
* @param data The data to invalidate with
|
* @param data The data to invalidate with
|
||||||
|
* @param immediately If true then do not schedule the event, but execute immediately.
|
||||||
*/
|
*/
|
||||||
void InvalidateWindowClassesData(WindowClass cls, int data)
|
void InvalidateWindowClassesData(WindowClass cls, int data, bool immediately)
|
||||||
{
|
{
|
||||||
Window *w;
|
Window *w;
|
||||||
|
|
||||||
FOR_ALL_WINDOWS_FROM_BACK(w) {
|
FOR_ALL_WINDOWS_FROM_BACK(w) {
|
||||||
if (w->window_class == cls) w->InvalidateData(data);
|
if (w->window_class == cls) {
|
||||||
|
if (immediately) {
|
||||||
|
w->InvalidateData(data);
|
||||||
|
} else {
|
||||||
|
w->ScheduleInvalidateData(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,8 +34,8 @@ void ResetWindowSystem();
|
||||||
void SetupColoursAndInitialWindow();
|
void SetupColoursAndInitialWindow();
|
||||||
void InputLoop();
|
void InputLoop();
|
||||||
|
|
||||||
void InvalidateWindowData(WindowClass cls, WindowNumber number, int data = 0);
|
void InvalidateWindowData(WindowClass cls, WindowNumber number, int data = 0, bool immediately = false);
|
||||||
void InvalidateWindowClassesData(WindowClass cls, int data = 0);
|
void InvalidateWindowClassesData(WindowClass cls, int data = 0, bool immediately = false);
|
||||||
|
|
||||||
void DeleteNonVitalWindows();
|
void DeleteNonVitalWindows();
|
||||||
void DeleteAllNonVitalWindows();
|
void DeleteAllNonVitalWindows();
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "company_type.h"
|
#include "company_type.h"
|
||||||
#include "tile_type.h"
|
#include "tile_type.h"
|
||||||
#include "widget_type.h"
|
#include "widget_type.h"
|
||||||
|
#include "core/smallvec_type.hpp"
|
||||||
|
|
||||||
/** State of handling an event. */
|
/** State of handling an event. */
|
||||||
enum EventState {
|
enum EventState {
|
||||||
|
@ -221,6 +222,8 @@ protected:
|
||||||
void InitializePositionSize(int x, int y, int min_width, int min_height);
|
void InitializePositionSize(int x, int y, int min_width, int min_height);
|
||||||
void FindWindowPlacementAndResize(int def_width, int def_height);
|
void FindWindowPlacementAndResize(int def_width, int def_height);
|
||||||
|
|
||||||
|
SmallVector<int, 4> scheduled_invalidation_data; ///< Data of scheduled OnInvalidateData() calls.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Window();
|
Window();
|
||||||
|
|
||||||
|
@ -438,6 +441,28 @@ public:
|
||||||
this->OnInvalidateData(data);
|
this->OnInvalidateData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule a invalidation call for next redraw.
|
||||||
|
* Important for asynchronous invalidation from commands.
|
||||||
|
* @param data The data to invalidate with
|
||||||
|
*/
|
||||||
|
void ScheduleInvalidateData(int data = 0)
|
||||||
|
{
|
||||||
|
this->SetDirty();
|
||||||
|
*this->scheduled_invalidation_data.Append() = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process all scheduled invalidations.
|
||||||
|
*/
|
||||||
|
void ProcessScheduledInvalidations()
|
||||||
|
{
|
||||||
|
for (int *data = this->scheduled_invalidation_data.Begin(); this->window_class != WC_INVALID && data != this->scheduled_invalidation_data.End(); data++) {
|
||||||
|
this->OnInvalidateData(*data);
|
||||||
|
}
|
||||||
|
this->scheduled_invalidation_data.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
/*** Event handling ***/
|
/*** Event handling ***/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue