~ubuntu-branches/ubuntu/karmic/gnash/karmic

« back to all changes in this revision

Viewing changes to plugin/win32/plugin.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alexander Sack
  • Date: 2008-10-13 14:29:49 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20081013142949-f6qdvnu4mn05ltdc
Tags: 0.8.4~~bzr9980-0ubuntu1
* new upstream release 0.8.4 (LP: #240325)
* ship new lib usr/lib/gnash/libmozsdk.so.* in mozilla-plugin-gnash
  - update debian/mozilla-plugin-gnash.install
* ship new lib usr/lib/gnash/libgnashnet.so.* in gnash-common
  - update debian/gnash-common.install
* add basic debian/build_head script to build latest CVS head packages.
  - add debian/build_head
* new sound architecture requires build depend on libsdl1.2-dev
  - update debian/control
* head build script now has been completely migrated to bzr (upstream +
  ubuntu)
  - update debian/build_head
* disable kde gui until klash/qt4 has been fixed; keep kde packages as empty
  packages for now.
  - update debian/rules
  - debian/klash.install
  - debian/klash.links
  - debian/klash.manpages
  - debian/konqueror-plugin-gnash.install
* drop libkonq5-dev build dependency accordingly
  - update debian/control
* don't install headers manually anymore. gnash doesnt provide a -dev
  package after all
  - update debian/rules
* update libs installed in gnash-common; libgnashserver-*.so is not available
  anymore (removed); in turn we add the new libgnashcore-*.so
  - update debian/gnash-common.install
* use -Os for optimization and properly pass CXXFLAGS=$(CFLAGS) to configure
  - update debian/rules
* touch firefox .autoreg in postinst of mozilla plugin
  - update debian/mozilla-plugin-gnash.postinst
* link gnash in ubufox plugins directory for the plugin alternative switcher
  - add debian/mozilla-plugin-gnash.links
* suggest ubufox accordingly
  - update debian/control
* add new required build-depends on libgif-dev
  - update debian/control
* add Xb-Npp-Description and Xb-Npp-File as new plugin database meta data
  - update debian/control

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// plugin.cpp:  Windows "win32" flash player Mozilla plugin, for Gnash.
 
2
// 
 
3
//   Copyright (C) 2005, 2006, 2007, 2008 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
 
18
//
 
19
 
 
20
#ifdef HAVE_CONFIG_H
 
21
#include "gnashconfig.h"
 
22
#endif
 
23
 
 
24
#include <cstdlib>
 
25
 
 
26
#define FLASH_MAJOR_VERSION "9"
 
27
#define FLASH_MINOR_VERSION "0"
 
28
#define FLASH_REV_NUMBER "82"
 
29
 
 
30
#define MIME_TYPES_HANDLED "application/x-shockwave-flash"
 
31
// The name must be this value to get flash movies that check the
 
32
// plugin version to load.
 
33
#define PLUGIN_NAME "Shockwave Flash"
 
34
#define MIME_TYPES_DESCRIPTION MIME_TYPES_HANDLED":swf:"PLUGIN_NAME
 
35
 
 
36
// Some javascript plugin detectors use the description
 
37
// to decide the flash version to display. They expect the
 
38
// form (major version).(minor version) r(revision).
 
39
// e.g. "8.0 r99."
 
40
#ifndef FLASH_MAJOR_VERSION
 
41
#define FLASH_MAJOR_VERSION DEFAULT_FLASH_MAJOR_VERSION
 
42
#endif
 
43
#ifndef FLASH_MINOR_VERSION
 
44
#define FLASH_MINOR_VERSION DEFAULT_FLASH_MINOR_VERSION
 
45
#endif
 
46
#ifndef FLASH_REV_NUMBER
 
47
#define FLASH_REV_NUMBER DEFAULT_FLASH_REV_NUMBER
 
48
#endif
 
49
#define FLASH_VERSION FLASH_MAJOR_VERSION"."\
 
50
    FLASH_MINOR_VERSION" r"FLASH_REV_NUMBER"."
 
51
 
 
52
#define PLUGIN_DESCRIPTION \
 
53
  "Shockwave Flash "FLASH_VERSION" Gnash "VERSION", the GNU SWF Player. \
 
54
  Copyright &copy; 2006, 2007, 2008 \
 
55
  <a href=\"http://www.fsf.org\">Free Software Foundation</a>, Inc.<br> \
 
56
  Gnash comes with NO WARRANTY, to the extent permitted by law. \
 
57
  You may redistribute copies of Gnash under the terms of the \
 
58
  <a href=\"http://www.gnu.org/licenses/gpl.html\">GNU General Public \
 
59
  License</a>. For more information about Gnash, see <a \
 
60
  href=\"http://www.gnu.org/software/gnash/\"> \
 
61
  http://www.gnu.org/software/gnash</a>. \
 
62
  Compatible Shockwave Flash "FLASH_VERSION
 
63
 
 
64
#define _WIN32_WINNT 0x0500
 
65
#include <windows.h>
 
66
#include <windowsx.h>
 
67
#include <wingdi.h>
 
68
 
 
69
#include <cstdarg>
 
70
#include <boost/cstdint.hpp>
 
71
#include <fstream>
 
72
 
 
73
#include "plugin.h"
 
74
 
 
75
static int module_initialized = FALSE;
 
76
static PRLock* playerLock = NULL;
 
77
static int instances = 0;
 
78
 
 
79
char* NPP_GetMIMEDescription(void);
 
80
static void playerThread(void *arg);
 
81
static LRESULT CALLBACK PluginWinProc(HWND, UINT, WPARAM, LPARAM);
 
82
 
 
83
#define DBG(x, ...) __DBG(x, ## __VA_ARGS__)
 
84
inline void
 
85
__DBG(const char *fmt, ...)
 
86
{
 
87
    char buf[1024];
 
88
    va_list ap;
 
89
    
 
90
    va_start(ap, fmt);
 
91
    vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
 
92
    va_end(ap);
 
93
    OutputDebugString(buf);
 
94
}
 
95
 
 
96
// general initialization and shutdown
 
97
 
 
98
NPError
 
99
NS_PluginInitialize(void)
 
100
{
 
101
    DBG("NS_PluginInitialize\n");
 
102
    if (!playerLock) {
 
103
        playerLock = PR_NewLock();
 
104
    }
 
105
    module_initialized = TRUE;
 
106
    return NPERR_NO_ERROR;
 
107
}
 
108
 
 
109
void
 
110
NS_PluginShutdown(void)
 
111
{
 
112
    DBG("NS_PluginShutdown\n");
 
113
    if (!module_initialized) return;
 
114
    if (playerLock) {
 
115
                PR_DestroyLock(playerLock);
 
116
                playerLock = NULL;
 
117
    }
 
118
}
 
119
 
 
120
/// \brief Return the MIME Type description for this plugin.
 
121
char*
 
122
NPP_GetMIMEDescription(void)
 
123
{
 
124
    if (!module_initialized) return NULL;
 
125
    return MIME_TYPES_HANDLED;
 
126
}
 
127
 
 
128
#if 0
 
129
/// \brief Retrieve values from the plugin for the Browser
 
130
///
 
131
/// This C++ function is called by the browser to get certain
 
132
/// information is needs from the plugin. This information is the
 
133
/// plugin name, a description, etc...
 
134
///
 
135
/// This is actually not used on Win32 (XP_WIN), only on Unix (XP_UNIX).
 
136
NPError
 
137
NS_PluginGetValue(NPPVariable aVariable, void *aValue)
 
138
{
 
139
    NPError err = NPERR_NO_ERROR;
 
140
 
 
141
    if (!module_initialized) return NPERR_NO_ERROR;
 
142
    DBG("aVariable = %d\n", aVariable);
 
143
    switch (aVariable) {
 
144
        case NPPVpluginNameString:
 
145
            *static_cast<char **> (aValue) = PLUGIN_NAME;
 
146
            break;
 
147
 
 
148
        // This becomes the description field you see below the opening
 
149
        // text when you type about:plugins and in
 
150
        // navigator.plugins["Shockwave Flash"].description, used in
 
151
        // many flash version detection scripts.
 
152
        case NPPVpluginDescriptionString:
 
153
            *static_cast<const char **>(aValue) = PLUGIN_DESCRIPTION;
 
154
            break;
 
155
 
 
156
        case NPPVpluginNeedsXEmbed:
 
157
#ifdef HAVE_GTK2
 
158
            *static_cast<PRBool *>(aValue) = PR_TRUE;
 
159
#else
 
160
            *static_cast<PRBool *>(aValue) = PR_FALSE;
 
161
#endif
 
162
            break;
 
163
 
 
164
        case NPPVpluginTimerInterval:
 
165
 
 
166
        case NPPVpluginKeepLibraryInMemory:
 
167
 
 
168
        default:
 
169
            err = NPERR_INVALID_PARAM;
 
170
            break;
 
171
    }
 
172
    return err;
 
173
}
 
174
#endif
 
175
 
 
176
// construction and destruction of our plugin instance object
 
177
 
 
178
nsPluginInstanceBase*
 
179
NS_NewPluginInstance(nsPluginCreateData* aCreateDataStruct)
 
180
{
 
181
    DBG("NS_NewPluginInstance\n");
 
182
    if (!module_initialized) return NULL;
 
183
    if (instances > 0) {
 
184
        return NULL;
 
185
    }
 
186
    instances++; // N.B. This is a threading race condition. FIXME.
 
187
    if (!playerLock) {
 
188
        playerLock = PR_NewLock();
 
189
    }
 
190
    if (!aCreateDataStruct) {
 
191
        return NULL;
 
192
    }
 
193
    return new nsPluginInstance(aCreateDataStruct);
 
194
}
 
195
 
 
196
void
 
197
NS_DestroyPluginInstance(nsPluginInstanceBase* aPlugin)
 
198
{
 
199
    DBG("NS_DestroyPluginInstance\n");
 
200
    if (!module_initialized) return;
 
201
    if (aPlugin) {
 
202
        delete (nsPluginInstance *) aPlugin;
 
203
    }
 
204
    if (playerLock) {
 
205
                PR_DestroyLock(playerLock);
 
206
                playerLock = NULL;
 
207
    }
 
208
    instances--;
 
209
}
 
210
 
 
211
// nsPluginInstance class implementation
 
212
 
 
213
/// \brief Constructor
 
214
nsPluginInstance::nsPluginInstance(nsPluginCreateData* data) :
 
215
    nsPluginInstanceBase(),
 
216
    _instance(data->instance),
 
217
    _window(NULL),
 
218
    _initialized(FALSE),
 
219
    _shutdown(FALSE),
 
220
    _stream(NULL),
 
221
    _url(""),
 
222
    _thread(NULL),
 
223
    _width(0),
 
224
    _height(0),
 
225
    _rowstride(0),
 
226
    _hMemDC(NULL),
 
227
    _bmp(NULL),
 
228
    _memaddr(NULL),
 
229
    mouse_x(0),
 
230
    mouse_y(0),
 
231
    mouse_buttons(0),
 
232
    _oldWndProc(NULL)
 
233
{
 
234
    DBG("nsPluginInstance::nsPluginInstance\n");
 
235
}
 
236
 
 
237
/// \brief Destructor
 
238
nsPluginInstance::~nsPluginInstance()
 
239
{
 
240
    DBG("nsPluginInstance::~nsPluginInstance\n");
 
241
    if (_memaddr) {
 
242
        // Deleting _bmp should free this memory.
 
243
        _memaddr = NULL;
 
244
    }
 
245
    if (_hMemDC) {
 
246
        DeleteObject(_hMemDC);
 
247
        _hMemDC = NULL;
 
248
    }
 
249
    if (_bmp) {
 
250
        DeleteObject(_bmp);
 
251
        _bmp = NULL;
 
252
    }
 
253
}
 
254
 
 
255
NPBool
 
256
nsPluginInstance::init(NPWindow* aWindow)
 
257
{
 
258
    DBG("nsPluginInstance::init\n");
 
259
 
 
260
    if (!aWindow) {
 
261
        DBG("aWindow == NULL\n");
 
262
        return FALSE;
 
263
    }
 
264
 
 
265
    _x = aWindow->x;
 
266
    _y = aWindow->y;
 
267
    _width = aWindow->width;
 
268
    _height = aWindow->height; 
 
269
    _window = (HWND) aWindow->window;
 
270
    // Windows DIB row stride is always a multiple of 4 bytes.
 
271
    _rowstride = /* 24 bits */ 3 * _width;
 
272
    _rowstride += _rowstride % 4;
 
273
 
 
274
    memset(&_bmpInfo, 0, sizeof(BITMAPINFOHEADER));
 
275
    _bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
 
276
    _bmpInfo.bmiHeader.biWidth = _width; 
 
277
    // Negative height means first row comes first in memory.
 
278
    _bmpInfo.bmiHeader.biHeight = -1 * _height; 
 
279
    _bmpInfo.bmiHeader.biPlanes = 1; 
 
280
    _bmpInfo.bmiHeader.biBitCount = 24; 
 
281
    _bmpInfo.bmiHeader.biCompression = BI_RGB; 
 
282
    _bmpInfo.bmiHeader.biSizeImage = 0; 
 
283
    _bmpInfo.bmiHeader.biXPelsPerMeter = 0; 
 
284
    _bmpInfo.bmiHeader.biYPelsPerMeter = 0; 
 
285
    _bmpInfo.bmiHeader.biClrUsed = 0; 
 
286
    _bmpInfo.bmiHeader.biClrImportant = 0; 
 
287
 
 
288
    HDC hDC = GetDC(_window);
 
289
    _hMemDC = CreateCompatibleDC(hDC);
 
290
    _bmp = CreateDIBSection(_hMemDC, &_bmpInfo,
 
291
            DIB_RGB_COLORS, (void **) &_memaddr, 0, 0);
 
292
    SelectObject(_hMemDC, _bmp);
 
293
 
 
294
    DBG("aWindow->type: %s (%u)\n", 
 
295
            (aWindow->type == NPWindowTypeWindow) ? "NPWindowTypeWindow" :
 
296
            (aWindow->type == NPWindowTypeDrawable) ? "NPWindowTypeDrawable" :
 
297
            "unknown",
 
298
            aWindow->type);
 
299
 
 
300
    // subclass window so we can intercept window messages and
 
301
    // do our drawing to it
 
302
    _oldWndProc = SubclassWindow(_window, (WNDPROC) PluginWinProc);
 
303
 
 
304
    // associate window with our nsPluginInstance object so we can access 
 
305
    // it in the window procedure
 
306
    SetWindowLong(_window, GWL_USERDATA, (LONG) this);
 
307
 
 
308
    _initialized = TRUE;
 
309
    return TRUE;
 
310
}
 
311
 
 
312
void
 
313
nsPluginInstance::shut(void)
 
314
{
 
315
    DBG("nsPluginInstance::shut\n");
 
316
 
 
317
    DBG("Acquiring playerLock mutex for shutdown.\n");
 
318
    PR_Lock(playerLock);
 
319
    _shutdown = TRUE;
 
320
    DBG("Releasing playerLock mutex for shutdown.\n");
 
321
    PR_Unlock(playerLock);
 
322
 
 
323
    if (_thread) {
 
324
        DBG("Waiting for thread to terminate.\n");
 
325
        PR_JoinThread(_thread);
 
326
        _thread = NULL; 
 
327
    }
 
328
 
 
329
    // subclass it back
 
330
    SubclassWindow(_window, _oldWndProc);
 
331
 
 
332
    _initialized = FALSE;
 
333
}
 
334
 
 
335
NPError
 
336
nsPluginInstance::NewStream(NPMIMEType type, NPStream *stream,
 
337
        NPBool seekable, boost::uint16_t *stype)
 
338
{
 
339
    DBG("nsPluginInstance::NewStream\n");
 
340
    DBG("stream->url: %s\n", stream->url);
 
341
 
 
342
    if (!_stream) {
 
343
        _stream = stream;
 
344
        _url = stream->url;
 
345
#if 0
 
346
        if (seekable) {
 
347
            *stype = NP_SEEK;
 
348
        }
 
349
#endif
 
350
    }
 
351
 
 
352
    return NPERR_NO_ERROR;
 
353
}
 
354
 
 
355
NPError
 
356
nsPluginInstance::DestroyStream(NPStream *stream, NPError reason)
 
357
{
 
358
    DBG("nsPluginInstance::DestroyStream\n");
 
359
    DBG("stream->url: %s\n", stream->url);
 
360
 
 
361
    // N.B. We can only support one Gnash VM/thread right now. 
 
362
    if (!_thread) {
 
363
        _thread = PR_CreateThread(PR_USER_THREAD, playerThread, this,
 
364
                PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
 
365
    }
 
366
 
 
367
    return NPERR_NO_ERROR;
 
368
}
 
369
 
 
370
int32
 
371
nsPluginInstance::Write(NPStream *stream, int32 offset, int32 len,
 
372
        void *buffer)
 
373
{
 
374
    DBG("nsPluginInstance::Write\n");
 
375
    DBG("stream->url: %s, offset: %ld, len: %ld\n",
 
376
            stream->url, offset, len);
 
377
}
 
378
 
 
379
static void
 
380
playerThread(void *arg)
 
381
{
 
382
    nsPluginInstance *plugin = (nsPluginInstance *) arg;
 
383
 
 
384
    plugin->threadMain();
 
385
}
 
386
 
 
387
void
 
388
nsPluginInstance::threadMain(void)
 
389
{
 
390
    DBG("nsPluginInstance::threadMain started\n");
 
391
    DBG("URL: %s\n", _url.c_str());
 
392
 
 
393
        PR_Lock(playerLock);
 
394
 
 
395
    // Initialize Gnash core library.
 
396
    gnash::gnashInit();
 
397
    DBG("Gnash core initialized.\n");
 
398
 
 
399
    // Init logfile.
 
400
    gnash::RcInitFile& rcinit = gnash::RcInitFile::getDefaultInstance();
 
401
    std::string logfilename = std::string(std::getenv("TEMP")) +
 
402
        std::string("\\npgnash.log");
 
403
    rcinit.setDebugLog(logfilename);
 
404
    gnash::LogFile& dbglogfile = gnash::LogFile::getDefaultInstance();
 
405
    dbglogfile.setWriteDisk(true);
 
406
    dbglogfile.setVerbosity(GNASH_DEBUG_LEVEL);
 
407
    DBG("Gnash logging initialized: %s\n", logfilename.c_str());
 
408
 
 
409
    // Init sound.
 
410
    _sound_handler.reset(gnash::media::create_sound_handler_sdl());
 
411
    gnash::set_sound_handler(_sound_handler.get());
 
412
    DBG("Gnash sound initialized.\n");
 
413
 
 
414
    // Init GUI.
 
415
    int old_mouse_x = 0, old_mouse_y = 0, old_mouse_buttons = 0;
 
416
    _render_handler =
 
417
        (gnash::render_handler *) gnash::create_render_handler_agg("BGR24");
 
418
    // _memaddr = (unsigned char *) malloc(getMemSize());
 
419
    static_cast<gnash::render_handler_agg_base *>(_render_handler)->init_buffer(
 
420
            getMemAddr(), getMemSize(), _width, _height, _rowstride);
 
421
    gnash::set_render_handler(_render_handler);
 
422
    DBG("Gnash GUI initialized: %ux%u\n", _width, _height);
 
423
 
 
424
    gnash::URL url(_url);
 
425
 
 
426
    VariableMap vars;
 
427
    gnash::URL::parse_querystring(url.querystring(), vars);
 
428
    for (VariableMap::iterator i = vars.begin(), ie = vars.end(); i != ie; i++) {
 
429
        _flashVars[i->first] = i->second;
 
430
    }
 
431
 
 
432
    gnash::set_base_url(url);
 
433
 
 
434
    gnash::movie_definition* md = NULL;
 
435
    try {
 
436
        md = gnash::create_library_movie(url, _url.c_str(), false);
 
437
    } catch (const gnash::GnashException& err) {
 
438
        md = NULL;
 
439
    }
 
440
    if (!md) {
 
441
        /*
 
442
         * N.B. Can't use the goto here, as C++ complains about "jump to
 
443
         * label 'done' from here crosses initialization of ..." a bunch
 
444
         * of things.  Sigh.  So, instead, I duplicate the cleanup code
 
445
         * here.  TODO: Remove this duplication.
 
446
         */
 
447
        // goto done;
 
448
 
 
449
        PR_Unlock(playerLock);
 
450
 
 
451
        DBG("Clean up Gnash.\n");
 
452
        gnash::clear();
 
453
 
 
454
        DBG("nsPluginInstance::threadMain exiting\n");
 
455
        return;
 
456
    }
 
457
    DBG("Movie created: %s\n", _url.c_str());
 
458
 
 
459
    int movie_width = static_cast<int>(md->get_width_pixels());
 
460
    int movie_height = static_cast<int>(md->get_height_pixels());
 
461
    float movie_fps = md->get_frame_rate();
 
462
    DBG("Movie dimensions: %ux%u (%.2f fps)\n",
 
463
            movie_width, movie_height, movie_fps);
 
464
 
 
465
    gnash::SystemClock clock; // use system clock here...
 
466
    gnash::movie_root& root = gnash::VM::init(*md, clock).getRoot();
 
467
    DBG("Gnash VM initialized.\n");
 
468
    
 
469
    // Register this plugin as listener for FsCommands from the core
 
470
    // (movie_root)
 
471
    root.registerFSCommandCallback(FSCommand_callback);
 
472
    
 
473
    // Register a static function to handle ActionScript events such
 
474
    // as Mouse.hide, Stage.align etc.
 
475
    // root.registerEventCallback(&staticEventHandlingFunction);
 
476
 
 
477
    md->completeLoad();
 
478
    DBG("Movie loaded.\n");
 
479
 
 
480
    std::auto_ptr<gnash::movie_instance> mr(md->create_movie_instance());
 
481
    mr->setVariables(_flashVars);
 
482
    root.setRootMovie(mr.release());
 
483
    root.set_display_viewport(0, 0, _width, _height);
 
484
    root.set_background_alpha(1.0f);
 
485
    gnash::movie_instance* mi = root.getRootMovie();
 
486
    DBG("Movie instance created.\n");
 
487
 
 
488
    ShowWindow(_window, SW_SHOW);
 
489
 
 
490
    for (;;) {
 
491
        // DBG("Inside main thread loop.\n");
 
492
 
 
493
        if (_shutdown) {
 
494
            DBG("Main thread shutting down.\n");
 
495
            break;
 
496
        }
 
497
 
 
498
        size_t cur_frame = mi->get_current_frame();
 
499
        // DBG("Got current frame number: %d.\n", cur_frame);
 
500
        size_t tot_frames = mi->get_frame_count();
 
501
        // DBG("Got total frame count: %d.\n", tot_frames);
 
502
 
 
503
        // DBG("Advancing one frame.\n");
 
504
        root.advance();
 
505
        // DBG("Going to next frame.\n");
 
506
        root.goto_frame(cur_frame + 1);
 
507
        // DBG("Ensuring frame is loaded.\n");
 
508
        root.get_movie_definition()->ensure_frame_loaded(tot_frames);
 
509
        // DBG("Setting play state to PLAY.\n");
 
510
        root.set_play_state(gnash::sprite_instance::PLAY);
 
511
 
 
512
        if (old_mouse_x != mouse_x || old_mouse_y != mouse_y) {
 
513
            old_mouse_x = mouse_x;
 
514
            old_mouse_y = mouse_y;
 
515
            root.notify_mouse_moved(mouse_x, mouse_y);
 
516
        }
 
517
        if (old_mouse_buttons != mouse_buttons) {
 
518
            old_mouse_buttons = mouse_buttons;
 
519
            int mask = 1;
 
520
            root.notify_mouse_clicked(mouse_buttons > 0, mask);
 
521
        }
 
522
 
 
523
        root.display();
 
524
 
 
525
        RECT rt;
 
526
        GetClientRect(_window, &rt);
 
527
        InvalidateRect(_window, &rt, FALSE);
 
528
 
 
529
#if 0
 
530
        InvalidatedRanges ranges;
 
531
        ranges.setSnapFactor(1.3f);
 
532
        ranges.setSingleMode(false);
 
533
        root.add_invalidated_bounds(ranges, false);
 
534
        ranges.growBy(40.0f);
 
535
        ranges.combine_ranges();
 
536
 
 
537
        if (!ranges.isNull()) {
 
538
            InvalidateRect(_window, &rt, FALSE);
 
539
        }
 
540
 
 
541
        root.display();
 
542
#endif
 
543
 
 
544
        // DBG("Unlocking playerLock mutex.\n");
 
545
        PR_Unlock(playerLock);
 
546
        // DBG("Sleeping.\n");
 
547
        PR_Sleep(PR_INTERVAL_MIN);
 
548
        // DBG("Acquiring playerLock mutex.\n");
 
549
        PR_Lock(playerLock);
 
550
    }
 
551
 
 
552
done:
 
553
        PR_Unlock(playerLock);
 
554
 
 
555
    DBG("Clean up Gnash.\n");
 
556
 
 
557
    /*
 
558
     * N.B.  As per server/impl.cpp:clear(), all of Gnash's threads aren't
 
559
     * guaranteed to be terminated by this, yet.  Therefore, when Firefox
 
560
     * unloads npgnash.dll after calling NS_PluginShutdown(), and there are
 
561
     * still Gnash threads running, they will try and access memory that was
 
562
     * freed as part of the unloading of npgnash.dll, resulting in a process
 
563
     * abend.
 
564
     */
 
565
 
 
566
    gnash::clear();
 
567
 
 
568
    DBG("nsPluginInstance::threadMain exiting\n");
 
569
}
 
570
 
 
571
const char*
 
572
nsPluginInstance::getVersion()
 
573
{
 
574
    return NPN_UserAgent(_instance);
 
575
}
 
576
 
 
577
void
 
578
nsPluginInstance::FSCommand_callback(gnash::sprite_instance* movie, const std::string& command, const std::string& args)
 
579
// For handling notification callbacks from ActionScript.
 
580
{
 
581
    gnash::log_debug(_("FSCommand_callback(%p): %s %s"), (void*) movie, command, args);
 
582
}
 
583
 
 
584
static LRESULT CALLBACK
 
585
PluginWinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 
586
{
 
587
    // get our plugin instance object
 
588
    nsPluginInstance *plugin =
 
589
        (nsPluginInstance *) GetWindowLong(hWnd, GWL_USERDATA);
 
590
 
 
591
    if (plugin) {
 
592
        switch (msg) {
 
593
            case WM_PAINT:
 
594
            {
 
595
                if (plugin->getMemAddr() == NULL) {
 
596
                    break;
 
597
                }
 
598
 
 
599
                PAINTSTRUCT ps;
 
600
                HDC hDC = BeginPaint(hWnd, &ps);
 
601
 
 
602
                RECT rt;
 
603
                GetClientRect(hWnd, &rt);
 
604
                int w = rt.right - rt.left;
 
605
                int h = rt.bottom - rt.top;
 
606
 
 
607
                BitBlt(hDC, rt.left, rt.top, w, h,
 
608
                        plugin->getMemDC(), 0, 0, SRCCOPY);
 
609
 
 
610
                EndPaint(hWnd, &ps);
 
611
                return 0L;
 
612
            }
 
613
            case WM_MOUSEMOVE:
 
614
            {
 
615
                int x = GET_X_LPARAM(lParam); 
 
616
                int y = GET_Y_LPARAM(lParam); 
 
617
 
 
618
                plugin->notify_mouse_state(x, y, -1);
 
619
                break;
 
620
            }
 
621
            case WM_LBUTTONDOWN:
 
622
            case WM_LBUTTONUP:
 
623
            {
 
624
                int x = GET_X_LPARAM(lParam); 
 
625
                int y = GET_Y_LPARAM(lParam); 
 
626
                int buttons = (msg == WM_LBUTTONDOWN) ? 1 : 0;
 
627
 
 
628
                plugin->notify_mouse_state(x, y, buttons);
 
629
                break;
 
630
            }
 
631
            default:
 
632
//                dbglogfile << "msg " << msg << endl;
 
633
                break;
 
634
        }
 
635
    }
 
636
    return DefWindowProc(hWnd, msg, wParam, lParam);
 
637
}