changeset 17487:3801fc917ab1 draft

(svn r22242) -Codechange: Let OnInvalidateData() decide itself what to do immediately in command scope, and what to do asynchronously in GUI-scope.
author frosch <frosch@openttd.org>
date Sun, 13 Mar 2011 21:32:13 +0000
parents e7672bafbe1c
children c94289e6fdf7
files src/window.cpp src/window_func.h src/window_gui.h
diffstat 3 files changed, 36 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -2481,46 +2481,55 @@
 
 /**
  * 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.
+ *
+ * Note that by default the invalidation is not considered to be called from GUI scope.
+ * That means only a part of invalidation is executed immediately. The rest is scheduled for the next redraw.
  * The asynchronous execution is important to prevent GUI code being executed from command scope.
+ * When not in GUI-scope:
+ *  - OnInvalidateData() may not do test-runs on commands, as they might affect the execution of
+ *    the command which triggered the invalidation. (town rating and such)
+ *  - OnInvalidateData() may not rely on _current_company == _local_company.
+ *    This implies that no NewGRF callbacks may be run.
+ *
+ * However, when invalidations are scheduled, then multiple calls may be scheduled before execution starts. Earlier scheduled
+ * invalidations may be called with invalidation-data, which is already invalid at the point of execution.
+ * That means some stuff requires to be executed immediately in command scope, while not everything may be executed in command
+ * scope. While GUI-scope calls have no restrictions on what they may do, they cannot assume the game to still be in the state
+ * when the invalidation was scheduled; passed IDs may have got invalid in the mean time.
+ *
+ * Finally, note that invalidations triggered from commands or the game loop result in OnInvalidateData() being called twice.
+ * Once in command-scope, once in GUI-scope. So make sure to not process differential-changes twice.
+ *
  * @param cls Window class
  * @param number Window number within the class
  * @param data The data to invalidate with
- * @param immediately If true then do not schedule the event, but execute immediately.
+ * @param gui_scope Whether the call is done from GUI scope
  */
-void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool immediately)
+void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope)
 {
 	Window *w;
 	FOR_ALL_WINDOWS_FROM_BACK(w) {
 		if (w->window_class == cls && w->window_number == number) {
-			if (immediately) {
-				w->InvalidateData(data);
-			} else {
-				w->ScheduleInvalidateData(data);
-			}
+			w->InvalidateData(data, gui_scope);
 		}
 	}
 }
 
 /**
  * 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.
+ * Note that by default the invalidation is not considered to be called from GUI scope.
+ * See InvalidateWindowData() for details on GUI-scope vs. command-scope.
  * @param cls Window class
  * @param data The data to invalidate with
- * @param immediately If true then do not schedule the event, but execute immediately.
+ * @param gui_scope Whether the call is done from GUI scope
  */
-void InvalidateWindowClassesData(WindowClass cls, int data, bool immediately)
+void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope)
 {
 	Window *w;
 
 	FOR_ALL_WINDOWS_FROM_BACK(w) {
 		if (w->window_class == cls) {
-			if (immediately) {
-				w->InvalidateData(data);
-			} else {
-				w->ScheduleInvalidateData(data);
-			}
+			w->InvalidateData(data, gui_scope);
 		}
 	}
 }
--- a/src/window_func.h
+++ b/src/window_func.h
@@ -34,8 +34,8 @@
 void SetupColoursAndInitialWindow();
 void InputLoop();
 
-void InvalidateWindowData(WindowClass cls, WindowNumber number, int data = 0, bool immediately = false);
-void InvalidateWindowClassesData(WindowClass cls, int data = 0, bool immediately = false);
+void InvalidateWindowData(WindowClass cls, WindowNumber number, int data = 0, bool gui_scope = false);
+void InvalidateWindowClassesData(WindowClass cls, int data = 0, bool gui_scope = false);
 
 void DeleteNonVitalWindows();
 void DeleteAllNonVitalWindows();
--- a/src/window_gui.h
+++ b/src/window_gui.h
@@ -434,22 +434,16 @@
 	/**
 	 * Mark this window's data as invalid (in need of re-computing)
 	 * @param data The data to invalidate with
+	 * @param gui_scope Whether the funtion is called from GUI scope.
 	 */
-	void InvalidateData(int data = 0)
+	void InvalidateData(int data = 0, bool gui_scope = true)
 	{
 		this->SetDirty();
-		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;
+		if (!gui_scope) {
+			/* Schedule GUI-scope invalidation for next redraw. */
+			*this->scheduled_invalidation_data.Append() = data;
+		}
+		this->OnInvalidateData(data, gui_scope);
 	}
 
 	/**
@@ -458,7 +452,7 @@
 	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->OnInvalidateData(*data, true);
 		}
 		this->scheduled_invalidation_data.Clear();
 	}