1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Lang = imports.lang;
const St = imports.gi.St;
const GdkPixbuf = imports.gi.GdkPixbuf;
const Clutter = imports.gi.Clutter;
const Cogl = imports.gi.Cogl;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const byteArray = imports.byteArray;
/*
* UtilMixin:
* Mixes in the given properties in _mixin into the object
*
*/
const Mixin = new Lang.Class({
Name: 'UtilMixin',
_init: function() {
this._lateMixin = {};
},
_mixin: {},
_conserve: [],
attach: function(o) {
if (!this._mixin) return;
if (this._conserve && this._conserve.forEach) {
o._conserved = {};
this._conserve.forEach(function(e) {
if (e in o) {
o._conserved[e] = o[e];
} else if (o.prototype && e in o.prototype) {
o._conserved[e] = o.prototype[e];
} else {
log("WARNING: attempted to conserve property '"+e+"' but not found.");
}
});
}
for (var i in this._mixin) {
o[i] = this._mixin[i];
}
for (var i in this._lateMixin) {
o[i] = this._lateMixin[i]
}
if (this._mixinInit) {
this._mixinInit.apply(o, Array.prototype.slice.call(arguments, 1));
}
}
});
/*
* AsyncTaskQueue:
* Schedules asynchrouns tasks which may not overlap during execution
*
* The scheduled functions are required to take a callback as their last arguments, and all other arguments
* need to be bound using Function.prototype.bind
*/
const AsyncTaskQueue = new Lang.Class({
Name: 'AsyncTaskQueue',
_init: function() {
this._taskList = [];
},
// shedule the async task for execution or execute right away if there's no current task
add: function(task, callback, context) {
this._taskList.push({task: task, callback: callback, context: context});
if (this._taskList.length == 1) this._executeNext();
},
_executeNext: function() {
this._taskList[0].task.call(null, (function() {
if (this._taskList[0].callback) this._taskList[0].callback.apply(this._taskList[0].context, arguments);
this._taskList.shift();
if (this._taskList.length) this._executeNext();
}).bind(this));
}
});
const createActorFromPixmap = function(pixmap, icon_size) {
if (!(pixmap && pixmap.length)) return null;
// pixmap is actually an array of icons, so that hosts can pick the
// best size (here considered as the area covered by the icon)
// XXX: should we use sum of width and height instead? or consider
// only one dimension?
let best = 0;
let bestHeight = pixmap[0][1];
let goal = icon_size;
for (let i = 1; i < pixmap.length; i++) {
let height = pixmap[i][1];
if (Math.abs(goal - height) < Math.abs(goal - bestHeight)) {
best = i;
bestHeight = height;
}
}
let [width, height, imageData] = pixmap[best];
// each image is ARGB32
// XXX: we're not getting a rowstride! let's hope images are compressed enough
let rowstride = width * 4;
return St.TextureCache.get_default().load_from_raw(imageData, imageData.length,
true, width, height, rowstride,
icon_size);
};
//data: GBytes
const createActorFromMemoryImage = function(data) {
var stream = Gio.MemoryInputStream.new_from_bytes(data);
var pixbuf = GdkPixbuf.Pixbuf.new_from_stream(stream, null);
return new St.Icon({ gicon: pixbuf, icon_size: pixbuf.get_width() });
}
//HACK: GLib.Variant.prototype.get_data_as_bytes only exists in recent gjs versions
const variantToGBytes = function(variant) {
if (typeof(GLib.Variant.prototype.get_data_as_bytes) != "undefined") {
return variant.get_data_as_bytes();
} else {
//FIXME: this is very very inefficient. we're sorry.
var data = variant.deep_unpack(); //will create an array of doubles...
var data_length = data.length;
var array = new imports.byteArray.ByteArray(data_length);
for (var i = 0; i < data_length; i++) {
array[i] = data[i];
}
return GLib.ByteArray.free_to_bytes(array); //this can't be correct but it suprisingly works like a charm.
}
}
|