bare-gtk 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CMakeLists.txt +16 -2
- package/README.md +35 -1
- package/binding.c +350 -1
- package/index.d.ts +65 -0
- package/index.js +32 -0
- package/lib/adjustment.d.ts +21 -0
- package/lib/adjustment.h +112 -0
- package/lib/adjustment.js +24 -0
- package/lib/bridging.h +347 -0
- package/lib/clipboard.d.ts +22 -0
- package/lib/clipboard.h +176 -0
- package/lib/clipboard.js +18 -0
- package/lib/constants.d.ts +40 -0
- package/lib/constants.js +51 -0
- package/lib/css-provider.d.ts +13 -0
- package/lib/css-provider.h +56 -0
- package/lib/css-provider.js +14 -0
- package/lib/cursor.d.ts +35 -0
- package/lib/cursor.h +220 -0
- package/lib/cursor.js +45 -0
- package/lib/device.d.ts +13 -0
- package/lib/device.h +35 -0
- package/lib/device.js +8 -0
- package/lib/dialog.d.ts +41 -0
- package/lib/dialog.js +37 -0
- package/lib/display.d.ts +25 -0
- package/lib/display.h +86 -0
- package/lib/display.js +23 -0
- package/lib/editable.h +160 -0
- package/lib/entry.d.ts +93 -0
- package/lib/entry.h +340 -0
- package/lib/entry.js +118 -0
- package/lib/event-controller-focus.d.ts +17 -0
- package/lib/event-controller-focus.h +55 -0
- package/lib/event-controller-focus.js +13 -0
- package/lib/event-controller-motion.d.ts +18 -0
- package/lib/event-controller-motion.h +66 -0
- package/lib/event-controller-motion.js +14 -0
- package/lib/event-controller.d.ts +17 -0
- package/lib/event-controller.h +103 -0
- package/lib/event-controller.js +22 -0
- package/lib/events.js +23 -0
- package/lib/fixed.d.ts +10 -0
- package/lib/fixed.h +28 -0
- package/lib/fixed.js +8 -0
- package/lib/frame-fixed.d.ts +10 -0
- package/lib/frame-fixed.js +12 -0
- package/lib/frame-layout-child.d.ts +17 -0
- package/lib/frame-layout-child.js +16 -0
- package/lib/frame-layout.d.ts +27 -0
- package/lib/frame-layout.h +291 -0
- package/lib/frame-layout.js +19 -0
- package/lib/gesture-click.d.ts +19 -0
- package/lib/gesture-click.h +66 -0
- package/lib/gesture-click.js +14 -0
- package/lib/gesture-drag.d.ts +25 -0
- package/lib/gesture-drag.h +165 -0
- package/lib/gesture-drag.js +23 -0
- package/lib/gesture-single.d.ts +13 -0
- package/lib/gesture-single.js +12 -0
- package/lib/gesture.d.ts +13 -0
- package/lib/gesture.h +73 -0
- package/lib/gesture.js +8 -0
- package/lib/handle.d.ts +5 -0
- package/lib/handle.js +6 -0
- package/lib/label.d.ts +36 -0
- package/lib/label.h +269 -0
- package/lib/label.js +78 -0
- package/lib/layout-child.d.ts +13 -0
- package/lib/layout-child.h +35 -0
- package/lib/layout-child.js +10 -0
- package/lib/layout-manager.d.ts +15 -0
- package/lib/layout-manager.h +42 -0
- package/lib/layout-manager.js +15 -0
- package/lib/message-dialog.d.ts +26 -0
- package/lib/message-dialog.h +190 -0
- package/lib/message-dialog.js +22 -0
- package/lib/monitor.d.ts +32 -0
- package/lib/monitor.h +143 -0
- package/lib/monitor.js +40 -0
- package/lib/native.h +31 -0
- package/lib/object.d.ts +18 -0
- package/lib/object.js +38 -0
- package/lib/paintable.d.ts +10 -0
- package/lib/paintable.js +3 -0
- package/lib/picture.d.ts +22 -0
- package/lib/picture.h +127 -0
- package/lib/picture.js +35 -0
- package/lib/reachable.js +11 -0
- package/lib/runtime.c +21 -4
- package/lib/scrolled-window.d.ts +22 -0
- package/lib/scrolled-window.h +142 -0
- package/lib/scrolled-window.js +37 -0
- package/lib/settings.d.ts +25 -0
- package/lib/settings.h +163 -0
- package/lib/settings.js +34 -0
- package/lib/spinner.d.ts +12 -0
- package/lib/spinner.h +61 -0
- package/lib/spinner.js +22 -0
- package/lib/style-context.d.ts +15 -0
- package/lib/style-context.h +67 -0
- package/lib/style-context.js +9 -0
- package/lib/surface.d.ts +19 -0
- package/lib/surface.h +61 -0
- package/lib/surface.js +22 -0
- package/lib/switch.d.ts +19 -0
- package/lib/switch.h +114 -0
- package/lib/switch.js +30 -0
- package/lib/text-buffer.d.ts +31 -0
- package/lib/text-buffer.h +246 -0
- package/lib/text-buffer.js +33 -0
- package/lib/text-view.d.ts +39 -0
- package/lib/text-view.h +247 -0
- package/lib/text-view.js +63 -0
- package/lib/text.d.ts +18 -0
- package/lib/text.h +189 -0
- package/lib/text.js +31 -0
- package/lib/texture.d.ts +20 -0
- package/lib/texture.h +100 -0
- package/lib/texture.js +17 -0
- package/lib/viewport.d.ts +22 -0
- package/lib/viewport.h +151 -0
- package/lib/viewport.js +38 -0
- package/lib/widget.d.ts +102 -0
- package/lib/widget.h +695 -17
- package/lib/widget.js +176 -11
- package/lib/window.d.ts +31 -0
- package/lib/window.h +142 -61
- package/lib/window.js +32 -11
- package/lib/wrap.js +7 -0
- package/package.json +12 -3
- package/prebuilds/linux-arm64/bare +2 -2
- package/prebuilds/linux-arm64/bare-gtk.bare +0 -0
- package/prebuilds/linux-x64/bare +2 -2
- package/prebuilds/linux-x64/bare-gtk.bare +0 -0
package/lib/adjustment.h
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#ifndef BARE_GTK_ADJUSTMENT_H
|
|
2
|
+
#define BARE_GTK_ADJUSTMENT_H
|
|
3
|
+
|
|
4
|
+
#include <assert.h>
|
|
5
|
+
#include <js.h>
|
|
6
|
+
|
|
7
|
+
#include <gtk/gtk.h>
|
|
8
|
+
|
|
9
|
+
#include "bridging.h"
|
|
10
|
+
|
|
11
|
+
enum {
|
|
12
|
+
bare_gtk_adjustment_event_value_changed = 1 << 0,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
static void
|
|
16
|
+
bare_gtk_adjustment__on_value_changed(GtkAdjustment *adjustment, gpointer data) {
|
|
17
|
+
bare_gtk_state_t *state = data;
|
|
18
|
+
|
|
19
|
+
if ((bare_gtk__observed(state, adjustment) & bare_gtk_adjustment_event_value_changed) == 0) return;
|
|
20
|
+
|
|
21
|
+
bare_gtk__emit(state, adjustment, "value-changed", 1, (const double[]) {gtk_adjustment_get_value(adjustment)});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static js_value_t *
|
|
25
|
+
bare_gtk_adjustment_event_mask(js_env_t *env, js_callback_info_t *info) {
|
|
26
|
+
int err;
|
|
27
|
+
|
|
28
|
+
size_t argc = 2;
|
|
29
|
+
js_value_t *argv[2];
|
|
30
|
+
|
|
31
|
+
bare_gtk_state_t *state;
|
|
32
|
+
err = js_get_callback_info(env, info, &argc, argv, NULL, (void **) &state);
|
|
33
|
+
assert(err == 0);
|
|
34
|
+
|
|
35
|
+
assert(argc == 2);
|
|
36
|
+
|
|
37
|
+
GtkAdjustment *adjustment;
|
|
38
|
+
err = bare_gobject_read_tag(env, state->registry, argv[0], "adjustment", (gpointer *) &adjustment);
|
|
39
|
+
if (err < 0) return NULL;
|
|
40
|
+
|
|
41
|
+
uint32_t events;
|
|
42
|
+
err = bare_gtk__read_uint32(env, argv[1], "events", &events);
|
|
43
|
+
if (err < 0) return NULL;
|
|
44
|
+
|
|
45
|
+
// Connected once and left connected. The mask decides whether anything is
|
|
46
|
+
// sent.
|
|
47
|
+
if (bare_gtk__observe(state, adjustment, events)) {
|
|
48
|
+
g_signal_connect(adjustment, "value-changed", G_CALLBACK(bare_gtk_adjustment__on_value_changed), state);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return NULL;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
static js_value_t *
|
|
55
|
+
bare_gtk_adjustment_value(js_env_t *env, js_callback_info_t *info) {
|
|
56
|
+
int err;
|
|
57
|
+
|
|
58
|
+
size_t argc = 2;
|
|
59
|
+
js_value_t *argv[2];
|
|
60
|
+
|
|
61
|
+
bare_gtk_state_t *state;
|
|
62
|
+
err = js_get_callback_info(env, info, &argc, argv, NULL, (void **) &state);
|
|
63
|
+
assert(err == 0);
|
|
64
|
+
|
|
65
|
+
assert(argc == 1 || argc == 2);
|
|
66
|
+
|
|
67
|
+
GtkAdjustment *adjustment;
|
|
68
|
+
err = bare_gobject_read_tag(env, state->registry, argv[0], "adjustment", (gpointer *) &adjustment);
|
|
69
|
+
if (err < 0) return NULL;
|
|
70
|
+
|
|
71
|
+
if (argc == 1) {
|
|
72
|
+
js_value_t *result;
|
|
73
|
+
err = js_create_double(env, gtk_adjustment_get_value(adjustment), &result);
|
|
74
|
+
assert(err == 0);
|
|
75
|
+
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
double value;
|
|
80
|
+
err = js_get_value_double(env, argv[1], &value);
|
|
81
|
+
assert(err == 0);
|
|
82
|
+
|
|
83
|
+
gtk_adjustment_set_value(adjustment, value);
|
|
84
|
+
|
|
85
|
+
return NULL;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
static js_value_t *
|
|
89
|
+
bare_gtk_adjustment_upper(js_env_t *env, js_callback_info_t *info) {
|
|
90
|
+
int err;
|
|
91
|
+
|
|
92
|
+
size_t argc = 1;
|
|
93
|
+
js_value_t *argv[1];
|
|
94
|
+
|
|
95
|
+
bare_gtk_state_t *state;
|
|
96
|
+
err = js_get_callback_info(env, info, &argc, argv, NULL, (void **) &state);
|
|
97
|
+
assert(err == 0);
|
|
98
|
+
|
|
99
|
+
assert(argc == 1);
|
|
100
|
+
|
|
101
|
+
GtkAdjustment *adjustment;
|
|
102
|
+
err = bare_gobject_read_tag(env, state->registry, argv[0], "adjustment", (gpointer *) &adjustment);
|
|
103
|
+
if (err < 0) return NULL;
|
|
104
|
+
|
|
105
|
+
js_value_t *result;
|
|
106
|
+
err = js_create_double(env, gtk_adjustment_get_upper(adjustment), &result);
|
|
107
|
+
assert(err == 0);
|
|
108
|
+
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
#endif // BARE_GTK_ADJUSTMENT_H
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const binding = require('../binding')
|
|
2
|
+
const GObject = require('./object')
|
|
3
|
+
|
|
4
|
+
module.exports = exports = class GTKAdjustment extends GObject {
|
|
5
|
+
static _events = {
|
|
6
|
+
'value-changed': binding.ADJUSTMENT_EVENT_VALUE_CHANGED
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
_eventMask(mask) {
|
|
10
|
+
binding.adjustmentEventMask(this._tag, mask)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
get value() {
|
|
14
|
+
return binding.adjustmentValue(this._tag)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
set value(value) {
|
|
18
|
+
binding.adjustmentValue(this._tag, value)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get upper() {
|
|
22
|
+
return binding.adjustmentUpper(this._tag)
|
|
23
|
+
}
|
|
24
|
+
}
|
package/lib/bridging.h
ADDED
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
#ifndef BARE_GTK_BRIDGING_H
|
|
2
|
+
#define BARE_GTK_BRIDGING_H
|
|
3
|
+
|
|
4
|
+
#include <assert.h>
|
|
5
|
+
#include <glib.h>
|
|
6
|
+
#include <js.h>
|
|
7
|
+
#include <stdbool.h>
|
|
8
|
+
#include <stdint.h>
|
|
9
|
+
#include <utf.h>
|
|
10
|
+
|
|
11
|
+
#include <gtk/gtk.h>
|
|
12
|
+
|
|
13
|
+
#include "registry.h"
|
|
14
|
+
|
|
15
|
+
// What the addon keeps between calls. It belongs to one instantiation, because
|
|
16
|
+
// an addon can be loaded more than once in a process. Bindings reach it through
|
|
17
|
+
// their data pointer, and signal handlers through the object they are connected
|
|
18
|
+
// to.
|
|
19
|
+
typedef struct {
|
|
20
|
+
bare_gobject_registry_t *registry;
|
|
21
|
+
js_env_t *env;
|
|
22
|
+
|
|
23
|
+
GHashTable *events;
|
|
24
|
+
|
|
25
|
+
// A label that is never shown, used to measure text in the font a real label
|
|
26
|
+
// draws with. A standalone Pango context would pick a different font. A theme
|
|
27
|
+
// may pad a label, so its inset is measured too.
|
|
28
|
+
GtkWidget *text_probe;
|
|
29
|
+
int text_inset_width;
|
|
30
|
+
int text_inset_height;
|
|
31
|
+
} bare_gtk_state_t;
|
|
32
|
+
|
|
33
|
+
static void
|
|
34
|
+
bare_gtk__on_observed_gone(gpointer data, GObject *object);
|
|
35
|
+
|
|
36
|
+
static void
|
|
37
|
+
bare_gtk__on_state_release(js_env_t *env, void *data, void *finalize_hint) {
|
|
38
|
+
bare_gtk_state_t *state = data;
|
|
39
|
+
|
|
40
|
+
GHashTableIter iter;
|
|
41
|
+
gpointer object;
|
|
42
|
+
|
|
43
|
+
g_hash_table_iter_init(&iter, state->events);
|
|
44
|
+
|
|
45
|
+
while (g_hash_table_iter_next(&iter, &object, NULL)) {
|
|
46
|
+
g_object_weak_unref(G_OBJECT(object), bare_gtk__on_observed_gone, state);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
g_hash_table_destroy(state->events);
|
|
50
|
+
|
|
51
|
+
if (state->text_probe) g_object_unref(state->text_probe);
|
|
52
|
+
|
|
53
|
+
bare_gobject_registry_release(state->registry);
|
|
54
|
+
|
|
55
|
+
g_free(state);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
static bare_gtk_state_t *
|
|
59
|
+
bare_gtk_state_create(js_env_t *env, js_value_t *exports) {
|
|
60
|
+
int err;
|
|
61
|
+
|
|
62
|
+
bare_gtk_state_t *state = g_new0(bare_gtk_state_t, 1);
|
|
63
|
+
|
|
64
|
+
state->registry = bare_gobject_registry_create(env, exports);
|
|
65
|
+
state->env = env;
|
|
66
|
+
|
|
67
|
+
state->events = g_hash_table_new(NULL, NULL);
|
|
68
|
+
|
|
69
|
+
err = js_add_finalizer(env, exports, state, bare_gtk__on_state_release, NULL, NULL);
|
|
70
|
+
assert(err == 0);
|
|
71
|
+
|
|
72
|
+
return state;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
static int
|
|
76
|
+
bare_gtk__read_bool(js_env_t *env, js_value_t *value, const char *name, bool *result) {
|
|
77
|
+
int err;
|
|
78
|
+
|
|
79
|
+
bool is;
|
|
80
|
+
err = js_is_boolean(env, value, &is);
|
|
81
|
+
assert(err == 0);
|
|
82
|
+
|
|
83
|
+
if (!is) {
|
|
84
|
+
err = js_throw_type_errorf(env, NULL, "Expected '%s' to be a boolean", name);
|
|
85
|
+
assert(err == 0);
|
|
86
|
+
|
|
87
|
+
return -1;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
err = js_get_value_bool(env, value, result);
|
|
91
|
+
assert(err == 0);
|
|
92
|
+
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
static int
|
|
97
|
+
bare_gtk__read_number(js_env_t *env, js_value_t *value, const char *name) {
|
|
98
|
+
int err;
|
|
99
|
+
|
|
100
|
+
bool is;
|
|
101
|
+
err = js_is_number(env, value, &is);
|
|
102
|
+
assert(err == 0);
|
|
103
|
+
|
|
104
|
+
if (!is) {
|
|
105
|
+
err = js_throw_type_errorf(env, NULL, "Expected '%s' to be a number", name);
|
|
106
|
+
assert(err == 0);
|
|
107
|
+
|
|
108
|
+
return -1;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return 0;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
static int
|
|
115
|
+
bare_gtk__read_int32(js_env_t *env, js_value_t *value, const char *name, int32_t *result) {
|
|
116
|
+
int err;
|
|
117
|
+
|
|
118
|
+
err = bare_gtk__read_number(env, value, name);
|
|
119
|
+
if (err < 0) return err;
|
|
120
|
+
|
|
121
|
+
err = js_get_value_int32(env, value, result);
|
|
122
|
+
assert(err == 0);
|
|
123
|
+
|
|
124
|
+
return 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
static int
|
|
128
|
+
bare_gtk__read_uint32(js_env_t *env, js_value_t *value, const char *name, uint32_t *result) {
|
|
129
|
+
int err;
|
|
130
|
+
|
|
131
|
+
err = bare_gtk__read_number(env, value, name);
|
|
132
|
+
if (err < 0) return err;
|
|
133
|
+
|
|
134
|
+
err = js_get_value_uint32(env, value, result);
|
|
135
|
+
assert(err == 0);
|
|
136
|
+
|
|
137
|
+
return 0;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
static int
|
|
141
|
+
bare_gtk__read_double(js_env_t *env, js_value_t *value, const char *name, double *result) {
|
|
142
|
+
int err;
|
|
143
|
+
|
|
144
|
+
err = bare_gtk__read_number(env, value, name);
|
|
145
|
+
if (err < 0) return err;
|
|
146
|
+
|
|
147
|
+
err = js_get_value_double(env, value, result);
|
|
148
|
+
assert(err == 0);
|
|
149
|
+
|
|
150
|
+
return 0;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
static int
|
|
154
|
+
bare_gtk__read_string(js_env_t *env, js_value_t *value, const char *name, char **result) {
|
|
155
|
+
int err;
|
|
156
|
+
|
|
157
|
+
bool is;
|
|
158
|
+
err = js_is_string(env, value, &is);
|
|
159
|
+
assert(err == 0);
|
|
160
|
+
|
|
161
|
+
if (!is) {
|
|
162
|
+
err = js_throw_type_errorf(env, NULL, "Expected '%s' to be a string", name);
|
|
163
|
+
assert(err == 0);
|
|
164
|
+
|
|
165
|
+
return -1;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
size_t len;
|
|
169
|
+
err = js_get_value_string_utf8(env, value, NULL, 0, &len);
|
|
170
|
+
assert(err == 0);
|
|
171
|
+
|
|
172
|
+
char *str = g_malloc(len + 1);
|
|
173
|
+
|
|
174
|
+
err = js_get_value_string_utf8(env, value, (utf8_t *) str, len + 1, NULL);
|
|
175
|
+
assert(err == 0);
|
|
176
|
+
|
|
177
|
+
*result = str;
|
|
178
|
+
|
|
179
|
+
return 0;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
static int
|
|
183
|
+
bare_gtk__read_string_or_null(js_env_t *env, js_value_t *value, const char *name, char **result) {
|
|
184
|
+
int err;
|
|
185
|
+
|
|
186
|
+
bool is;
|
|
187
|
+
err = js_is_null(env, value, &is);
|
|
188
|
+
assert(err == 0);
|
|
189
|
+
|
|
190
|
+
if (is) {
|
|
191
|
+
*result = NULL;
|
|
192
|
+
|
|
193
|
+
return 0;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return bare_gtk__read_string(env, value, name, result);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// A GTK call that fails sets a `GError`. Here that becomes a thrown error.
|
|
200
|
+
static int
|
|
201
|
+
bare_gtk__throw(js_env_t *env, GError *error) {
|
|
202
|
+
int err = js_throw_error(env, NULL, error->message);
|
|
203
|
+
assert(err == 0);
|
|
204
|
+
|
|
205
|
+
g_error_free(error);
|
|
206
|
+
|
|
207
|
+
return -1;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
static int
|
|
211
|
+
bare_gtk__read_tag_or_null(js_env_t *env, bare_gobject_registry_t *registry, js_value_t *value, const char *name, gpointer *result) {
|
|
212
|
+
int err;
|
|
213
|
+
|
|
214
|
+
bool is;
|
|
215
|
+
err = js_is_null(env, value, &is);
|
|
216
|
+
assert(err == 0);
|
|
217
|
+
|
|
218
|
+
if (is) {
|
|
219
|
+
*result = NULL;
|
|
220
|
+
|
|
221
|
+
return 0;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return bare_gobject_read_tag(env, registry, value, name, result);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
static js_value_t *
|
|
228
|
+
bare_gtk__create_tag(js_env_t *env, bare_gtk_state_t *state, gpointer object) {
|
|
229
|
+
int err;
|
|
230
|
+
|
|
231
|
+
js_value_t *result;
|
|
232
|
+
|
|
233
|
+
if (object) {
|
|
234
|
+
err = js_create_uint32(env, bare_gobject_tag(state->registry, object), &result);
|
|
235
|
+
} else {
|
|
236
|
+
err = js_get_null(env, &result);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
assert(err == 0);
|
|
240
|
+
|
|
241
|
+
return result;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Each instantiation keeps its own event mask for an object, because objects
|
|
245
|
+
// such as `GtkSettings` are shared by the whole process. The weak reference
|
|
246
|
+
// removes the entry when the object goes away.
|
|
247
|
+
static void
|
|
248
|
+
bare_gtk__on_observed_gone(gpointer data, GObject *object) {
|
|
249
|
+
bare_gtk_state_t *state = data;
|
|
250
|
+
|
|
251
|
+
g_hash_table_remove(state->events, object);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
static uint32_t
|
|
255
|
+
bare_gtk__observed(bare_gtk_state_t *state, gpointer object) {
|
|
256
|
+
return GPOINTER_TO_UINT(g_hash_table_lookup(state->events, object));
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Returns true the first time this state sees the object, which is when it
|
|
260
|
+
// still has to connect its signals.
|
|
261
|
+
static bool
|
|
262
|
+
bare_gtk__observe(bare_gtk_state_t *state, gpointer object, uint32_t events) {
|
|
263
|
+
if (!g_hash_table_insert(state->events, object, GUINT_TO_POINTER(events))) return false;
|
|
264
|
+
|
|
265
|
+
g_object_weak_ref(G_OBJECT(object), bare_gtk__on_observed_gone, state);
|
|
266
|
+
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Emit an edit before it happens, as the range it replaces and the new text.
|
|
271
|
+
static void
|
|
272
|
+
bare_gtk__emit_replacement(bare_gtk_state_t *state, gpointer object, const char *event, const char *text, int start, int end) {
|
|
273
|
+
int err;
|
|
274
|
+
|
|
275
|
+
js_env_t *env = state->env;
|
|
276
|
+
|
|
277
|
+
js_handle_scope_t *scope;
|
|
278
|
+
err = js_open_handle_scope(env, &scope);
|
|
279
|
+
assert(err == 0);
|
|
280
|
+
|
|
281
|
+
js_value_t *wrapper = bare_gobject_lookup(env, state->registry, object);
|
|
282
|
+
|
|
283
|
+
if (wrapper) {
|
|
284
|
+
js_value_t *emit;
|
|
285
|
+
err = js_get_named_property(env, wrapper, "emit", &emit);
|
|
286
|
+
assert(err == 0);
|
|
287
|
+
|
|
288
|
+
js_value_t *argv[4];
|
|
289
|
+
|
|
290
|
+
err = js_create_string_utf8(env, (const utf8_t *) event, (size_t) -1, &argv[0]);
|
|
291
|
+
assert(err == 0);
|
|
292
|
+
|
|
293
|
+
err = js_create_string_utf8(env, (const utf8_t *) (text == NULL ? "" : text), (size_t) -1, &argv[1]);
|
|
294
|
+
assert(err == 0);
|
|
295
|
+
|
|
296
|
+
err = js_create_int32(env, start, &argv[2]);
|
|
297
|
+
assert(err == 0);
|
|
298
|
+
|
|
299
|
+
err = js_create_int32(env, end, &argv[3]);
|
|
300
|
+
assert(err == 0);
|
|
301
|
+
|
|
302
|
+
err = js_call_function(env, wrapper, emit, 4, argv, NULL);
|
|
303
|
+
assert(err == 0 || err == js_pending_exception);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
err = js_close_handle_scope(env, scope);
|
|
307
|
+
assert(err == 0);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
static void
|
|
311
|
+
bare_gtk__emit(bare_gtk_state_t *state, gpointer object, const char *event, size_t argc, const double args[]) {
|
|
312
|
+
int err;
|
|
313
|
+
|
|
314
|
+
js_env_t *env = state->env;
|
|
315
|
+
|
|
316
|
+
js_handle_scope_t *scope;
|
|
317
|
+
err = js_open_handle_scope(env, &scope);
|
|
318
|
+
assert(err == 0);
|
|
319
|
+
|
|
320
|
+
js_value_t *wrapper = bare_gobject_lookup(env, state->registry, object);
|
|
321
|
+
|
|
322
|
+
if (wrapper) {
|
|
323
|
+
js_value_t *emit;
|
|
324
|
+
err = js_get_named_property(env, wrapper, "emit", &emit);
|
|
325
|
+
assert(err == 0);
|
|
326
|
+
|
|
327
|
+
js_value_t *argv[8];
|
|
328
|
+
|
|
329
|
+
assert(argc + 1 <= 8);
|
|
330
|
+
|
|
331
|
+
err = js_create_string_utf8(env, (const utf8_t *) event, (size_t) -1, &argv[0]);
|
|
332
|
+
assert(err == 0);
|
|
333
|
+
|
|
334
|
+
for (size_t i = 0; i < argc; i++) {
|
|
335
|
+
err = js_create_double(env, args[i], &argv[i + 1]);
|
|
336
|
+
assert(err == 0);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
err = js_call_function(env, wrapper, emit, argc + 1, argv, NULL);
|
|
340
|
+
assert(err == 0 || err == js_pending_exception);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
err = js_close_handle_scope(env, scope);
|
|
344
|
+
assert(err == 0);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
#endif // BARE_GTK_BRIDGING_H
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import GObject = require('./object')
|
|
2
|
+
|
|
3
|
+
/** A clipboard, as a `GdkClipboard`. Get one from a `GDKDisplay`. */
|
|
4
|
+
interface GDKClipboard extends GObject {
|
|
5
|
+
/**
|
|
6
|
+
* Read the text on the clipboard. `callback` is called with an error message, or with `null`
|
|
7
|
+
* and the text, which is `null` if there is none.
|
|
8
|
+
*/
|
|
9
|
+
readTextAsync(callback: (error: string | null, text: string | null) => void): void
|
|
10
|
+
|
|
11
|
+
/** Put `text` on the clipboard. */
|
|
12
|
+
setText(text: string): this
|
|
13
|
+
|
|
14
|
+
/** The mime types of what the clipboard holds. */
|
|
15
|
+
readonly formats: string[]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
declare class GDKClipboard {
|
|
19
|
+
protected constructor()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export = GDKClipboard
|
package/lib/clipboard.h
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
#ifndef BARE_GTK_CLIPBOARD_H
|
|
2
|
+
#define BARE_GTK_CLIPBOARD_H
|
|
3
|
+
|
|
4
|
+
#include <assert.h>
|
|
5
|
+
#include <js.h>
|
|
6
|
+
|
|
7
|
+
#include <gtk/gtk.h>
|
|
8
|
+
|
|
9
|
+
#include "bridging.h"
|
|
10
|
+
|
|
11
|
+
// GDK reads a clipboard through a callback, so the caller passes one in.
|
|
12
|
+
typedef struct {
|
|
13
|
+
bare_gtk_state_t *state;
|
|
14
|
+
js_ref_t *callback;
|
|
15
|
+
} bare_gtk_clipboard_read_t;
|
|
16
|
+
|
|
17
|
+
static void
|
|
18
|
+
bare_gtk_clipboard__on_read_text(GObject *source, GAsyncResult *result, gpointer data) {
|
|
19
|
+
int err;
|
|
20
|
+
|
|
21
|
+
bare_gtk_clipboard_read_t *read = data;
|
|
22
|
+
|
|
23
|
+
js_env_t *env = read->state->env;
|
|
24
|
+
|
|
25
|
+
js_handle_scope_t *scope;
|
|
26
|
+
err = js_open_handle_scope(env, &scope);
|
|
27
|
+
assert(err == 0);
|
|
28
|
+
|
|
29
|
+
js_value_t *callback;
|
|
30
|
+
err = js_get_reference_value(env, read->callback, &callback);
|
|
31
|
+
assert(err == 0);
|
|
32
|
+
|
|
33
|
+
GError *error = NULL;
|
|
34
|
+
|
|
35
|
+
char *text = gdk_clipboard_read_text_finish(GDK_CLIPBOARD(source), result, &error);
|
|
36
|
+
|
|
37
|
+
js_value_t *argv[2];
|
|
38
|
+
|
|
39
|
+
if (error == NULL) {
|
|
40
|
+
err = js_get_null(env, &argv[0]);
|
|
41
|
+
assert(err == 0);
|
|
42
|
+
|
|
43
|
+
if (text == NULL) {
|
|
44
|
+
err = js_get_null(env, &argv[1]);
|
|
45
|
+
} else {
|
|
46
|
+
err = js_create_string_utf8(env, (const utf8_t *) text, (size_t) -1, &argv[1]);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
assert(err == 0);
|
|
50
|
+
} else {
|
|
51
|
+
err = js_create_string_utf8(env, (const utf8_t *) error->message, (size_t) -1, &argv[0]);
|
|
52
|
+
assert(err == 0);
|
|
53
|
+
|
|
54
|
+
err = js_get_null(env, &argv[1]);
|
|
55
|
+
assert(err == 0);
|
|
56
|
+
|
|
57
|
+
g_error_free(error);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
g_free(text);
|
|
61
|
+
|
|
62
|
+
js_value_t *receiver;
|
|
63
|
+
err = js_get_null(env, &receiver);
|
|
64
|
+
assert(err == 0);
|
|
65
|
+
|
|
66
|
+
err = js_call_function(env, receiver, callback, 2, argv, NULL);
|
|
67
|
+
(void) err;
|
|
68
|
+
|
|
69
|
+
err = js_delete_reference(env, read->callback);
|
|
70
|
+
assert(err == 0);
|
|
71
|
+
|
|
72
|
+
err = js_close_handle_scope(env, scope);
|
|
73
|
+
assert(err == 0);
|
|
74
|
+
|
|
75
|
+
free(read);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static js_value_t *
|
|
79
|
+
bare_gtk_clipboard_read_text_async(js_env_t *env, js_callback_info_t *info) {
|
|
80
|
+
int err;
|
|
81
|
+
|
|
82
|
+
size_t argc = 2;
|
|
83
|
+
js_value_t *argv[2];
|
|
84
|
+
|
|
85
|
+
bare_gtk_state_t *state;
|
|
86
|
+
err = js_get_callback_info(env, info, &argc, argv, NULL, (void **) &state);
|
|
87
|
+
assert(err == 0);
|
|
88
|
+
|
|
89
|
+
assert(argc == 2);
|
|
90
|
+
|
|
91
|
+
GdkClipboard *clipboard;
|
|
92
|
+
err = bare_gobject_read_tag(env, state->registry, argv[0], "clipboard", (gpointer *) &clipboard);
|
|
93
|
+
if (err < 0) return NULL;
|
|
94
|
+
|
|
95
|
+
bare_gtk_clipboard_read_t *read = malloc(sizeof(bare_gtk_clipboard_read_t));
|
|
96
|
+
|
|
97
|
+
read->state = state;
|
|
98
|
+
|
|
99
|
+
err = js_create_reference(env, argv[1], 1, &read->callback);
|
|
100
|
+
assert(err == 0);
|
|
101
|
+
|
|
102
|
+
gdk_clipboard_read_text_async(clipboard, NULL, bare_gtk_clipboard__on_read_text, read);
|
|
103
|
+
|
|
104
|
+
return NULL;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
static js_value_t *
|
|
108
|
+
bare_gtk_clipboard_set_text(js_env_t *env, js_callback_info_t *info) {
|
|
109
|
+
int err;
|
|
110
|
+
|
|
111
|
+
size_t argc = 2;
|
|
112
|
+
js_value_t *argv[2];
|
|
113
|
+
|
|
114
|
+
bare_gtk_state_t *state;
|
|
115
|
+
err = js_get_callback_info(env, info, &argc, argv, NULL, (void **) &state);
|
|
116
|
+
assert(err == 0);
|
|
117
|
+
|
|
118
|
+
assert(argc == 2);
|
|
119
|
+
|
|
120
|
+
GdkClipboard *clipboard;
|
|
121
|
+
err = bare_gobject_read_tag(env, state->registry, argv[0], "clipboard", (gpointer *) &clipboard);
|
|
122
|
+
if (err < 0) return NULL;
|
|
123
|
+
|
|
124
|
+
char *text;
|
|
125
|
+
err = bare_gtk__read_string(env, argv[1], "text", &text);
|
|
126
|
+
if (err < 0) return NULL;
|
|
127
|
+
|
|
128
|
+
gdk_clipboard_set_text(clipboard, text);
|
|
129
|
+
|
|
130
|
+
free(text);
|
|
131
|
+
|
|
132
|
+
return NULL;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// A `GdkContentFormats` is not a `GObject`, so it crosses as the list of mime
|
|
136
|
+
// types it holds.
|
|
137
|
+
static js_value_t *
|
|
138
|
+
bare_gtk_clipboard_formats(js_env_t *env, js_callback_info_t *info) {
|
|
139
|
+
int err;
|
|
140
|
+
|
|
141
|
+
size_t argc = 1;
|
|
142
|
+
js_value_t *argv[1];
|
|
143
|
+
|
|
144
|
+
bare_gtk_state_t *state;
|
|
145
|
+
err = js_get_callback_info(env, info, &argc, argv, NULL, (void **) &state);
|
|
146
|
+
assert(err == 0);
|
|
147
|
+
|
|
148
|
+
assert(argc == 1);
|
|
149
|
+
|
|
150
|
+
GdkClipboard *clipboard;
|
|
151
|
+
err = bare_gobject_read_tag(env, state->registry, argv[0], "clipboard", (gpointer *) &clipboard);
|
|
152
|
+
if (err < 0) return NULL;
|
|
153
|
+
|
|
154
|
+
GdkContentFormats *formats = gdk_clipboard_get_formats(clipboard);
|
|
155
|
+
|
|
156
|
+
gsize len = 0;
|
|
157
|
+
|
|
158
|
+
const char *const *mime_types = gdk_content_formats_get_mime_types(formats, &len);
|
|
159
|
+
|
|
160
|
+
js_value_t *result;
|
|
161
|
+
err = js_create_array_with_length(env, len, &result);
|
|
162
|
+
assert(err == 0);
|
|
163
|
+
|
|
164
|
+
for (gsize i = 0; i < len; i++) {
|
|
165
|
+
js_value_t *value;
|
|
166
|
+
err = js_create_string_utf8(env, (const utf8_t *) mime_types[i], (size_t) -1, &value);
|
|
167
|
+
assert(err == 0);
|
|
168
|
+
|
|
169
|
+
err = js_set_element(env, result, i, value);
|
|
170
|
+
assert(err == 0);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return result;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
#endif // BARE_GTK_CLIPBOARD_H
|
package/lib/clipboard.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const binding = require('../binding')
|
|
2
|
+
const GObject = require('./object')
|
|
3
|
+
|
|
4
|
+
module.exports = exports = class GDKClipboard extends GObject {
|
|
5
|
+
readTextAsync(callback) {
|
|
6
|
+
binding.clipboardReadTextAsync(this._tag, callback)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
setText(text) {
|
|
10
|
+
binding.clipboardSetText(this._tag, text)
|
|
11
|
+
|
|
12
|
+
return this
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
get formats() {
|
|
16
|
+
return binding.clipboardFormats(this._tag)
|
|
17
|
+
}
|
|
18
|
+
}
|