~ubuntu-branches/ubuntu/quantal/gnash/quantal-proposed

« back to all changes in this revision

Viewing changes to doc/C/refmanual/extensions/extensions.xml

  • Committer: Bazaar Package Importer
  • Author(s): Alexander Sack
  • Date: 2008-10-14 16:06:54 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20081014160654-0anbl2mi098aee2h
Tags: 0.8.4-0ubuntu1
* LP: #84526 - Gnash menu launcher (/usr/share/applications/gnash.desktop
  file) doesn't start any application, also gnash isn't asociated with SWF
  mimetype; we dont show gnash in the .desktop launcher; we add
  NoDisplay=true, add a GenericName and Comment for the sake of
  completeness. Also we add the proper MimeType value, remove Encoding,
  don't use absolute paths for icon and exec and dont use specific icon
  file format suffix.
  - update debian/gnash.desktop

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
<chapter id="extensions">
2
 
  <title>Gnash Extensions</title>
3
 
  
4
 
  <para>
5
 
    Gnash supports extending the SWF specification by creating
6
 
    custom ActionScript classes that are compiled code, as opposed to
7
 
    the existing method of defining custom classes as
8
 
    ActionScript. Executing compiled code has many performance
9
 
    benefits over having to interpret the byte stream of the
10
 
    ActionScript opcodes.
11
 
  </para>
12
 
  
13
 
  <para>
14
 
    I can already hear people complaining now about the concept of
15
 
    extending SWF, so this in no way affects Gnash's ability to play
16
 
    SWF movies when functioning as a browser plugin.
17
 
    Gnash's goal is still to function in a way that is compatible
18
 
    with the current proprietary Flash player.
19
 
  </para>
20
 
 
21
 
  <para>
22
 
    But at the same time, we see SWF as the ideal scripting language
23
 
    for a digital multi-media streaming environment. There are many
24
 
    resources for SWF movie creators for widgets, higher level APIs,
25
 
    all sorts of desirable things. But for those of use committed to
26
 
    using free software tools for SWF, our options are very
27
 
    limited. 
28
 
  </para>
29
 
 
30
 
  <para>
31
 
    Rather than launching a multi-year project to duplicate all
32
 
    classes in the commercial Flash IDE, it's much more efficient to
33
 
    use existing development libraries much like Python or Perl
34
 
    do. The extension mechanism in Gnash allows wrappers to be created
35
 
    for any C or C++ development library. Unlike the proprietary Flash
36
 
    IDE, which compiles all the extension libraries into byte codes
37
 
    from ActionScript, the support is moved to the player side. Movies
38
 
    with all of the goodies of the proprietary IDE in them play in
39
 
    Gnash just fine, as it's all just byte codes by then.
40
 
  </para>
41
 
 
42
 
  <para>
43
 
    This trick works because until SWF version 9, all the
44
 
    ActionScript class names and methods are passed as ASCII strings
45
 
    into the SWF movie. So the Gnash Virtual Machine just loads the
46
 
    extension file if that class name is invoked in the movie. All
47
 
    extension files specify the class name and methods it implements
48
 
    in an identical style as adding any new ActionScript class. The
49
 
    advantage is the class itself is compiled code, and runs much
50
 
    faster than the equivalent byte codes which all have to be
51
 
    interpreted..
52
 
  </para>
53
 
 
54
 
  <sect1 id="newext">
55
 
    <title>Creating A New Extension</title>
56
 
 
57
 
    <para>
58
 
      Each new extension should live in it's own directory. The
59
 
      extensions included in Gnash are all in the
60
 
      <emphasis>gnash/extensions</emphasis> directory. Creating an extension
61
 
      requires a Makefile.am,
62
 
    </para>
63
 
 
64
 
    <para>
65
 
      If you are adding this extension to the Gnash source tree
66
 
      itself, then you need to make two changes to add the new
67
 
      extension.
68
 
    </para>
69
 
 
70
 
    <para>
71
 
      The first change is to add the directory to the list in
72
 
      extensions/Makefile.am. This can be done either by adding the
73
 
      new directory to the SUBDIRS setting, or by wrapping it in a
74
 
      conditional test.
75
 
    </para>
76
 
 
77
 
    <para>
78
 
      The other change is to add it to the AC_OUTPUT list in
79
 
      <emphasis>configure.ac</emphasis> so the new directory will be
80
 
      configured along with the rest of Gnash.
81
 
    </para>
82
 
 
83
 
    <para>
84
 
      Each extension should have an ActionScript source file included
85
 
      that tests the new class, and this file should be referenced in
86
 
      the new Makefile.am in the <emphasis>check_PROGRAMS</emphasis>
87
 
      variable so that "make check" works.
88
 
    </para>
89
 
 
90
 
    <para>
91
 
      When creating an extension that is a wrapper for an existing
92
 
      development library API, it's often better to make this a thin
93
 
      layer, than to get carried away with creating beautiful
94
 
      abstractions. Higher-level classes that offer a lot of new
95
 
      functionality are fine, but is different than wrapping a library
96
 
      so it can be used from within Gnash.
97
 
    </para>
98
 
 
99
 
    <sect2 id="craftext">
100
 
      <title>Crafting an Extension</title>
101
 
 
102
 
      <para>
103
 
        All extensions have the same requirements, namely setting up a
104
 
        few defined function callbacks, which the Gnash VM then uses
105
 
        to do the right thing. The initial two function callbacks are
106
 
        for handling the interface of the newly created object so that
107
 
        Gnash can find and use it.
108
 
      </para>
109
 
 
110
 
      <para>
111
 
        The first function is commonly called
112
 
        <emphasis>attachInterface</emphasis>, and this sets the other
113
 
        function callbacks for all the methods this class
114
 
        supports. The method callbacks are attached to the parent
115
 
        class by using <emphasis>init_member()</emphasis> to set a C
116
 
        function pointer to the string value used in the SWF movie.
117
 
      </para>
118
 
 
119
 
      <programlisting>
120
 
        // Attach DummyClass 'func1' and 'func2' methods to the given object
121
 
        static void
122
 
        attachInterface(as_object&amp; obj) {
123
 
            obj.init_member("func1", &amp;ext_func1);
124
 
            obj.init_member("func2", &amp;ext_func2);
125
 
        }
126
 
      </programlisting>
127
 
 
128
 
      <para>
129
 
        The second function is commonly called
130
 
        <emphasis>getInterface()</emphasis>, and this returns a
131
 
        pointer to a static prototype of the class.
132
 
        Gnash uses garbage collection for ActionScript objects
133
 
        so you need to register the static with the VM to give it
134
 
        a chance to be marked as reachable.
135
 
      </para>
136
 
      <programlisting>
137
 
        static as_object*
138
 
        getInterface()
139
 
        {
140
 
            static boost::intrusive_ptr&lt;as_object&gt; o;
141
 
            if (o == NULL) {
142
 
                o = new as_object();
143
 
                VM::get().addStatic(o);
144
 
                attachInterface(*o);
145
 
            }
146
 
            return o.get();
147
 
        }
148
 
      </programlisting>
149
 
 
150
 
      <para>
151
 
        This is the callback that gets executed when constructing a
152
 
        new object for the VM. In this example we'll assume the new
153
 
        ActionScript class is called <emphasis>DummyExt</emphasis>,
154
 
        and has two methods, <emphasis>func1</emphasis> and
155
 
        <emphasis>func2</emphasis>.
156
 
      </para>
157
 
      <programlisting>
158
 
        static as_value
159
 
        dummyext_ctor(const fn_call&amp; fn)
160
 
        {
161
 
            DummyExt *obj = new DummyExt(); // will setup prototypes
162
 
 
163
 
            return as_value(obj); 
164
 
        }
165
 
      </programlisting>
166
 
 
167
 
      <para>
168
 
        The trick for the above simple constructor to work is that
169
 
        class appartenence is setup in the C++ DummyExt constructor
170
 
        itself, which should derive from as_object and construct the
171
 
        base passing it the interface (prototype) of it's class.
172
 
      </para>
173
 
 
174
 
      <programlisting>
175
 
        class DummyExt : public as_object
176
 
        {
177
 
        public:
178
 
            DummyExt()
179
 
                :
180
 
                as_object(getInterface()) // returns the static prototype
181
 
            {}
182
 
 
183
 
        };
184
 
      </programlisting>
185
 
 
186
 
      <para>
187
 
        Initialize the extension. This is looked for by the extension
188
 
        handling code in each extension, and is executed when the
189
 
        extension is loaded. This is the main entry point into the
190
 
        extension. This function can be found because the prefix of
191
 
        <emphasis>dummyext</emphasis>, which also matches the file
192
 
        name of the extension. Gnash uses the name of the extension
193
 
        file itself when looking for the init function.
194
 
      </para>
195
 
      <programlisting>
196
 
        extern "C" {
197
 
            void
198
 
            dummyext_class_init(as_object &amp;obj)
199
 
            {
200
 
                static builtin_function* cl=NULL;
201
 
                if (!cl)
202
 
                {
203
 
                    // Create a builtin function using the given constructor
204
 
                    // to instanciate objects and exporting the given interface
205
 
                    cl = new builtin_function(&amp;dummyext_ctor, getInterface());
206
 
                    VM::get().addStatic(cl); // will forbid to collect the class
207
 
                }
208
 
        
209
 
                obj.init_member("DummyExt", cl);
210
 
            }
211
 
        } // end of extern C
212
 
      </programlisting>
213
 
 
214
 
      <para>
215
 
        The callbacks are all C functions. Like all the other code
216
 
        that implements ActionScript, parameters to the function are
217
 
        passed in using the <emphasis>fn_call</emphasis> data
218
 
        structure. The return code, if any, is also returned using
219
 
        this data structure. <emphasis>this_ptr</emphasis> is the
220
 
        object that the method is a member of.
221
 
      </para>
222
 
      <programlisting>
223
 
        // Creates a new button with the label as the text.
224
 
        as_value func1(const fn_call&amp; fn) {
225
 
            // Following line will ensure 'func1' is called for a DummyExt instance,
226
 
            // or would throw an exception which should behave as if we returned the
227
 
            // undefined value.
228
 
            boost::intrusive_ptr&lt;DummyExt&gt; ptr = ensureType&lt;DummyExt&gt;(fn.this_ptr);
229
 
        
230
 
            if (fn.nargs > 0) {
231
 
                std::string label = fn.arg(0).to_string();
232
 
                bool ret = ptr->dummy_text_label(label);
233
 
                return as_value(ret);
234
 
            }
235
 
        }
236
 
      </programlisting>
237
 
 
238
 
    </sect2>
239
 
 
240
 
  </sect1>
241
 
 
242
 
  <sect1 id="debuext">
243
 
    <title>Debugging An Extension</title>
244
 
    
245
 
    <para>
246
 
      As extensions are loaded dynamically at runtime, debugging one
247
 
      can be difficult. You can use GDB, but you have the problem of
248
 
      not being able to set a breakpoint in Gnash until
249
 
      <emphasis>after</emphasis> the extension has been loaded into
250
 
      Gnash's VM. The easy solution is to use the Gnash debugger.
251
 
    </para>
252
 
 
253
 
    <para>
254
 
      You can insert these few lines in any file that you wish to
255
 
      manually start the debugger. Once at the console, you can attach
256
 
      GDB to the process. Then you can set breakpoints, etc... and you
257
 
      are at the point of execution where the console was started. To
258
 
      then continue playing the movie, type the <emphasis>c</emphasis>
259
 
      (for continue) command to the Gnash console.
260
 
    </para>
261
 
    <programlisting>
262
 
      // Get the debugger instance
263
 
      static Debugger&amp; debugger = Debugger::getDefaultInstance();
264
 
 
265
 
      // Enable the debugger
266
 
      debugger.enabled(true);
267
 
      // Stop and drop into a console
268
 
      debugger.console();
269
 
    </programlisting>
270
 
 
271
 
    <para>
272
 
      You can also resort to the time honored technique of creating a
273
 
      loop before the point you want to set a breakpoint for. Gnash
274
 
      will stop playing the movie at this point, and then you can
275
 
      externally attach GDB to the running process, or type
276
 
      <emphasis>^C</emphasis> to drop into the GDB command console.
277
 
    </para>
278
 
    <programlisting>
279
 
      bool stall = true;
280
 
      while (stall) {
281
 
          sleep 1;
282
 
      }
283
 
    </programlisting>
284
 
 
285
 
    <para>
286
 
      Once you have set the breakpoints you want, reset the value of
287
 
      the <emphasis>stall</emphasis> variable to break out of the
288
 
      loop, and the SWF movie will then continue playing.
289
 
    </para>
290
 
    <programlisting>
291
 
      (gdb) set variable stall = false;
292
 
      continue
293
 
    </programlisting>
294
 
 
295
 
  </sect1>
296
 
  
297
 
  <sect1 id="inclext">
298
 
    <title>Included Extensions</title>
299
 
 
300
 
    <para>
301
 
      Gnash has some extensions included in the distribution. This is
302
 
      mostly because they were written by the Gnash team. Extensions
303
 
      can be external to gnash, Gnash needs no compiled in knowledge
304
 
      to load an extension file.
305
 
    </para>
306
 
    
307
 
    &gtkext;
308
 
    &fileext;
309
 
    &mysqlext;
310
 
 
311
 
  </sect1>
312
 
 
313
 
</chapter>