update copyright date
[gnash.git] / extensions / gtk2 / gtkext.cpp
blob052c784551c3fb7eb90d0748b7eb3c7e076eff05
1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
3 // 2011 Free Software Foundation, Inc
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 #ifdef HAVE_CONFIG_H
20 #include "gnashconfig.h"
21 #endif
23 #include <map>
24 #include <iostream>
25 #include <string>
26 #include <cstdio>
27 #include <boost/algorithm/string/case_conv.hpp>
29 #include <gtk/gtk.h>
30 #include <gdk/gdkx.h>
31 #include <gdk/gdkkeysyms.h>
33 #include "VM.h"
34 #include "fn_call.h"
35 #include "log.h"
36 #include "fn_call.h"
37 #include "as_object.h"
38 #include "as_function.h"
39 #include "debugger.h"
40 #include "gtkext.h"
41 #include "as_function.h"
43 using namespace std;
45 namespace gnash
48 #define dbglogfile cerr // FIXME: use log_*()
50 // prototypes for the callbacks required by Gnash
51 as_value gtkext_window_new(const fn_call& fn);
52 as_value gtkext_signal_connect(const fn_call& fn);
53 as_value gtkext_container_set_border_width(const fn_call& fn);
54 as_value gtkext_button_new_with_label(const fn_call& fn);
55 as_value gtkext_signal_connect_swapped(const fn_call& fn);
56 as_value gtkext_container_add(const fn_call& fn);
57 as_value gtkext_widget_show(const fn_call& fn);
58 as_value gtkext_main(const fn_call& fn);
60 // Sigh... We can't store the callbacks for the events in the GtkExt
61 // class object because that data is inaccessible to a C symbol based
62 // callback.
63 static map<string, as_value> callbacks;
65 void dump_callbacks(map<string, as_value> &calls)
67 // GNASH_REPORT_FUNCTION;
68 map<string, as_value>::const_iterator it;
69 dbglogfile << "# of callbacks is: " << calls.size() << endl;
70 for (it=calls.begin(); it != calls.end(); it++) {
71 string name = (*it).first;
72 as_value as = (*it).second;
73 dbglogfile << "Event \"" << name.c_str() << "\" has AS function" << as.to_string() << endl;
78 static void
79 generic_callback(GtkWidget * /*widget*/, gpointer data)
81 // GNASH_REPORT_FUNCTION;
82 // g_print ("Hello World - %d\n", *(int *)data;
83 const char *event = (const char *)data;
85 as_value handler = callbacks[event];
86 as_function *as_func = handler.to_function();
88 // start the debugger when this callback is activated.
89 // debugger.enabled(true);
90 // debugger.console();
92 // FIXME: Delete events don't seem to pass in data in a form we
93 // can access it. So for now we just hack in a quit, since we know
94 // we're done, we hope...
95 if (*event == 0) {
96 gtk_main_quit();
97 return;
98 } else {
99 cerr << "event is: \"" << event << "\"" << endl;
102 as_value val;
103 as_environment env(getVM(*as_func));
105 fn_call::Args args;
106 args += handler, event, handler;
108 as_object obj = val.to_object(*getGlobal(fn));
110 // Call the AS function defined in the source file using this extension
111 (*as_func)(fn_call(&obj, &env, args));
114 static void
115 attachInterface(as_object *obj)
117 // GNASH_REPORT_FUNCTION;
119 obj->init_member("window_new", gl->createFunction(gtkext_window_new));
120 obj->init_member("signal_connect", gl->createFunction(gtkext_signal_connect));
121 obj->init_member("container_set_border_width", gl->createFunction(gtkext_container_set_border_width));
122 obj->init_member("button_new_with_label", gl->createFunction(gtkext_button_new_with_label));
123 obj->init_member("signal_connect_swapped", gl->createFunction(gtkext_signal_connect_swapped));
124 obj->init_member("container_add", gl->createFunction(gtkext_container_add));
125 obj->init_member("widget_show", gl->createFunction(gtkext_widget_show));
126 obj->init_member("main", gl->createFunction(gtkext_main));
129 static as_object*
130 getInterface()
132 // GNASH_REPORT_FUNCTION;
133 static boost::intrusive_ptr<as_object> o;
134 if (o == NULL) {
135 o = new as_object();
137 return o.get();
140 static as_value
141 gtkext_ctor(const fn_call& /*fn*/)
143 // GNASH_REPORT_FUNCTION;
144 GtkExt *obj = new GtkExt();
146 attachInterface(obj);
147 return as_value(obj); // will keep alive
151 GtkExt::GtkExt()
153 // GNASH_REPORT_FUNCTION;
154 int argc = 0;
155 char **argv;
156 gtk_init (&argc, &argv);
159 GtkExt::~GtkExt()
161 // GNASH_REPORT_FUNCTION;
164 void
165 GtkExt::window_new()
167 GNASH_REPORT_FUNCTION;
168 // std::auto_ptr<Gui> ggg = player.getGuiHandle();
169 // player.getGuiHandle();
170 // gui.getWindow();
171 _window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
174 // void
175 // GtkExt::signal_connect()
176 // {
177 // GNASH_REPORT_FUNCTION;
178 // }
180 // void gtk_container_set_border_width (GtkContainer *container, guint border_width);
181 void
182 GtkExt::container_set_border_width(int width)
184 // GNASH_REPORT_FUNCTION;
185 if (_window) {
186 gtk_container_set_border_width (GTK_CONTAINER (_window), width);
190 // GtkWidget *gtk_button_new_with_label (const gchar *label);
191 GtkWidget *
192 GtkExt::button_new_with_label(const char *label)
194 // GNASH_REPORT_FUNCTION;
195 _window = gtk_button_new_with_label (label);
196 return _window;
199 void
200 GtkExt::main()
202 // GNASH_REPORT_FUNCTION;
205 // this callback takes no arguments
206 as_value gtkext_window_new(const fn_call& fn)
208 // GNASH_REPORT_FUNCTION;
209 boost::intrusive_ptr<GtkExt> ptr = ensureType<GtkExt>(fn.this_ptr);
211 GtkExt *obj = new GtkExt;
212 obj->window_new();
213 return as_value(obj);
216 // this callback takes 4 arguments, we only need two of them
217 // g_signal_connect (instance, detailed_signal, c_handler, data)
218 as_value gtkext_signal_connect(const fn_call& fn)
220 // GNASH_REPORT_FUNCTION;
221 boost::intrusive_ptr<GtkExt> ptr = ensureType<GtkExt>(fn.this_ptr);
223 if (fn.nargs > 0) {
224 GtkExt *window = dynamic_cast<GtkExt *>(fn.arg(0).to_object(*getGlobal(fn)).get());
225 string name = fn.arg(1).to_string();
226 as_value func = fn.arg(2).to_function();
227 //int data = fn.arg(3).to_int();
229 dbglogfile << "Adding callback " << func.to_string()
230 << " for event \"" << name << "\"" << endl;
231 callbacks[name] = func;
232 g_signal_connect (G_OBJECT (window->getWindow()), name.c_str(),
233 G_CALLBACK (generic_callback), (void *)name.c_str());
235 return as_value();
238 // this callback takes 2 arguments
239 // void gtk_container_set_border_width (GtkContainer *container, guint border_width);
240 as_value gtkext_container_set_border_width(const fn_call& fn)
242 // GNASH_REPORT_FUNCTION;
244 boost::intrusive_ptr<GtkExt> ptr = ensureType<GtkExt>(fn.this_ptr);
246 if (fn.nargs > 0) {
247 GtkExt *window = dynamic_cast<GtkExt *>(fn.arg(0).to_object(*getGlobal(fn)).get());
248 int width = fn.arg(1).to_int();
249 window->container_set_border_width(width);
250 dbglogfile << "set container border width to " << width << " !" << endl;
252 return as_value();
255 // Creates a new button with the label "Hello World".
256 // GtkWidget *gtk_button_new_with_label (const gchar *label);
257 as_value gtkext_button_new_with_label(const fn_call& fn)
259 // GNASH_REPORT_FUNCTION;
260 boost::intrusive_ptr<GtkExt> ptr = ensureType<GtkExt>(fn.this_ptr);
262 if (fn.nargs > 0) {
263 string label = fn.arg(0).to_string();
264 GtkExt *obj = new GtkExt;
265 obj->button_new_with_label(label.c_str());
266 return as_value(obj);
268 return as_value();
271 // g_signal_connect_swapped(instance, detailed_signal, c_handler, data)
273 // Connects a GCallback function to a signal for a particular object.
275 // The instance on which the signal is emitted and data will be swapped when calling the handler.
276 // instance : the instance to connect to.
277 // detailed_signal : a string of the form "signal-name::detail".
278 // c_handler : the GCallback to connect.
279 // data : data to pass to c_handler calls.
280 // Returns : the handler id
281 as_value gtkext_signal_connect_swapped(const fn_call& fn)
283 GNASH_REPORT_FUNCTION;
284 boost::intrusive_ptr<GtkExt> ptr = ensureType<GtkExt>(fn.this_ptr);
286 if (fn.nargs > 0) {
287 GtkExt *parent = dynamic_cast<GtkExt *>(fn.arg(0).to_object(*getGlobal(fn)).get());
288 string name = (fn.arg(1).to_string());
289 GtkExt *child = dynamic_cast<GtkExt *>(fn.arg(3).to_object(*getGlobal(fn)).get());
290 // currently unused
291 // as_value *callback = dynamic_cast<as_value *>(fn.arg(2).to_object(*getGlobal(fn)));
293 // FIXME: This seems to cause an Gobject warning
294 g_signal_connect_swapped (G_OBJECT (child->getWindow()), name.c_str(),
295 G_CALLBACK (gtk_widget_destroy),
296 G_OBJECT (parent->getWindow()));
298 return as_value();
301 // this takes two arguments
302 as_value gtkext_container_add(const fn_call& fn)
304 // GNASH_REPORT_FUNCTION;
305 boost::intrusive_ptr<GtkExt> ptr = ensureType<GtkExt>(fn.this_ptr);
307 if (fn.nargs > 0) {
308 GtkExt *parent = dynamic_cast<GtkExt *>(fn.arg(0).to_object(*getGlobal(fn)).get());
309 GtkExt *child = dynamic_cast<GtkExt *>(fn.arg(1).to_object(*getGlobal(fn)).get());
310 gtk_container_add (GTK_CONTAINER (parent->getWindow()), child->getWindow());
311 return as_value(true);
313 return as_value(false);
316 as_value gtkext_widget_show(const fn_call& fn)
318 // GNASH_REPORT_FUNCTION;
319 boost::intrusive_ptr<GtkExt> ptr = ensureType<GtkExt>(fn.this_ptr);
321 if (fn.nargs > 0) {
322 GtkExt *window = dynamic_cast<GtkExt *>(fn.arg(0).to_object(*getGlobal(fn)).get());
323 gtk_widget_show(window->getWindow());
325 return as_value();
328 // gtk_main takes no arguments.
329 as_value gtkext_main(const fn_call& fn)
331 // GNASH_REPORT_FUNCTION;
332 boost::intrusive_ptr<GtkExt> ptr = ensureType<GtkExt>(fn.this_ptr);
334 gtk_main();
335 return as_value();
338 std::auto_ptr<as_object>
339 init_gtkext_instance()
341 return std::auto_ptr<as_object>(new GtkExt());
344 extern "C" {
345 void
346 gtkext_class_init(as_object &obj)
348 // GNASH_REPORT_FUNCTION;
349 // This is going to be the global "class"/"function"
350 static boost::intrusive_ptr<builtin_function> cl;
351 if (cl == NULL) {
352 as_object* proto = getInterface();
353 Global_as* gl = getGlobal(global);
354 cl = gl->createClass(&gtkext_ctor, proto);
355 // replicate all interface to class, to be able to access
356 // all methods as static functions
357 attachInterface(cl.get());
360 obj.init_member("GtkExt", cl.get());
362 } // end of extern C
365 } // end of gnash namespace
367 // Local Variables:
368 // mode: C++
369 // indent-tabs-mode: t
370 // End: