1
/*
2
 *  Capa: Capa Assists Photograph Aquisition
3
 *
4
 *  Copyright (C) 2009 Daniel P. Berrange
5
 *
6
 *  This program is free software: you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation, either version 3 of the License, or
9
 *  (at your option) any later version.
10
 *
11
 *  This program is distributed in the hope that it will be useful,
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  GNU General Public License for more details.
15
 *
16
 *  You should have received a copy of the GNU General Public License
17
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 *
19
 */
20
21
#include <config.h>
22
23
#include "capa-debug.h"
24
#include "capa-plugin-javascript.h"
25
26
#include <string.h>
27
#include <gjs/gjs.h>
28
#include <gjs/gi/object.h>
29
30
#define CAPA_PLUGIN_JAVASCRIPT_GET_PRIVATE(obj)                            \
31
    (G_TYPE_INSTANCE_GET_PRIVATE((obj), CAPA_TYPE_PLUGIN_JAVASCRIPT, CapaPluginJavascriptPrivate))
32
33
struct _CapaPluginJavascriptPrivate {
34
    GjsContext *context;
35
    gboolean active;
36
};
37
38
G_DEFINE_TYPE(CapaPluginJavascript, capa_plugin_javascript, CAPA_TYPE_PLUGIN);
39
40
/* XXX
41
 * Evil hack. THis method is defined in the .so, but not in the
42
 * header files. This is the only apparant way to get the
43
 * JSContext that we need in order to define new global vars
44
 */
45
JSContext* gjs_context_get_context(GjsContext *js_context);
46
47
static void
48
capa_plugin_javascript_set_global(CapaPluginJavascript *plugin,
49
                                  const char *name,
50
                                  GObject *value)
51
{
52
    CapaPluginJavascriptPrivate *priv = plugin->priv;
53
    JSContext *jscontext;
54
    JSObject *jsglobal;
55
    JSObject *jsvalue;
56
57
    /* XXX
58
     * Evil hack. GJS ought to provide a official public API
59
     * for defining a global variable from a GObject.
60
     */
61
    jscontext = gjs_context_get_context(priv->context);
62
    jsglobal = JS_GetGlobalObject(jscontext);
63
    JS_EnterLocalRootScope(jscontext);
64
    jsvalue = gjs_object_from_g_object(jscontext, value);
65
    JS_DefineProperty(jscontext, jsglobal,
66
                      name, OBJECT_TO_JSVAL(jsvalue),
67
                      NULL, NULL,
68
                      JSPROP_READONLY | JSPROP_PERMANENT);
69
    JS_LeaveLocalRootScope(jscontext);
70
}
71
72
73
static gboolean
74
capa_plugin_javascript_eval(CapaPluginJavascript *plugin,
75
                            GObject *app,
76
                            const gchar *script)
77
{
78
    CapaPluginJavascriptPrivate *priv = plugin->priv;
79
    gchar *file;
80
    int status;
81
    const gchar *searchpath[2];
82
83
    file = g_strdup_printf("%s/main.js", capa_plugin_get_dir(CAPA_PLUGIN(plugin)));
84
85
    searchpath[0] = capa_plugin_get_dir(CAPA_PLUGIN(plugin));
86
    searchpath[1] = NULL;
87
88
    if (!priv->context) {
89
        priv->context = gjs_context_new_with_search_path((gchar **)searchpath);
90
        /* We need to do this eval now so that the later
91
         *    'gjs_object_from_g_object'
92
         * call can find the introspection data it requires */
93
        gjs_context_eval(priv->context,
94
                         "const Capa = imports.gi.Capa",
95
                         -1,
96
                         file,
97
                         &status,
98
                         NULL);
99
    }
100
101
    capa_plugin_javascript_set_global(plugin, "plugin", G_OBJECT(plugin));
102
    capa_plugin_javascript_set_global(plugin, "app", app);
103
104
    CAPA_DEBUG("Eval javascript '%s' in '%s'\n", script, file);
105
    gjs_context_eval(priv->context,
106
                     script,
107
                     -1,
108
                     file,
109
                     &status,
110
                     NULL);
111
112
    g_free(file);
113
    return status == 0 ? TRUE : FALSE;
114
}
115
116
static gboolean
117
capa_plugin_javascript_activate(CapaPlugin *iface, GObject *app)
118
{
119
    CapaPluginJavascript *plugin = CAPA_PLUGIN_JAVASCRIPT(iface);
120
    CapaPluginJavascriptPrivate *priv = plugin->priv;
121
122
    if (priv->active)
123
        return TRUE;
124
125
    priv->active = TRUE;
126
127
    return capa_plugin_javascript_eval(plugin, app,
128
                                       "const Main = imports.main; Main.activate(plugin, app);");
129
}
130
131
static gboolean
132
capa_plugin_javascript_deactivate(CapaPlugin *iface, GObject *app)
133
{
134
    CapaPluginJavascript *plugin = CAPA_PLUGIN_JAVASCRIPT(iface);
135
    CapaPluginJavascriptPrivate *priv = plugin->priv;
136
137
    if (!priv->active)
138
        return TRUE;
139
140
    priv->active = FALSE;
141
142
    return capa_plugin_javascript_eval(plugin, app,
143
                                       "const Main = imports.main; Main.deactivate(plugin, app);");
144
}
145
146
static gboolean
147
capa_plugin_javascript_is_active(CapaPlugin *iface)
148
{
149
    CapaPluginJavascript *plugin = CAPA_PLUGIN_JAVASCRIPT(iface);
150
    CapaPluginJavascriptPrivate *priv = plugin->priv;
151
152
    return priv->active;
153
}
154
155
156
static void capa_plugin_javascript_finalize(GObject *object)
157
{
158
    CapaPluginJavascript *plugin = CAPA_PLUGIN_JAVASCRIPT(object);
159
    CapaPluginJavascriptPrivate *priv = plugin->priv;
160
161
    g_object_unref(priv->context);
162
163
    G_OBJECT_CLASS(capa_plugin_javascript_parent_class)->finalize (object);
164
}
165
166
static void capa_plugin_javascript_class_init(CapaPluginJavascriptClass *klass)
167
{
168
    GObjectClass *object_class = G_OBJECT_CLASS (klass);
169
    CapaPluginClass *plugin_class = CAPA_PLUGIN_CLASS (klass);
170
171
    object_class->finalize = capa_plugin_javascript_finalize;
172
173
    plugin_class->activate = capa_plugin_javascript_activate;
174
    plugin_class->deactivate = capa_plugin_javascript_deactivate;
175
    plugin_class->is_active = capa_plugin_javascript_is_active;
176
177
    g_type_class_add_private(klass, sizeof(CapaPluginJavascriptPrivate));
178
}
179
180
181
void capa_plugin_javascript_init(CapaPluginJavascript *plugin)
182
{
183
    CapaPluginJavascriptPrivate *priv;
184
185
    priv = plugin->priv = CAPA_PLUGIN_JAVASCRIPT_GET_PRIVATE(plugin);
186
    memset(priv, 0, sizeof(*priv));
187
}
188
189
/*
190
 * Local variables:
191
 *  c-indent-level: 4
192
 *  c-basic-offset: 4
193
 *  indent-tabs-mode: nil
194
 *  tab-width: 8
195
 * End:
196
 */