Now builds with Vala 0.14: closes #3756
This commit introduces a Scheduler module which deals with the problem of scheduling on the idle or timeout queue unowned SourceFuncs (because the idle and timeout functions require owned delegates). It also takes care of a handful of places where an out parameter was not being set before the method returned, which Vala's new code analysis now picks up.
This commit is contained in:
parent
0fdc45e4ec
commit
fb54fb1847
12 changed files with 168 additions and 28 deletions
|
|
@ -75,18 +75,13 @@ public class MessageListCellRenderer : Gtk.CellRenderer {
|
|||
|
||||
public override void get_size(Gtk.Widget widget, Gdk.Rectangle? cell_area, out int x_offset,
|
||||
out int y_offset, out int width, out int height) {
|
||||
|
||||
if (cell_height == -1 || preview_height == -1 || example_data == null)
|
||||
style_changed(widget);
|
||||
|
||||
if (&x_offset != null)
|
||||
x_offset = 0;
|
||||
if (&y_offset != null)
|
||||
y_offset = 0;
|
||||
if (&width != null)
|
||||
width = 0;
|
||||
if (&height != null)
|
||||
height = cell_height;
|
||||
x_offset = 0;
|
||||
y_offset = 0;
|
||||
width = 0;
|
||||
height = cell_height;
|
||||
}
|
||||
|
||||
public override void render(Cairo.Context ctx, Gtk.Widget widget, Gdk.Rectangle background_area,
|
||||
|
|
|
|||
|
|
@ -222,6 +222,8 @@ public class Geary.Imap.ClientSessionManager {
|
|||
|
||||
private async ClientSession select_examine_async(string folder, bool is_select,
|
||||
out SelectExamineResults results, Cancellable? cancellable) throws Error {
|
||||
results = null;
|
||||
|
||||
ClientSession.Context needed_context = (is_select) ? ClientSession.Context.SELECTED
|
||||
: ClientSession.Context.EXAMINED;
|
||||
foreach (ClientSession session in sessions) {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ public class Geary.Imap.ClientSession {
|
|||
|
||||
// Need this because delegates with targets cannot be stored in ADTs.
|
||||
private class CommandCallback {
|
||||
public SourceFunc callback;
|
||||
public unowned SourceFunc callback;
|
||||
|
||||
public CommandCallback(SourceFunc callback) {
|
||||
this.callback = callback;
|
||||
|
|
@ -50,7 +50,7 @@ public class Geary.Imap.ClientSession {
|
|||
// the multiple transitions are completed
|
||||
private class AsyncParams : Object {
|
||||
public Cancellable? cancellable;
|
||||
public SourceFunc cb;
|
||||
public unowned SourceFunc cb;
|
||||
public CommandResponse? cmd_response = null;
|
||||
public Error? err = null;
|
||||
public bool do_yield = false;
|
||||
|
|
@ -434,7 +434,7 @@ public class Geary.Imap.ClientSession {
|
|||
fsm.issue(Event.SEND_ERROR, null, null, err);
|
||||
connect_params.err = err;
|
||||
|
||||
Idle.add(connect_params.cb);
|
||||
Scheduler.on_idle(connect_params.cb);
|
||||
connect_params = null;
|
||||
|
||||
return;
|
||||
|
|
@ -463,7 +463,7 @@ public class Geary.Imap.ClientSession {
|
|||
fsm.issue(Event.CONNECT_DENIED);
|
||||
}
|
||||
|
||||
Idle.add(connect_params.cb);
|
||||
Scheduler.on_idle(connect_params.cb);
|
||||
connect_params = null;
|
||||
|
||||
return false;
|
||||
|
|
@ -872,7 +872,7 @@ public class Geary.Imap.ClientSession {
|
|||
disconnect_params.err = err;
|
||||
}
|
||||
|
||||
Idle.add(disconnect_params.cb);
|
||||
Scheduler.on_idle(disconnect_params.cb);
|
||||
disconnect_params = null;
|
||||
}
|
||||
|
||||
|
|
@ -1015,7 +1015,7 @@ public class Geary.Imap.ClientSession {
|
|||
success = true;
|
||||
}
|
||||
|
||||
Idle.add(params.cb);
|
||||
Scheduler.on_idle(params.cb);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
|
@ -1058,7 +1058,7 @@ public class Geary.Imap.ClientSession {
|
|||
CommandCallback? cmd_callback = cb_queue.poll();
|
||||
assert(cmd_callback != null);
|
||||
|
||||
Idle.add(cmd_callback.callback);
|
||||
Scheduler.on_idle(cmd_callback.callback);
|
||||
}
|
||||
|
||||
private void on_received_server_data(ServerData server_data) {
|
||||
|
|
@ -1071,7 +1071,7 @@ public class Geary.Imap.ClientSession {
|
|||
CommandCallback? cmd_callback = cb_queue.poll();
|
||||
assert(cmd_callback != null);
|
||||
|
||||
Idle.add(cmd_callback.callback);
|
||||
Scheduler.on_idle(cmd_callback.callback);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
public abstract class Geary.NonblockingAbstractSemaphore {
|
||||
private class Pending {
|
||||
public SourceFunc cb;
|
||||
public unowned SourceFunc cb;
|
||||
public Cancellable? cancellable;
|
||||
public bool passed = false;
|
||||
|
||||
|
|
@ -59,14 +59,14 @@ public abstract class Geary.NonblockingAbstractSemaphore {
|
|||
if (all) {
|
||||
foreach (Pending pending in pending_queue) {
|
||||
pending.passed = passed;
|
||||
Idle.add(pending.cb);
|
||||
Scheduler.on_idle(pending.cb);
|
||||
}
|
||||
|
||||
pending_queue.clear();
|
||||
} else {
|
||||
Pending pending = pending_queue.remove_at(0);
|
||||
pending.passed = passed;
|
||||
Idle.add(pending.cb);
|
||||
Scheduler.on_idle(pending.cb);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -126,7 +126,7 @@ public abstract class Geary.NonblockingAbstractSemaphore {
|
|||
bool removed = pending_queue.remove(pending);
|
||||
assert(removed);
|
||||
|
||||
Idle.add(pending.cb);
|
||||
Scheduler.on_idle(pending.cb);
|
||||
}
|
||||
|
||||
private void on_cancelled() {
|
||||
|
|
|
|||
|
|
@ -215,6 +215,8 @@ public class Geary.Sqlite.MessageLocationTable : Geary.Sqlite.Table {
|
|||
*/
|
||||
public async bool does_ordering_exist_async(int64 folder_id, int64 ordering,
|
||||
out int64 message_id, Cancellable? cancellable = null) throws Error {
|
||||
message_id = Row.INVALID_ID;
|
||||
|
||||
SQLHeavy.Query query = db.prepare(
|
||||
"SELECT message_id FROM MessageLocationTable WHERE folder_id = ? AND ordering = ?");
|
||||
query.bind_int64(0, folder_id);
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ public class Geary.State.MachineDescriptor {
|
|||
public uint state_count { get; private set; }
|
||||
public uint event_count { get; private set; }
|
||||
|
||||
private StateEventToString? state_to_string;
|
||||
private StateEventToString? event_to_string;
|
||||
private unowned StateEventToString? state_to_string;
|
||||
private unowned StateEventToString? event_to_string;
|
||||
|
||||
public MachineDescriptor(string name, uint start_state, uint state_count, uint event_count,
|
||||
StateEventToString? state_to_string, StateEventToString? event_to_string) {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ public class Geary.State.Machine {
|
|||
private Geary.State.MachineDescriptor descriptor;
|
||||
private uint state;
|
||||
private Mapping[,] transitions;
|
||||
private Transition? default_transition;
|
||||
private unowned Transition? default_transition;
|
||||
private bool locked = false;
|
||||
private bool abort_on_no_transition = true;
|
||||
private bool logging = false;
|
||||
|
|
@ -61,7 +61,7 @@ public class Geary.State.Machine {
|
|||
|
||||
unowned Mapping? mapping = transitions[state, event];
|
||||
|
||||
Transition? transition = (mapping != null) ? mapping.transition : default_transition;
|
||||
unowned Transition? transition = (mapping != null) ? mapping.transition : default_transition;
|
||||
if (transition == null) {
|
||||
string msg = "%s: No transition defined for %s@%s".printf(to_string(),
|
||||
descriptor.get_event_string(event), descriptor.get_state_string(state));
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ public delegate uint Geary.State.Transition(uint state, uint event, void *user =
|
|||
public class Geary.State.Mapping {
|
||||
public uint state;
|
||||
public uint event;
|
||||
public Transition transition;
|
||||
public unowned Transition transition;
|
||||
|
||||
public Mapping(uint state, uint event, Transition transition) {
|
||||
this.state = state;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@
|
|||
* simple ref) implements the ReferenceSemantics interface. (Note that the only required field to
|
||||
* implement is manual_ref_count.) The objects that are distributed to callers are subclasses
|
||||
* of SmartReference. When all the SmartReferences are destroyed, the ReferenceSemantics
|
||||
* "freed" signal will fire. Any final references can be dropped and/or clean up can then occur.
|
||||
* "freed" signal will fire. Any final references to the underlying Object can be dropped and/or
|
||||
* clean up can then occur.
|
||||
*
|
||||
* If the ReferenceSemantics object needs all the SmartReferences to drop their reference to it,
|
||||
* fire the "release-now" signal. Although the SmartReferences will still be active in the system,
|
||||
|
|
@ -58,6 +59,10 @@ public interface Geary.ReferenceSemantics : Object {
|
|||
if (--manual_ref_count == 0)
|
||||
freed();
|
||||
}
|
||||
|
||||
public bool is_freed() {
|
||||
return (manual_ref_count == 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
135
src/engine/util/util-scheduler.vala
Normal file
135
src/engine/util/util-scheduler.vala
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/* Copyright 2011 Yorba Foundation
|
||||
*
|
||||
* This software is licensed under the GNU Lesser General Public License
|
||||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Scheduler provides a mechanism for submitting unowned SourceFunc delegates to the Idle and
|
||||
* Timeout event queues. The returned Scheduled object can be used to cancel the callback, or
|
||||
* can be simply dropped (ignored) and the callback will be called at the scheduled time.
|
||||
*/
|
||||
|
||||
namespace Geary.Scheduler {
|
||||
|
||||
private Gee.HashSet<ScheduledInstance>? scheduled_map = null;
|
||||
|
||||
private class ScheduledInstance : Object, Geary.ReferenceSemantics {
|
||||
protected int manual_ref_count { get; protected set; }
|
||||
|
||||
private unowned SourceFunc? cb;
|
||||
private uint sched_id;
|
||||
|
||||
// Can't rely on ReferenceSemantic's "freed" signal because it's possible all the SmartReferences
|
||||
// have been dropped but the callback is still pending. This signal is fired when all references
|
||||
// are dropped and the callback is not pending or has been cancelled.
|
||||
public signal void dead();
|
||||
|
||||
public ScheduledInstance.on_idle(SourceFunc cb, int priority) {
|
||||
this.cb = cb;
|
||||
sched_id = Idle.add(on_callback, priority);
|
||||
|
||||
freed.connect(on_freed);
|
||||
}
|
||||
|
||||
public ScheduledInstance.after_msec(uint msec, SourceFunc cb, int priority) {
|
||||
this.cb = cb;
|
||||
sched_id = Timeout.add(msec, on_callback, priority);
|
||||
|
||||
freed.connect(on_freed);
|
||||
}
|
||||
|
||||
public ScheduledInstance.after_sec(uint sec, SourceFunc cb, int priority) {
|
||||
this.cb = cb;
|
||||
sched_id = Timeout.add_seconds(sec, on_callback, priority);
|
||||
|
||||
freed.connect(on_freed);
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
if (sched_id == 0)
|
||||
return;
|
||||
|
||||
// cancel callback
|
||||
Source.remove(sched_id);
|
||||
|
||||
// mark as cancelled
|
||||
cb = null;
|
||||
sched_id = 0;
|
||||
|
||||
// tell SmartReferences to drop their refs
|
||||
// (this in turn will call "freed", firing the "dead" signal)
|
||||
release_now();
|
||||
}
|
||||
|
||||
private bool on_callback() {
|
||||
bool again = (cb != null) ? cb() : false;
|
||||
|
||||
if (!again) {
|
||||
// mark as cancelled
|
||||
cb = null;
|
||||
sched_id = 0;
|
||||
|
||||
// tell the SmartReferences to drop their refs
|
||||
// (this in turn will call "freed", firing the "dead" signal, unless all refs were
|
||||
// released earlier and the callback was pending, so fire "dead" now)
|
||||
if (is_freed())
|
||||
dead();
|
||||
else
|
||||
release_now();
|
||||
}
|
||||
|
||||
return again;
|
||||
}
|
||||
|
||||
private void on_freed() {
|
||||
// only fire "dead" if marked as cancelled, otherwise wait until callback completes
|
||||
if (sched_id == 0)
|
||||
dead();
|
||||
}
|
||||
}
|
||||
|
||||
public class Scheduled : Geary.SmartReference {
|
||||
internal Scheduled(ScheduledInstance instance) {
|
||||
base (instance);
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
ScheduledInstance? instance = get_reference() as ScheduledInstance;
|
||||
if (instance != null)
|
||||
instance.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
public Scheduled on_idle(SourceFunc cb, int priority = Priority.DEFAULT_IDLE) {
|
||||
return schedule_instance(new ScheduledInstance.on_idle(cb, priority));
|
||||
}
|
||||
|
||||
public Scheduled after_msec(uint msec, SourceFunc cb, int priority = Priority.DEFAULT) {
|
||||
return schedule_instance(new ScheduledInstance.after_msec(msec, cb, priority));
|
||||
}
|
||||
|
||||
public Scheduled after_sec(uint sec, SourceFunc cb, int priority = Priority.DEFAULT) {
|
||||
return schedule_instance(new ScheduledInstance.after_sec(sec, cb, priority));
|
||||
}
|
||||
|
||||
private Scheduled schedule_instance(ScheduledInstance inst) {
|
||||
inst.dead.connect(on_scheduled_dead);
|
||||
|
||||
if (scheduled_map == null)
|
||||
scheduled_map = new Gee.HashSet<ScheduledInstance>();
|
||||
|
||||
scheduled_map.add(inst);
|
||||
|
||||
return new Scheduled(inst);
|
||||
}
|
||||
|
||||
private void on_scheduled_dead(ScheduledInstance inst) {
|
||||
inst.dead.disconnect(on_scheduled_dead);
|
||||
|
||||
bool removed = scheduled_map.remove(inst);
|
||||
assert(removed);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -118,6 +118,7 @@ def build(bld):
|
|||
'../engine/util/util-interfaces.vala',
|
||||
'../engine/util/util-memory.vala',
|
||||
'../engine/util/util-reference-semantics.vala',
|
||||
'../engine/util/util-scheduler.vala',
|
||||
'../engine/util/util-string.vala',
|
||||
'../engine/util/util-trillian.vala'
|
||||
]
|
||||
|
|
|
|||
2
wscript
2
wscript
|
|
@ -23,7 +23,7 @@ def options(opt):
|
|||
def configure(conf):
|
||||
conf.load('compiler_c vala glib2')
|
||||
|
||||
conf.check_vala((0, 12, 0))
|
||||
conf.check_vala((0, 14, 0))
|
||||
|
||||
conf.check_cfg(
|
||||
package='glib-2.0',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue