Add "leisure function" capability
To support scheduling performance-measurement scripts that want to run a number of actions in series, add shell_global_run_at_leisure() to run a callback when all work is finished. The initial implementation of this is not that accurate: we track business in Tweener.js via new shell_global_begin_work(), shell_global_end_work() functions, and we also handle the case where the main loop is continually busy. https://bugzilla.gnome.org/show_bug.cgi?id=618189
This commit is contained in:
parent
2ce746e7dd
commit
a9a513c621
@ -243,12 +243,14 @@ ClutterFrameTicker.prototype = {
|
||||
|
||||
start : function() {
|
||||
this._timeline.start();
|
||||
global.begin_work();
|
||||
},
|
||||
|
||||
stop : function() {
|
||||
this._timeline.stop();
|
||||
this._startTime = -1;
|
||||
this._currentTime = -1;
|
||||
global.end_work();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -57,6 +57,10 @@ struct _ShellGlobal {
|
||||
ClutterActor *root_pixmap;
|
||||
|
||||
gint last_change_screen_width, last_change_screen_height;
|
||||
|
||||
guint work_count;
|
||||
GSList *leisure_closures;
|
||||
guint leisure_function_id;
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -1392,3 +1396,134 @@ shell_global_set_property_mutable (ShellGlobal *global,
|
||||
JS_RemoveRoot (context, &val);
|
||||
return !gjs_log_exception (context, NULL);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ShellLeisureFunction func;
|
||||
gpointer user_data;
|
||||
GDestroyNotify notify;
|
||||
} LeisureClosure;
|
||||
|
||||
static gboolean
|
||||
run_leisure_functions (gpointer data)
|
||||
{
|
||||
ShellGlobal *global = data;
|
||||
GSList *closures;
|
||||
GSList *iter;
|
||||
|
||||
global->leisure_function_id = 0;
|
||||
|
||||
/* We started more work since we scheduled the idle */
|
||||
if (global->work_count > 0)
|
||||
return FALSE;
|
||||
|
||||
closures = global->leisure_closures;
|
||||
global->leisure_closures = NULL;
|
||||
|
||||
for (iter = closures; iter; iter = iter->next)
|
||||
{
|
||||
LeisureClosure *closure = closures->data;
|
||||
closure->func (closure->user_data);
|
||||
|
||||
if (closure->notify)
|
||||
closure->notify (closure->user_data);
|
||||
|
||||
g_slice_free (LeisureClosure, closure);
|
||||
}
|
||||
|
||||
g_slist_free (closures);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
schedule_leisure_functions (ShellGlobal *global)
|
||||
{
|
||||
/* This is called when we think we are ready to run leisure functions
|
||||
* by our own accounting. We try to handle other types of business
|
||||
* (like ClutterAnimation) by adding a low priority idle function.
|
||||
*
|
||||
* This won't work properly if the mainloop goes idle waiting for
|
||||
* the vertical blanking interval or waiting for work being done
|
||||
* in another thread.
|
||||
*/
|
||||
if (!global->leisure_function_id)
|
||||
global->leisure_function_id = g_idle_add_full (G_PRIORITY_LOW,
|
||||
run_leisure_functions,
|
||||
global, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_begin_work:
|
||||
* @global: the #ShellGlobal
|
||||
*
|
||||
* Marks that we are currently doing work. This is used to to track
|
||||
* whether we are busy for the purposes of shell_global_run_at_leisure().
|
||||
* A count is kept and shell_global_end_work() must be called exactly
|
||||
* as many times as shell_global_begin_work().
|
||||
*/
|
||||
void
|
||||
shell_global_begin_work (ShellGlobal *global)
|
||||
{
|
||||
global->work_count++;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_end_work:
|
||||
* @global: the #ShellGlobal
|
||||
*
|
||||
* Marks the end of work that we started with shell_global_begin_work().
|
||||
* If no other work is ongoing and functions have been added with
|
||||
* shell_global_run_at_leisure(), they will be run at the next
|
||||
* opportunity.
|
||||
*/
|
||||
void
|
||||
shell_global_end_work (ShellGlobal *global)
|
||||
{
|
||||
g_return_if_fail (global->work_count > 0);
|
||||
|
||||
global->work_count--;
|
||||
if (global->work_count == 0 && global->leisure_closures != NULL)
|
||||
schedule_leisure_functions (global);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_run_at_leisure:
|
||||
* @global: the #ShellGlobal
|
||||
* @func: function to call at leisure
|
||||
* @user_data: data to pass to @func
|
||||
* @notify: function to call to free @user_data
|
||||
*
|
||||
* Schedules a function to be called the next time the shell is idle.
|
||||
* Idle means here no animations, no redrawing, and no ongoing background
|
||||
* work. Since there is currently no way to hook into the Clutter master
|
||||
* clock and know when is running, the implementation here is somewhat
|
||||
* approximation. Animations done through the shell's Tweener module will
|
||||
* be handled properly, but other animations may be detected as terminating
|
||||
* early if they can be drawn fast enough so that the event loop goes idle
|
||||
* between frames.
|
||||
*
|
||||
* The intent of this function is for performance measurement runs
|
||||
* where a number of actions should be run serially and each action is
|
||||
* timed individually. Using this function for other purposes will
|
||||
* interfere with the ability to use it for performance measurement so
|
||||
* should be avoided.
|
||||
*/
|
||||
void
|
||||
shell_global_run_at_leisure (ShellGlobal *global,
|
||||
ShellLeisureFunction func,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
LeisureClosure *closure = g_slice_new (LeisureClosure);
|
||||
closure->func = func;
|
||||
closure->user_data = user_data;
|
||||
closure->notify = notify;
|
||||
|
||||
global->leisure_closures = g_slist_append (global->leisure_closures,
|
||||
closure);
|
||||
|
||||
if (global->work_count == 0)
|
||||
schedule_leisure_functions (global);
|
||||
}
|
||||
|
@ -101,6 +101,16 @@ gboolean shell_global_set_property_mutable (ShellGlobal *global,
|
||||
const char *property,
|
||||
gboolean mutable);
|
||||
|
||||
void shell_global_begin_work (ShellGlobal *global);
|
||||
void shell_global_end_work (ShellGlobal *global);
|
||||
|
||||
typedef void (*ShellLeisureFunction) (gpointer data);
|
||||
|
||||
void shell_global_run_at_leisure (ShellGlobal *global,
|
||||
ShellLeisureFunction func,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __SHELL_GLOBAL_H__ */
|
||||
|
Loading…
Reference in New Issue
Block a user