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
18 
19 #ifdef HAVE_CONFIG_H
20 #include "gnashconfig.h"
21 #endif
22 
23 #include <fltk/Item.h>
24 #include <fltk/Window.h>
25 
26 #ifdef HAVE_X11_X_H
27 #include <fltk/x11.h>
28 #endif
29 
30 #include <fltk/events.h>
31 #include <fltk/run.h>
32 #include <fltk/Cursor.h>
33 #include <fltk/layout.h>
34 #include <fltk/MenuBar.h>
35 #include <fltk/ItemGroup.h>
36 #include <fltk/file_chooser.h>
37 
38 #include "fltksup.h"
39 #include "gui.h"
40 #include "VM.h"
41 #include "RunResources.h"
42 
43 #include "Renderer.h"
44 
45 using namespace std;
46 using namespace fltk;
47 
48 
49 
50 namespace gnash
51 {
52 
53 
FltkGui(unsigned long xid,float scale,bool loop,RunResources & r)54 FltkGui::FltkGui(unsigned long xid, float scale, bool loop, RunResources& r)
55   : Window(0, 0),
56     Gui(xid, scale, loop, r),
57     _menu_height(_xid ? 0 : 20)
58 {
59 }
60 
~FltkGui()61 FltkGui::~FltkGui()
62 {
63     delete _popup_menu;
64 }
65 
66 
67 void
renderBuffer()68 FltkGui::renderBuffer()
69 {
70     // FLTK has a nice mechanism where you can set damage() to whatever you want
71     // so in draw() you can check what exactly you want to redraw. But
72     // unfortunately it doesn't seem to remember what bits you turn on. So I'll
73     // just do it the old-fashioned way.
74 
75     static bool firstRun = true;
76 
77     if (firstRun) {
78       using namespace geometry;
79       Range2d<int> bounds(0, 0, _width, _height);
80       _glue->render(bounds);
81 
82       return;
83     }
84 
85     if (! _drawbounds_vec.size() ) {
86       return; // XXX what about Cairo?
87     }
88 
89     for (unsigned bno=0; bno < _drawbounds_vec.size(); bno++) {
90        geometry::Range2d<int>& bounds = _drawbounds_vec[bno];
91 
92        assert ( bounds.isFinite() );
93 
94        _glue->render(bounds);
95     }
96 }
97 
98 int
handle(int event)99 FltkGui::handle(int event)
100 {
101     switch (event) {
102       case TIMEOUT:
103         advance_movie(this);
104         repeat_timeout(_interval);
105         return true;
106       case PUSH:
107         Window::handle(event);
108         notifyMouseClick(true);
109         return true;
110       case RELEASE:
111         Window::handle(event);
112         notifyMouseClick(false);
113         return true;
114       case MOVE:
115       {
116         if (!_xid && event_y() < static_cast<int>(_menu_height)) {
117           return Window::handle(event);
118         }
119         notifyMouseMove(event_x(), event_y()-_menu_height);
120         return Window::handle(event);
121       }
122       case SHORTCUT:
123       case KEY:
124         handleKey(event_key());
125         return true;
126       default:
127         return Window::handle(event);
128     }
129 }
130 
131 void
handleKey(unsigned key)132 FltkGui::handleKey(unsigned key)
133 {
134     // TODO: there are more keys
135     struct {
136       unsigned              fltkKey;
137       gnash::key::code      gnashKey;
138     } table[] = {
139       { BackSpaceKey,       gnash::key::BACKSPACE },
140       { TabKey,             gnash::key::TAB },
141       { ClearKey,           gnash::key::CLEAR },
142       { ReturnKey,          gnash::key::ENTER },
143       { CapsLockKey,        gnash::key::CAPSLOCK },
144       { EscapeKey,          gnash::key::ESCAPE },
145       { SpaceKey,           gnash::key::SPACE },
146       { PageDownKey,        gnash::key::PGDN },
147       { PageUpKey,          gnash::key::PGUP },
148       { HomeKey,            gnash::key::HOME },
149       { EndKey,             gnash::key::END },
150       { LeftKey,            gnash::key::LEFT },
151       { UpKey,              gnash::key::UP },
152       { RightKey,           gnash::key::RIGHT },
153       { DownKey,            gnash::key::DOWN },
154       { InsertKey,          gnash::key::INSERT },
155       { DeleteKey,          gnash::key::DELETEKEY },
156       { HelpKey,            gnash::key::HELP },
157       { NumLockKey,         gnash::key::NUM_LOCK },
158       { SubtractKey,        gnash::key::MINUS },
159       { DivideKey,          gnash::key::SLASH },
160       { 0,                  gnash::key::INVALID }
161 #if 0
162             // These appear to be unavailable in fltk
163             { bracketleft, gnash::key::LEFT_BRACKET },
164             { backslash, gnash::key::BACKSLASH },
165             { bracketright, gnash::key::RIGHT_BRACKET },
166             { quotedbl, gnash::key::QUOTE },
167             { VoidSymbol, gnash::key::INVALID }
168             { SemicolonKey, gnash::key::SEMICOLON },
169             { equalKey, gnash::key::EQUALS },
170 #endif
171     };
172 
173     int modifier = gnash::key::GNASH_MOD_NONE;
174 
175     unsigned long state = event_state();
176 
177     if (state & SHIFT) {
178         modifier = modifier | gnash::key::GNASH_MOD_SHIFT;
179     }
180     if (state & CTRL) {
181         modifier = modifier | gnash::key::GNASH_MOD_CONTROL;
182     }
183     if (state & ALT) {
184         modifier = modifier | gnash::key::GNASH_MOD_ALT;
185     }
186 
187     for (int i = 0; table[i].fltkKey; i++) {
188         if (key == table[i].fltkKey) {
189             notify_key_event((gnash::key::code)table[i].gnashKey, modifier,
190                              true);
191             break;
192         }
193     }
194 }
195 
196 bool
run()197 FltkGui::run()
198 {
199     fltk::run();
200 
201     return true;
202 }
203 
204 bool
init(int,char ***)205 FltkGui::init(int /* argc */, char *** /*argv */)
206 {
207 
208     return true;
209 }
210 
211 void
setInterval(unsigned int time)212 FltkGui::setInterval(unsigned int time)
213 {
214     _interval = time / 1000.0;
215     add_timeout (_interval);
216 }
217 
218 void
create()219 FltkGui::create()
220 {
221 #ifdef HAVE_X11_X_H
222     if (_xid) {
223       // Make FLTK render into an X window indicated by the XID.
224       CreatedWindow::set_xid(this, _xid);
225       return;
226     }
227 #endif
228     Window::create();
229 }
230 
231 bool
createWindow(const char * title,int width,int height,int xPosition,int yPosition)232 FltkGui::createWindow(const char* title, int width, int height,
233                       int xPosition, int yPosition)
234 {
235     resize(width, _menu_height + height);
236 
237 
238     label(title);
239     begin();
240 
241     if (!_xid) {
242       MenuBar* menubar = new MenuBar(0, 0, width, _menu_height);
243       menubar->begin();
244       addMenuItems();
245       menubar->end();
246     }
247 #ifdef RENDERER_AGG
248     _glue = new FltkAggGlue(0, _menu_height, width, height);
249 #elif defined(RENDERER_CAIRO)
250 #error FLTK/Cairo is currently broken. Please try again soon...
251     FltkCairoGlue _glue;
252 #elif defined(RENDERER_OPENGL)
253 #error FLTK/OpenGL is currently broken. Please try again soon...
254     FltkCairoGlue _glue;
255 #endif
256     createMenu();
257     end();
258 
259     _renderer.reset(_glue->createRenderHandler());
260     if (!_renderer.get()) return false;
261     _runResources.setRenderer(_renderer);
262 
263     _glue->initBuffer(width, height);
264 
265     // The minimum size of the window is 1x1 pixels.
266     size_range (1, 1);
267 
268     show();
269 
270     return true;
271 }
272 
273 
fltk_menu_open_file(Widget *,void *)274 static void fltk_menu_open_file(Widget*, void*)
275 {
276     const char *newfile = fltk::file_chooser("Open File", "*.swf", NULL);
277     if (!newfile) {
278       return;
279     }
280 
281     // menu_open_file()..
282 }
283 
fltk_menu_save_file_as(Widget *,void *)284 static void fltk_menu_save_file_as(Widget*, void*)
285 {
286     const char* savefile = file_chooser("Save File as", NULL, NULL);
287     if (!savefile) {
288       return;
289     }
290 
291     // menu_save_file();
292 }
293 
fltk_menu_fullscreen(Widget *,void * ptr)294 static void fltk_menu_fullscreen(Widget*, void* ptr)
295 {
296 //    GNASH_REPORT_FUNCTION;
297 
298     static bool fullscreen = false;
299     static Rectangle oldBounds;
300 
301     fullscreen = !fullscreen;
302 
303     FltkGui* gui = static_cast<FltkGui*>(ptr);
304     if (fullscreen) {
305       oldBounds.set(gui->x(), gui->y(), gui->w(), gui->h());
306       gui->fullscreen();
307     } else {
308       gui->fullscreen_off(oldBounds.x(), oldBounds.y(), oldBounds.w(), oldBounds.h());
309     }
310 }
311 
312 
313 static void
fltk_menu_quit(Widget *,void * ptr)314 fltk_menu_quit(Widget*, void* ptr)
315 {
316     FltkGui* gui = static_cast<FltkGui*>(ptr);
317     gui->quit();
318 }
319 
320 static void
fltk_menu_play(Widget *,void * ptr)321 fltk_menu_play(Widget*, void* ptr)
322 {
323     FltkGui* gui = static_cast<FltkGui*>(ptr);
324     gui->play();
325 }
326 
327 static void
fltk_menu_pause(Widget *,void * ptr)328 fltk_menu_pause(Widget*, void* ptr)
329 {
330     FltkGui* gui = static_cast<FltkGui*>(ptr);
331     gui->pause();
332 }
333 
334 static void
fltk_menu_stop(Widget *,void * ptr)335 fltk_menu_stop(Widget*, void* ptr)
336 {
337     FltkGui* gui = static_cast<FltkGui*>(ptr);
338     gui->stop();
339 }
340 
341 static void
fltk_menu_restart(Widget *,void * ptr)342 fltk_menu_restart(Widget*, void* ptr)
343 {
344     FltkGui* gui = static_cast<FltkGui*>(ptr);
345     gui->restart();
346 }
347 
348 static void
fltk_menu_toggle_sound(Widget *,void * ptr)349 fltk_menu_toggle_sound(Widget*, void* ptr)
350 {
351     FltkGui* gui = static_cast<FltkGui*>(ptr);
352     gui->toggleSound();
353 }
354 
355 void
addMenuItems()356 FltkGui::addMenuItems()
357 {
358     ItemGroup* file = new ItemGroup("File");
359 
360 
361     file->begin();
362     new Item("Open",                    0, fltk_menu_open_file);
363     new Item("Save as",                 0, fltk_menu_save_file_as);
364     new Item("Quit",                    0, fltk_menu_quit, this);
365     file->end();
366 
367     ItemGroup* edit = new ItemGroup("Edit");
368     edit->begin();
369     new Item("Preferences");
370     edit->end();
371 
372     ItemGroup* view = new ItemGroup("View");
373     view->begin();
374     new Item("Double size");
375     new Item("Fullscreen",              0, fltk_menu_fullscreen, this);
376     view->end();
377 
378     ItemGroup* movie_ctrl = new ItemGroup("Movie control");
379     movie_ctrl->begin();
380     new Item("Play Movie",              0, fltk_menu_play, this);
381     new Item("Pause Movie",             0, fltk_menu_pause, this);
382     new Item("Stop Movie",              0, fltk_menu_stop, this);
383     new Item("Restart Movie",           0, fltk_menu_restart, this);
384     new Item("Toggle Sound",            0, fltk_menu_toggle_sound, this);
385     movie_ctrl->end();
386 
387     ItemGroup* help = new ItemGroup("Help");
388     help->begin();
389     new Item("About");
390     help->end();
391 }
392 
393 
394 
395 bool
createMenu()396 FltkGui::createMenu()
397 {
398     _popup_menu = new PopupMenu(0, 0, w(), h());
399     _popup_menu->type(PopupMenu::POPUP3);
400 
401     _popup_menu->begin();
402 
403     addMenuItems();
404 
405     _popup_menu->end();
406 
407     return true;
408 }
409 
410 void
layout()411 FltkGui::layout()
412 {
413     if (!VM::isInitialized()) {
414       // No movie yet; don't bother resizing anything.
415       return;
416     }
417 
418     // Let FLTK update the window borders, etc.
419     Window::layout();
420 
421     if ((layout_damage() & LAYOUT_WH)) {
422       _glue->resize(w(), h() - _menu_height);
423       resize_view(w(), h() - _menu_height);
424     }
425 }
426 
427 void
setCursor(gnash_cursor_type newcursor)428 FltkGui::setCursor(gnash_cursor_type newcursor)
429 {
430     fltk::Cursor* cursortype;
431 
432     switch(newcursor) {
433       case gnash::CURSOR_HAND:
434         cursortype = fltk::CURSOR_HAND;
435         break;
436       case gnash::CURSOR_INPUT:
437         cursortype = fltk::CURSOR_INSERT;
438         break;
439       default:
440         cursortype = fltk::CURSOR_DEFAULT;
441     }
442 
443     cursor(cursortype);
444 }
445 
446 void
setInvalidatedRegions(const InvalidatedRanges & ranges)447 FltkGui::setInvalidatedRegions(const InvalidatedRanges& ranges)
448 {
449     // forward to renderer
450     //
451     // Why? Why have the region been invalidated ??
452     // Was the renderer offscreen buffer also invalidated
453     // (need to rerender)?
454     // Was only the 'onscreen' buffer be invalidated (no need to rerender,
455     // just to blit) ??
456     //
457     // To be safe just assume this 'invalidated' region is actually
458     // the offscreen buffer, for safety, but we need to clarify this.
459     //
460     _renderer->set_invalidated_regions(ranges);
461 
462     _drawbounds_vec.clear();
463 
464     for (size_t rno=0; rno<ranges.size(); rno++) {
465 
466       geometry::Range2d<int> bounds = Intersection(
467       _renderer->world_to_pixel(ranges.getRange(rno)),
468       _validbounds);
469 
470       // it may happen that a particular range is out of the screen, which
471       // will lead to bounds==null.
472       if (bounds.isNull()) continue;
473 
474       assert(bounds.isFinite());
475 
476       _drawbounds_vec.push_back(bounds);
477 
478     }
479 }
480 
481 // end of namespace
482 }
483 
484