1 // gtk.cpp: Gnome ToolKit graphical user interface, for Gnash.
2 //
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
4 // 2011 Free Software Foundation, Inc
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, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 //
20
21 #ifdef HAVE_CONFIG_H
22 #include "gnashconfig.h"
23 #endif
24
25 #include "gtksup.h"
26 #include "revno.h"
27
28 #include <iostream>
29 #include <string>
30 #include <utility>
31 #include <gtk/gtk.h>
32 #include <gdk/gdk.h>
33 #include <gdk/gdkkeysyms.h>
34 #ifdef HAVE_VA_VA_H
35 # include <va/va.h>
36 # include "vaapi_utils.h"
37 #endif
38 #ifdef HAVE_VA_VA_X11_H
39 # include <va/va_x11.h>
40 #endif
41 #ifdef HAVE_X11_X_H
42 # include <X11/keysym.h>
43 # include <gdk/gdkx.h>
44 # include <X11/Xlib.h>
45 #endif
46
47 #include "log.h"
48 #include "gui.h"
49 #include "rc.h"
50 #include "sound_handler.h"
51 #include "Renderer.h"
52 #include "RunResources.h"
53 #include "VM.h"
54 #include "GnashEnums.h"
55 #include "MediaHandler.h"
56 #include "gtk_canvas.h"
57
58 #ifdef HAVE_VA_VA_H
59 extern VAStatus va_getDriverName(VADisplay dpy, char **driver_name);
60 #endif
61
62 namespace gnash
63 {
64
65 // Forward declarations
66 namespace {
67
68 // Menu Item callbacks
69 void menuSound(GtkMenuItem *menuitem, gpointer instance);
70 void menuFullscreen(GtkMenuItem *menuitem, gpointer instance);
71 void menuRestart(GtkMenuItem *menuitem, gpointer instance);
72 void menuQuit(GtkMenuItem *menuitem, gpointer instance);
73 void menuPlay(GtkMenuItem *menuitem, gpointer instance);
74 void menuPause(GtkMenuItem *menuitem, gpointer instance);
75 void menuStop(GtkMenuItem *menuitem, gpointer instance);
76 void menuAbout(GtkMenuItem *menuitem, gpointer instance);
77 void menuOpenFile(GtkMenuItem *menuitem, gpointer instance);
78 void menuPreferences(GtkMenuItem *menuitem, gpointer instance);
79 void menuMovieInfo(GtkMenuItem *menuitem, gpointer instance);
80 void menuRefreshView(GtkMenuItem *menuitem, gpointer instance);
81 void menuShowUpdatedRegions(GtkMenuItem *menuitem, gpointer instance);
82 void menuQualityLow(GtkMenuItem *menuitem, gpointer instance);
83 void menuQualityMedium(GtkMenuItem *menuitem, gpointer instance);
84 void menuQualityHigh(GtkMenuItem *menuitem, gpointer instance);
85 void menuQualityBest(GtkMenuItem *menuitem, gpointer instance);
86
87 void timeoutQuit(gpointer data);
88
89 // Event handlers
90 gboolean realizeEvent(GtkWidget *widget, GdkEvent *event, gpointer data);
91 gboolean deleteEvent(GtkWidget *widget, GdkEvent *event, gpointer data);
92 gboolean configureEvent(GtkWidget *widget, GdkEventConfigure *event,
93 gpointer data);
94 gboolean keyPressEvent(GtkWidget *widget, GdkEventKey *event,
95 gpointer data);
96 gboolean keyReleaseEvent(GtkWidget *widget, GdkEventKey *event,
97 gpointer data);
98 gboolean buttonPressEvent(GtkWidget *widget, GdkEventButton *event,
99 gpointer data);
100 gboolean buttonReleaseEvent(GtkWidget *widget, GdkEventButton *event,
101 gpointer data);
102 gboolean mouseWheelEvent(GtkWidget *widget, GdkEventScroll *event,
103 gpointer data);
104 gboolean motionNotifyEvent(GtkWidget *widget, GdkEventMotion *event,
105 gpointer data);
106 gboolean visibilityNotifyEvent(GtkWidget *widget, GdkEventVisibility *event,
107 gpointer data);
108 gint popupHandler(GtkWidget *widget, GdkEvent *event);
109
110 gint popupHandlerAlt(GtkWidget *widget, GdkEvent *event);
111
112 void openFile(GtkWidget *widget, gpointer data);
113
114 void addPixmapDirectory(const gchar *directory);
115
116 void addGnashIcon(GtkWindow* window);
117
118 gchar* findPixmapFile(const gchar *filename);
119
120 GdkPixbuf* createPixbuf(const gchar *filename);
121
122 key::code gdk_to_gnash_key(guint key);
123
124 int gdk_to_gnash_modifier(int key);
125
126 //for use in popupHandler
127 bool _showMenuState;
128
129 }
130
~GtkGui()131 GtkGui::~GtkGui()
132 {
133 }
134
GtkGui(unsigned long xid,float scale,bool loop,RunResources & r)135 GtkGui::GtkGui(unsigned long xid, float scale, bool loop, RunResources& r)
136 :
137 Gui(xid, scale, loop, r)
138 ,_window(0)
139 ,_resumeButton(0)
140 ,_overlay(0)
141 ,_canvas(0)
142 ,_visible(true)
143 ,_popup_menu(0)
144 ,_popup_menu_alt(0)
145 ,_menubar(0)
146 ,_vbox(0)
147 ,_exiting(false)
148 ,_advanceSourceTimer(0)
149 {
150 }
151
152 bool
init(int argc,char ** argv[])153 GtkGui::init(int argc, char **argv[])
154 {
155 #ifdef HAVE_X11
156 if (!XInitThreads()) {
157 log_error(_("Failed to initialize X threading support\n"));
158 return false;
159 }
160 #endif
161 gtk_init(&argc, argv);
162
163 addPixmapDirectory (PKGDATADIR);
164
165 if (_xid) {
166 #ifdef _WIN32
167 _window = gtk_plug_new((void *)_xid);
168 #else
169 _window = gtk_plug_new(_xid);
170 #endif
171 // log_debug("Created XEmbedded window");
172 } else {
173 _window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
174 // log_debug ("Created top level window");
175 }
176
177 addGnashIcon(GTK_WINDOW(_window));
178
179 std::string hwaccel = _runResources.getHWAccelBackend();
180 std::string renderer = _runResources.getRenderBackend();
181
182 if (renderer == "opengl") {
183 // See if our X11 server supports the DRI extension, otherwise
184 // there is no point in trying to use OpenGL.
185 bool dri = false;
186 if (checkX11Extension("DRI")) {
187 log_debug("DRI extension found");
188 dri = true;
189 }
190 bool glx = false;
191 // See if our X11 server supports the GLX extension, otherwise
192 // there is no point in trying to use OpenGL.
193 if (checkX11Extension("GLX")) {
194 log_debug("GLX extension found");
195 glx = true;
196 }
197 // If we don't have these extensions, don't bother with OpenGl,
198 // drop back to AGG.
199 if (!glx || !dri) {
200 log_error(_("This system lacks a hardware OpenGL driver!"));
201 }
202 }
203
204 _canvas = gnash_canvas_new();
205 gnash_canvas_setup(GNASH_CANVAS(_canvas), hwaccel, renderer, argc, argv);
206 // Increase reference count to prevent its destruction (which could happen
207 // later if we remove it from its container).
208 g_object_ref(G_OBJECT(_canvas));
209
210 _resumeButton = gtk_button_new();
211 gtk_container_add(GTK_CONTAINER(_resumeButton),
212 gtk_label_new(_("Click to play")));
213 gtk_widget_show_all(_resumeButton);
214
215 // Same here.
216 g_object_ref(G_OBJECT(_resumeButton));
217
218 // This callback indirectly results in playHook() being called.
219 g_signal_connect(_resumeButton, "clicked", G_CALLBACK(menuPlay), this);
220
221 createMenu();
222 createMenuAlt();
223
224 // A vertical box is used to allow display of the menu bar and paused widget
225 _vbox = gtk_vbox_new(FALSE, 0);
226 gtk_widget_show(_vbox);
227 gtk_container_add(GTK_CONTAINER(_window), _vbox);
228
229 #if defined(USE_MENUS)
230 if ( ! _xid ) {
231 createMenuBar();
232 }
233 #endif
234
235 gtk_box_pack_start(GTK_BOX(_vbox), _canvas, TRUE, TRUE, 0);
236
237 setupEvents();
238
239 gtk_widget_realize(_window);
240 gtk_widget_show(_canvas);
241 gtk_widget_show(_window);
242
243 _renderer = gnash_canvas_get_renderer(GNASH_CANVAS(_canvas));
244 _runResources.setRenderer(_renderer);
245
246 // The first time stop() was called, stopHook() might not have had a chance
247 // to do anything, because GTK+ wasn't garanteed to be initialised.
248 //if (isStopped()) stopHook();
249
250 return true;
251 }
252
253 bool
run()254 GtkGui::run()
255 {
256 // Kick-start before setting the interval timeout
257 advance_movie(this);
258
259 if (!_exiting)
260 {
261 gtk_main();
262 }
263 gtk_widget_destroy(_window);
264 return true;
265 }
266
267 void
setTimeout(unsigned int timeout)268 GtkGui::setTimeout(unsigned int timeout)
269 {
270 g_timeout_add(timeout, (GSourceFunc)timeoutQuit, this);
271 }
272
273
274 void
error(const std::string & msg)275 GtkGui::error(const std::string& msg)
276 {
277
278 RcInitFile& rcfile = RcInitFile::getDefaultInstance();
279
280 if (!rcfile.popupMessages()) {
281 return;
282 }
283
284 GtkWidget* popup = gtk_dialog_new_with_buttons("Gnash Error",
285 GTK_WINDOW(_window),
286 static_cast<GtkDialogFlags>(GTK_DIALOG_DESTROY_WITH_PARENT),
287 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, nullptr);
288
289 g_signal_connect_swapped(popup, "response", G_CALLBACK(gtk_widget_destroy),
290 popup);
291
292 #if GTK_CHECK_VERSION(2,14,0)
293 GtkWidget* content = gtk_dialog_get_content_area(GTK_DIALOG(popup));
294 #else
295 GtkWidget* content = GTK_DIALOG(popup)->vbox;
296 #endif
297
298 GtkWidget* label = gtk_label_new(msg.c_str());
299 gtk_widget_set_size_request(label, 400, 200);
300 gtk_label_set_line_wrap(GTK_LABEL(label), true);
301 gtk_box_pack_start(GTK_BOX(content), label, false, false, 0);
302 gtk_widget_show_all(popup);
303 }
304
305 void
setClipboard(const std::string & copy)306 GtkGui::setClipboard(const std::string& copy)
307 {
308 GtkClipboard* cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
309 gtk_clipboard_clear(cb);
310 gtk_clipboard_set_text(cb, copy.c_str(), copy.size());
311 }
312
313 void
setFullscreen()314 GtkGui::setFullscreen()
315 {
316
317 if (_fullscreen) return;
318
319 // Plugin
320 if (_xid) {
321
322 // Create new window and make fullscreen
323 _overlay = gtk_window_new (GTK_WINDOW_TOPLEVEL);
324 addGnashIcon(GTK_WINDOW(_overlay));
325 gtk_window_fullscreen(GTK_WINDOW(_overlay));
326
327 // Reparent drawing area from GtkPlug to fullscreen window
328 gtk_widget_realize(_overlay);
329 gtk_widget_reparent(_vbox, _overlay);
330
331 // Apply key event callbacks to the new window.
332 setupWindowEvents();
333
334 gtk_widget_show(_overlay);
335 }
336
337 // Stand-alone
338 else {
339
340 // This is a hack to fix another hack (see createWindow). If the minimum
341 // size (size request) is larger than the screen, fullscreen messes up.
342 // This way allows the drawing area to be shrunk, which is what we
343 // really want, but not only after we've gone fullscreen.
344 // It could be a good hack if it were done earlier.
345 // There really doesn't seem to be a proper way of setting the
346 // starting size of a widget but allowing it to be shrunk.
347 gtk_widget_set_size_request(_canvas, -1, -1);
348 gtk_window_fullscreen(GTK_WINDOW(_window));
349
350 showMenu(false);
351 }
352
353 _fullscreen = true;
354 }
355
356 void
unsetFullscreen()357 GtkGui::unsetFullscreen()
358 {
359 if (!_fullscreen) return;
360
361 // Plugin
362 if (_xid) {
363 gtk_widget_reparent(_vbox, _window);
364
365 // Apply key event callbacks to the plugin instance.
366 setupWindowEvents();
367 if (_overlay) {
368 gtk_widget_destroy(_overlay);
369 }
370 }
371 else {
372 // Stand-alone
373 gtk_window_unfullscreen(GTK_WINDOW(_window));
374 showMenu(true);
375 }
376
377 _fullscreen = false;
378 }
379
380 void
hideMenu()381 GtkGui::hideMenu()
382 {
383 // Not showing menu anyway if it's a plugin
384 if (_fullscreen || _xid) return;
385
386 // Stand-alone
387 showMenu(false);
388 }
389
390
391 void
setCursor(gnash_cursor_type newcursor)392 GtkGui::setCursor(gnash_cursor_type newcursor)
393 {
394
395 if (!_mouseShown) return;
396
397 GdkCursorType cursortype;
398
399 switch (newcursor)
400 {
401 case CURSOR_HAND:
402 cursortype = GDK_HAND2;
403 break;
404 case CURSOR_INPUT:
405 cursortype = GDK_XTERM;
406 break;
407 default:
408 cursortype = GDK_LAST_CURSOR;
409 }
410
411 GdkCursor* gdkcursor = nullptr;
412
413 if (cursortype != GDK_LAST_CURSOR) {
414 gdkcursor = gdk_cursor_new(cursortype);
415 }
416
417 // The parent of _drawingArea is different for the plugin in fullscreen
418 gdk_window_set_cursor(_canvas->window, gdkcursor);
419
420 if (gdkcursor) {
421 gdk_cursor_unref(gdkcursor);
422 }
423 }
424
425 // Returns whether the mouse was visible before call.
426 bool
showMouse(bool show)427 GtkGui::showMouse(bool show)
428 {
429
430 bool state = _mouseShown;
431
432 RcInitFile& rcfile = RcInitFile::getDefaultInstance();
433
434 // Whether to forcibly show the mouse pointer even if the SWF file
435 // disables it. This allows touchscreen based SWF files to
436 // work on a normal non-touchscreen desktop.
437 if (rcfile.showMouse()) {
438 return true;
439 } else {
440 if (show == _mouseShown) {
441 return state;
442 }
443 }
444
445 if (!show) {
446 GdkPixmap *pixmap;
447 GdkColor *color;
448
449 color = g_new0(GdkColor, 1);
450 pixmap = gdk_pixmap_new(nullptr, 1, 1, 1);
451 GdkCursor* cursor = gdk_cursor_new_from_pixmap(pixmap, pixmap,
452 color, color, 0, 0);
453
454 gdk_window_set_cursor (_canvas->window, cursor);
455
456 g_free(color);
457 g_object_unref(pixmap);
458 gdk_cursor_unref(cursor);
459
460 _mouseShown = false;
461
462 }
463 else if (show) {
464 _mouseShown = true;
465 }
466
467 return state;
468 }
469
470 void
showMenu(bool show)471 GtkGui::showMenu(bool show)
472 {
473 RcInitFile& rcfile = RcInitFile::getDefaultInstance();
474
475 // If we allow the swf author to set Stage.showMenu
476 if( !rcfile.ignoreShowMenu() ) {
477 _showMenuState = show;
478 }
479
480 #ifdef USE_MENUS
481 if (!_menubar) {
482 return;
483 }
484
485 if (show) {
486 gtk_widget_show(_menubar);
487 } else {
488 gtk_widget_hide(_menubar);
489 }
490 #endif
491
492 }
493
494 double
getPixelAspectRatio() const495 GtkGui::getPixelAspectRatio() const
496 {
497 GdkScreen* screen = gdk_screen_get_default();
498
499 const std::pair<int, int> res = screenResolution();
500
501 // Screen size / number of pixels = pixel size.
502 // The physical size of the screen may be reported wrongly by gdk (from X),
503 // but it's the best we have. This method agrees with the pp in my case.
504 double pixelAspectRatio =
505 (gdk_screen_get_height_mm(screen) / static_cast<double>(res.first)) /
506 (gdk_screen_get_width_mm(screen) / static_cast<double>(res.second));
507 return pixelAspectRatio;
508 }
509
510 std::pair<int, int>
screenResolution() const511 GtkGui::screenResolution() const
512 {
513 return std::make_pair(gdk_screen_width(), gdk_screen_height());
514 }
515
516 double
getScreenDPI() const517 GtkGui::getScreenDPI() const
518 {
519 #if GTK_CHECK_VERSION(2,10,0)
520 GdkScreen* screen = gdk_screen_get_default();
521 return gdk_screen_get_resolution(screen);
522 #else
523 return 0;
524 #endif
525 }
526
527 // private
528 void
setupWindowEvents()529 GtkGui::setupWindowEvents()
530 {
531 g_signal_connect(gtk_widget_get_toplevel(_canvas),
532 "delete_event", G_CALLBACK(deleteEvent), this);
533 g_signal_connect(gtk_widget_get_toplevel(_canvas),
534 "key_press_event", G_CALLBACK(keyPressEvent), this);
535 g_signal_connect(gtk_widget_get_toplevel(_canvas),
536 "key_release_event", G_CALLBACK(keyReleaseEvent), this);
537 }
538
539 // public virtual
540 bool
setupEvents()541 GtkGui::setupEvents()
542 {
543
544 setupWindowEvents();
545
546 gtk_widget_add_events(_canvas, GDK_EXPOSURE_MASK
547 | GDK_VISIBILITY_NOTIFY_MASK
548 | GDK_BUTTON_PRESS_MASK
549 | GDK_BUTTON_RELEASE_MASK
550 | GDK_KEY_RELEASE_MASK
551 | GDK_KEY_PRESS_MASK
552 | GDK_POINTER_MOTION_MASK);
553
554 _showMenuState = true; //Default for showMenu
555
556 g_signal_connect_swapped(_canvas, "button_press_event",
557 G_CALLBACK(popupHandler), _popup_menu);
558
559 g_signal_connect_swapped(_canvas, "button_press_event",
560 G_CALLBACK(popupHandlerAlt), _popup_menu_alt);
561
562 g_signal_connect(_canvas, "button_press_event",
563 G_CALLBACK(buttonPressEvent), this);
564 g_signal_connect(_canvas, "button_release_event",
565 G_CALLBACK(buttonReleaseEvent), this);
566 g_signal_connect(_canvas, "motion_notify_event",
567 G_CALLBACK(motionNotifyEvent), this);
568 g_signal_connect(_canvas, "scroll_event",
569 G_CALLBACK(mouseWheelEvent), this);
570 g_signal_connect(_canvas, "visibility-notify-event",
571 G_CALLBACK(visibilityNotifyEvent), this);
572
573 g_signal_connect_after(_canvas, "realize",
574 G_CALLBACK (realizeEvent), nullptr);
575
576 // connect_after because we are going to cause a rendering and the canvas
577 // widget should have had a chance to update the size of the render area
578 g_signal_connect_after(_canvas, "configure_event",
579 G_CALLBACK (configureEvent), this);
580
581 return true;
582 }
583
584 void
grabFocus()585 GtkGui::grabFocus()
586 {
587 gtk_widget_grab_focus(GTK_WIDGET(_canvas));
588 }
589
590 void
quitUI()591 GtkGui::quitUI()
592 {
593 stopAdvanceTimer();
594 // Unregister the callback registered by setTimeout, if any. This also
595 // removes other callbacks, but we're about to go away anyway.
596 while (g_source_remove_by_user_data(this)) {}
597
598 _exiting = true;
599 if (gtk_main_level() > 0)
600 {
601 gtk_main_quit();
602 }
603 }
604
605 /*private*/
606 void
startAdvanceTimer()607 GtkGui::startAdvanceTimer()
608 {
609 stopAdvanceTimer();
610
611 _advanceSourceTimer = g_timeout_add_full(G_PRIORITY_LOW, _interval,
612 (GSourceFunc)advance_movie, this, nullptr);
613
614 log_debug(_("Advance interval timer set to %d ms (~ %d FPS)"),
615 _interval, _interval ? 1000/_interval : 1000);
616 }
617
618 /*private*/
619 void
stopAdvanceTimer()620 GtkGui::stopAdvanceTimer()
621 {
622 if (_advanceSourceTimer)
623 {
624 g_source_remove(_advanceSourceTimer);
625 _advanceSourceTimer = 0;
626 }
627 }
628
629 void
setInterval(unsigned int interval)630 GtkGui::setInterval(unsigned int interval)
631 {
632 _interval = interval;
633
634 if ( ! isStopped() ) {
635 startAdvanceTimer();
636 }
637 }
638
639 ///////////////////////////////////////////////////////////////////////////////
640 ///////////////////////////////////////////////////////////////////////////////
641 /// ///
642 /// Widget functions ///
643 /// ///
644 ///////////////////////////////////////////////////////////////////////////////
645 ///////////////////////////////////////////////////////////////////////////////
646
647 // Setup the menu bar for the top of the window frame.
648 bool
createMenuBar()649 GtkGui::createMenuBar()
650 {
651 _menubar = gtk_menu_bar_new();
652 gtk_widget_show(_menubar);
653 gtk_box_pack_start(GTK_BOX(_vbox), _menubar, FALSE, FALSE, 0);
654
655 createFileMenu(_menubar);
656 createEditMenu(_menubar);
657 createViewMenu(_menubar);
658 createControlMenu(_menubar);
659 createHelpMenu(_menubar);
660
661 return true;
662 }
663
664 bool
createMenu()665 GtkGui::createMenu()
666 {
667 // A menu that pops up (normally) on a right-mouse click.
668
669 _popup_menu = GTK_MENU(gtk_menu_new());
670
671 #ifdef USE_MENUS
672 // If menus are disabled, these are not added to the popup menu
673 // either.
674 createFileMenu(GTK_WIDGET(_popup_menu));
675 createEditMenu(GTK_WIDGET(_popup_menu));
676 createViewMenu(GTK_WIDGET(_popup_menu));
677 createControlMenu(GTK_WIDGET(_popup_menu));
678 #endif
679 createHelpMenu(GTK_WIDGET(_popup_menu));
680
681 GtkWidget *separator1 = gtk_separator_menu_item_new();
682 gtk_widget_show(separator1);
683 gtk_container_add (GTK_CONTAINER(_popup_menu), separator1);
684
685 /// The sound handler is initialized after the Gui is created, and
686 /// may be disabled or enabled dynamically.
687 GtkCheckMenuItem *menusound =
688 GTK_CHECK_MENU_ITEM(gtk_check_menu_item_new_with_label(_("Sound")));
689 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(menusound), TRUE);
690 gtk_menu_append(_popup_menu, GTK_WIDGET(menusound));
691 gtk_widget_show(GTK_WIDGET(menusound));
692 g_signal_connect(menusound, "activate", G_CALLBACK(menuSound), this);
693
694 GtkWidget *separator2 = gtk_separator_menu_item_new();
695 gtk_widget_show(separator2);
696 gtk_container_add (GTK_CONTAINER(_popup_menu), separator2);
697
698 GtkWidget *quit = gtk_image_menu_item_new_from_stock("gtk-quit", 0);
699 gtk_widget_show(quit);
700 gtk_container_add(GTK_CONTAINER(_popup_menu), quit);
701 g_signal_connect(quit, "activate", G_CALLBACK(menuQuit), this);
702
703 return true;
704 }
705
706 bool
createMenuAlt()707 GtkGui::createMenuAlt()
708 {
709 //An alternative short version of the popup menu
710
711 _popup_menu_alt = GTK_MENU(gtk_menu_new());
712
713 #ifdef USE_MENUS
714 // If menus are disabled, these are not added to the popup menu
715 // either.
716 createEditMenu(GTK_WIDGET(_popup_menu_alt));
717 #endif
718 createHelpMenu(GTK_WIDGET(_popup_menu_alt));
719
720 GtkWidget *separator1 = gtk_separator_menu_item_new();
721 gtk_widget_show(separator1);
722 gtk_container_add (GTK_CONTAINER(_popup_menu_alt), separator1);
723
724 GtkWidget *quit = gtk_image_menu_item_new_from_stock("gtk-quit", 0);
725 gtk_widget_show(quit);
726 gtk_container_add(GTK_CONTAINER(_popup_menu_alt), quit);
727 g_signal_connect(quit, "activate", G_CALLBACK(menuQuit), this);
728
729 return true;
730 }
731
732 void
resizeWindow(int width,int height)733 GtkGui::resizeWindow(int width, int height)
734 {
735 // log_debug("GtkGui: Window resize request received");
736
737 if (!_xid) {
738
739 // This sets the *minimum* size for the drawing area and thus will
740 // also resize the window if needed.
741 // Advantage: The window is sized correctly, no matter what other
742 // widgets are visible
743 // Disadvantage: The window will never be shrinked, which is bad.
744 gtk_widget_set_size_request(_canvas, width, height);
745 }
746 }
747
748 bool
createWindow(const char * title,int width,int height,int xPosition,int yPosition)749 GtkGui::createWindow(const char *title, int width, int height,
750 int xPosition, int yPosition)
751 {
752 // First call the old createWindow function and then set the title.
753 // In case there's some need to not setting the title.
754 bool ret = createWindow(width, height);
755 gtk_window_set_title(GTK_WINDOW(_window), title);
756
757 // Move the window to correct position if requested by user.
758 int x, y;
759 gtk_window_get_position(GTK_WINDOW(_window), &x, &y);
760 if (xPosition > -1) x = xPosition; // -1 so we can tell if user requested window move
761 if (yPosition > -1) y = yPosition; // as 0 is also a valid coordinate.
762 gtk_window_move(GTK_WINDOW(_window), x, y);
763
764 if (!_xid) {
765
766 // This sets the *minimum* size for the drawing area and thus will
767 // also resize the window.
768 // Advantage: The window is sized correctly, no matter what other
769 // widgets are visible
770 // Disadvantage: The window cannot be shrinked, which is bad.
771 gtk_widget_set_size_request(_canvas, width, height);
772
773 }
774 return ret;
775 }
776
777 #ifdef USE_SWFTREE
778
779 // This creates a GtkTree model for displaying movie info.
780 GtkTreeModel*
makeTreeModel(const std::unique_ptr<movie_root::InfoTree> & treepointer)781 GtkGui::makeTreeModel(const std::unique_ptr<movie_root::InfoTree>& treepointer)
782 {
783
784 const movie_root::InfoTree& info = *treepointer;
785
786 enum
787 {
788 STRING1_COLUMN,
789 STRING2_COLUMN,
790 NUM_COLUMNS
791 };
792
793 GtkTreeStore *model = gtk_tree_store_new (NUM_COLUMNS,
794 G_TYPE_STRING, G_TYPE_STRING);
795
796 GtkTreeIter iter = {0, 0, 0, 0};
797 GtkTreeIter child_iter = {0, 0, 0, 0};
798 GtkTreeIter parent_iter = {0, 0, 0, 0};
799
800 // Depth within the *GTK* tree.
801 int depth = 0;
802
803 assert(info.depth(info.begin()) == 0); // seems assumed in the code below
804 for (movie_root::InfoTree::iterator i = info.begin(), e = info.end();
805 i != e; ++i) {
806
807 const movie_root::InfoTree::value_type& p = *i;
808
809 std::ostringstream os;
810 os << info.depth(i);
811
812 int newdepth = info.depth(i);
813
814 if (newdepth > depth) {
815 assert(newdepth == depth+1);
816 depth++;
817 iter=child_iter;
818 }
819
820 if (newdepth < depth) {
821 int gap = depth - newdepth;
822 depth = newdepth;
823 while (gap--) {
824 gtk_tree_model_iter_parent(GTK_TREE_MODEL(model),
825 &parent_iter, &iter);
826 iter = parent_iter;
827 }
828 }
829
830 //Read in data from present node
831 if (depth == 0) gtk_tree_store_append(model, &child_iter, nullptr);
832 else gtk_tree_store_append(model, &child_iter, &iter);
833
834 gtk_tree_store_set(model, &child_iter,
835 STRING1_COLUMN, p.first.c_str(), // "Variable"
836 STRING2_COLUMN, p.second.c_str(), // "Value"
837 -1);
838
839 }
840
841 return GTK_TREE_MODEL(model);
842
843 }
844
845 #endif
846
847
848 ///////////////////////////////////////////////////////////////////////////////
849 ///////////////////////////////////////////////////////////////////////////////
850 /// ///
851 /// Rendering stuff ///
852 /// ///
853 ///////////////////////////////////////////////////////////////////////////////
854 ///////////////////////////////////////////////////////////////////////////////
855
856 bool
createWindow(int width,int height)857 GtkGui::createWindow(int width, int height)
858 {
859 assert(_width>0);
860 assert(_height>0);
861
862 _width = width;
863 _height = height;
864
865 _validbounds.setTo(0, 0, _width, _height);
866
867 return true;
868 }
869
870 void
beforeRendering()871 GtkGui::beforeRendering()
872 {
873 gnash_canvas_before_rendering(GNASH_CANVAS(_canvas), getStage());
874 }
875
876 void
renderBuffer()877 GtkGui::renderBuffer()
878 {
879 gdk_window_process_updates(_canvas->window, false);
880 }
881
882 void
setInvalidatedRegions(const InvalidatedRanges & ranges)883 GtkGui::setInvalidatedRegions(const InvalidatedRanges& ranges)
884 {
885 // forward to renderer
886 //
887 // Why? Why have the region been invalidated ??
888 // A: I don't understand this question.
889 // Was the renderer offscreen buffer also invalidated
890 // (need to rerender)?
891 // A: Yes.
892 // Was only the 'onscreen' buffer be invalidated (no need to rerender,
893 // just to blit) ??
894 // A: I don't understand this question.
895 //
896 // Clarification: the render (optionally) only draws to the invalidated
897 // (i.e., changed) part of the buffer. So we need to tell the renderer
898 // where that is. The renderer draws to the offscreen buffer. (Although
899 // that should be obvious!)
900 _renderer->set_invalidated_regions(ranges);
901
902 for (unsigned rno=0; rno<ranges.size(); rno++) {
903 geometry::Range2d<int> bounds = Intersection(
904 _renderer->world_to_pixel(ranges.getRange(rno)),
905 _validbounds);
906
907 // it may happen that a particular range is out of the screen, which
908 // will lead to bounds==null.
909 if (bounds.isNull()) continue;
910
911 assert(bounds.isFinite());
912
913 GdkRectangle rect;
914 rect.x = bounds.getMinX();
915 rect.y = bounds.getMinY();
916 rect.width = bounds.width();
917 rect.height = bounds.height();
918
919 // We add the rectangle to the part of the window to be redrawn
920 // (also known as the "clipping" or "damaged" area). in renderBuffer(),
921 // we force a redraw.
922 gdk_window_invalidate_rect(_canvas->window, &rect, false);
923 }
924
925 }
926
927
928 ///////////////////////////////////////////////////////////////////////////////
929 ///////////////////////////////////////////////////////////////////////////////
930 /// ///
931 /// Dialogues ///
932 /// ///
933 ///////////////////////////////////////////////////////////////////////////////
934 ///////////////////////////////////////////////////////////////////////////////
935
936 namespace {
937
938 class PreferencesDialog
939 {
940
941 public:
942
943 PreferencesDialog(GtkWidget* window);
944
945 void show();
946
947 private:
948
949 // A struct containing pointers to widgets for passing preference
950 // data from the dialogue
951 struct PrefWidgets {
952 GtkWidget *soundToggle;
953 GtkWidget *actionDumpToggle;
954 GtkWidget *parserDumpToggle;
955 GtkWidget *malformedSWFToggle;
956 GtkWidget *ASCodingErrorToggle;
957 GtkWidget *logfileName;
958 GtkWidget *writeLogToggle;
959 GtkWidget *verbosityScale;
960 GtkWidget *streamsTimeoutScale;
961 GtkWidget *localDomainToggle;
962 GtkWidget *localHostToggle;
963 GtkWidget *solReadOnlyToggle;
964 GtkWidget *solLocalDomainToggle;
965 GtkWidget *localConnectionToggle;
966 GtkWidget *insecureSSLToggle;
967 GtkWidget *solSandbox;
968 GtkWidget *osText;
969 GtkWidget *versionText;
970 GtkWidget *urlOpenerText;
971 GtkWidget *librarySize;
972 GtkWidget *startStoppedToggle;
973 GtkWidget *mediaDir;
974 GtkWidget *saveStreamingMediaToggle;
975 GtkWidget *saveLoadedMediaToggle;
976 GtkWidget *scriptsTimeout;
977 GtkWidget *scriptsRecursionLimit;
978 GtkWidget *lockScriptLimitsToggle;
979
PrefWidgetsgnash::__anonded7254c0311::PreferencesDialog::PrefWidgets980 PrefWidgets()
981 :
982 soundToggle(0),
983 actionDumpToggle(0),
984 parserDumpToggle(0),
985 malformedSWFToggle(0),
986 ASCodingErrorToggle(0),
987 logfileName(0),
988 writeLogToggle(0),
989 verbosityScale(0),
990 streamsTimeoutScale(0),
991 localDomainToggle(0),
992 localHostToggle(0),
993 solReadOnlyToggle(0),
994 solLocalDomainToggle(0),
995 localConnectionToggle(0),
996 insecureSSLToggle(0),
997 solSandbox(0),
998 osText(0),
999 versionText(0),
1000 urlOpenerText(0),
1001 librarySize(0),
1002 startStoppedToggle(0),
1003 mediaDir(0),
1004 saveStreamingMediaToggle(0),
1005 saveLoadedMediaToggle(0),
1006 scriptsTimeout(0),
1007 scriptsRecursionLimit(0),
1008 lockScriptLimitsToggle(0)
1009 {}
1010
1011 };
1012
1013 static void handlePrefs(GtkWidget* widget, gint response, gpointer data);
1014
1015 /// Network Tab
1016 void addNetworkTab();
1017
1018 /// Logging Tab
1019 void addLoggingTab();
1020
1021 void addSecurityTab();
1022
1023 void addMediaTab();
1024
1025 void addPlayerTab();
1026
1027 GtkWidget* _window;
1028
1029 PrefWidgets* _prefs;
1030
1031 RcInitFile& _rcfile;
1032
1033 GtkWidget* _prefsDialog;
1034
1035 GtkWidget* _notebook;
1036
1037 };
1038
1039
1040 // Callback to read values from the preferences dialogue and set rcfile
1041 // values accordingly.
1042 void
handlePrefs(GtkWidget * dialog,gint response,gpointer data)1043 PreferencesDialog::handlePrefs(GtkWidget* dialog, gint response, gpointer data)
1044 {
1045
1046 PrefWidgets *prefs = static_cast<PrefWidgets*>(data);
1047
1048 RcInitFile& _rcfile = RcInitFile::getDefaultInstance();
1049
1050 if (response == GTK_RESPONSE_OK) {
1051
1052 // For getting from const gchar* to std::string&
1053 std::string tmp;
1054
1055 if (prefs->soundToggle) {
1056 _rcfile.useSound(gtk_toggle_button_get_active(
1057 GTK_TOGGLE_BUTTON(prefs->soundToggle)));
1058 }
1059
1060 if (prefs->saveLoadedMediaToggle) {
1061 _rcfile.saveLoadedMedia(
1062 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
1063 prefs->saveLoadedMediaToggle)));
1064 }
1065
1066 if (prefs->saveStreamingMediaToggle) {
1067 _rcfile.saveStreamingMedia(
1068 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
1069 prefs->saveStreamingMediaToggle)));
1070 }
1071
1072 if (prefs->mediaDir) {
1073 tmp = gtk_entry_get_text(GTK_ENTRY(prefs->mediaDir));
1074 _rcfile.setMediaDir(tmp);
1075 }
1076
1077 if (prefs->actionDumpToggle) {
1078 _rcfile.useActionDump(
1079 gtk_toggle_button_get_active(
1080 GTK_TOGGLE_BUTTON(prefs->actionDumpToggle)));
1081 }
1082
1083 if (prefs->parserDumpToggle) {
1084 _rcfile.useParserDump(
1085 gtk_toggle_button_get_active(
1086 GTK_TOGGLE_BUTTON(prefs->parserDumpToggle)));
1087 }
1088
1089 if ( prefs->logfileName ) {
1090 tmp = gtk_entry_get_text(GTK_ENTRY(prefs->logfileName));
1091 _rcfile.setDebugLog(tmp);
1092 }
1093
1094 if ( prefs->writeLogToggle ) {
1095 _rcfile.useWriteLog(
1096 gtk_toggle_button_get_active(
1097 GTK_TOGGLE_BUTTON(prefs->writeLogToggle)));
1098 }
1099
1100 if ( prefs->verbosityScale ) {
1101 _rcfile.verbosityLevel(static_cast<int>(
1102 gtk_range_get_value(GTK_RANGE(prefs->verbosityScale))));
1103 }
1104
1105 if ( prefs->streamsTimeoutScale ) {
1106 _rcfile.setStreamsTimeout(
1107 gtk_spin_button_get_value_as_int(
1108 GTK_SPIN_BUTTON(prefs->streamsTimeoutScale)));
1109 }
1110
1111 if ( prefs->ASCodingErrorToggle ) {
1112 _rcfile.showASCodingErrors(
1113 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
1114 prefs->ASCodingErrorToggle)));
1115 }
1116
1117 if ( prefs->malformedSWFToggle ) {
1118 _rcfile.showMalformedSWFErrors(
1119 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
1120 prefs->malformedSWFToggle)));
1121 }
1122
1123 if ( prefs->localHostToggle ) {
1124 _rcfile.useLocalHost(
1125 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
1126 prefs->localHostToggle)));
1127 }
1128
1129 if ( prefs->localDomainToggle ) {
1130 _rcfile.useLocalDomain(
1131 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
1132 prefs->localDomainToggle)));
1133 }
1134
1135 if ( prefs->solLocalDomainToggle ) {
1136 _rcfile.setSOLLocalDomain(
1137 gtk_toggle_button_get_active(
1138 GTK_TOGGLE_BUTTON(prefs->solLocalDomainToggle)));
1139 }
1140
1141 if ( prefs->solReadOnlyToggle ) {
1142 _rcfile.setSOLReadOnly(
1143 gtk_toggle_button_get_active(
1144 GTK_TOGGLE_BUTTON(prefs->solReadOnlyToggle)));
1145 }
1146
1147 if ( prefs->localConnectionToggle ) {
1148 _rcfile.setLocalConnection(
1149 gtk_toggle_button_get_active(
1150 GTK_TOGGLE_BUTTON(prefs->localConnectionToggle)));
1151 }
1152
1153 if ( prefs->insecureSSLToggle ) {
1154 _rcfile.insecureSSL(
1155 gtk_toggle_button_get_active(
1156 GTK_TOGGLE_BUTTON(prefs->insecureSSLToggle)));
1157 }
1158
1159 if ( prefs->solSandbox ) {
1160 tmp = gtk_entry_get_text(GTK_ENTRY(prefs->solSandbox));
1161 _rcfile.setSOLSafeDir(tmp);
1162 }
1163
1164 if ( prefs->osText ) {
1165 tmp = gtk_entry_get_text(GTK_ENTRY(prefs->osText));
1166 _rcfile.setFlashSystemOS(tmp);
1167 }
1168
1169 if ( prefs->versionText ) {
1170 tmp = gtk_entry_get_text(GTK_ENTRY(prefs->versionText));
1171 _rcfile.setFlashVersionString(tmp);
1172 }
1173
1174 if ( prefs->librarySize ) {
1175 _rcfile.setMovieLibraryLimit(
1176 gtk_spin_button_get_value_as_int(
1177 GTK_SPIN_BUTTON(prefs->librarySize)));
1178 }
1179
1180 if ( prefs->startStoppedToggle ) {
1181 _rcfile.startStopped(
1182 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(prefs->startStoppedToggle)));
1183 }
1184
1185 if ( prefs->scriptsTimeout ) {
1186 _rcfile.setScriptsTimeout(
1187 gtk_spin_button_get_value_as_int(
1188 GTK_SPIN_BUTTON(prefs->scriptsTimeout)));
1189 }
1190
1191 if ( prefs->scriptsRecursionLimit ) {
1192 _rcfile.setScriptsRecursionLimit(
1193 gtk_spin_button_get_value_as_int(
1194 GTK_SPIN_BUTTON(prefs->scriptsRecursionLimit)));
1195 }
1196
1197 if ( prefs->lockScriptLimitsToggle ) {
1198 _rcfile.lockScriptLimits(
1199 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(prefs->lockScriptLimitsToggle)));
1200 }
1201
1202 if ( prefs->urlOpenerText ) {
1203 tmp = gtk_entry_get_text(GTK_ENTRY(prefs->urlOpenerText));
1204 _rcfile.setURLOpenerFormat(tmp);
1205 }
1206
1207
1208 // Let _rcfile decide which file to update: generally the file
1209 // being used if specified in GNASHRC environment variable, or in
1210 // the user's home directory if that can be found.
1211 // TODO: We can also specify here which file should be written
1212 // by passing that instead. How might that best be done?
1213 _rcfile.updateFile();
1214
1215 // Close the window when 'ok' is clicked
1216 gtk_widget_destroy(dialog);
1217 }
1218
1219 else if (response == GTK_RESPONSE_CANCEL) {
1220 // Close the window when 'cancel' is clicked
1221 gtk_widget_destroy(dialog);
1222 }
1223
1224 delete prefs;
1225 }
1226
1227 void
show()1228 PreferencesDialog::show()
1229 {
1230 gtk_widget_show_all(_prefsDialog);
1231 }
1232
PreferencesDialog(GtkWidget * window)1233 PreferencesDialog::PreferencesDialog(GtkWidget* window)
1234 :
1235 _window(window),
1236 _prefs(new PrefWidgets),
1237 _rcfile(RcInitFile::getDefaultInstance())
1238 {
1239 // Create top-level window
1240 _prefsDialog = gtk_dialog_new_with_buttons(
1241 _("Gnash preferences"),
1242 GTK_WINDOW(_window),
1243 // Needs an explicit cast in C++
1244 GtkDialogFlags(
1245 GTK_DIALOG_DESTROY_WITH_PARENT |
1246 GTK_DIALOG_NO_SEPARATOR),
1247 // The buttons and their response codes:
1248 GTK_STOCK_OK, GTK_RESPONSE_OK,
1249 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1250 nullptr);
1251 // Add Gnash icon
1252 addGnashIcon(GTK_WINDOW(_prefsDialog));
1253
1254 // Add notebook (tabs) to dialogue's vbox
1255 _notebook = gtk_notebook_new ();
1256 gtk_container_add (
1257 GTK_CONTAINER(GTK_DIALOG(_prefsDialog)->vbox), _notebook);
1258
1259 // Pass the widgets containing settings to the callback function
1260 // when any button is clicked or when the dialogue is destroyed.
1261 g_signal_connect (_prefsDialog, "response", G_CALLBACK(&handlePrefs), _prefs);
1262
1263 addLoggingTab();
1264 addSecurityTab();
1265 addNetworkTab();
1266 addMediaTab();
1267 addPlayerTab();
1268 }
1269
1270 void
addNetworkTab()1271 PreferencesDialog::addNetworkTab()
1272 {
1273 GtkWidget *vbox = gtk_vbox_new (FALSE, 10);
1274
1275 // Tab label
1276 GtkWidget *label = gtk_label_new_with_mnemonic (_("_Network"));
1277 gtk_notebook_append_page(GTK_NOTEBOOK(_notebook), GTK_WIDGET(vbox), label);
1278
1279 // Network preferences
1280 label = gtk_label_new (_("<b>Network preferences</b>"));
1281 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
1282 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
1283
1284 // Streams timeout
1285 GtkWidget *timeoutbox = gtk_hbox_new (FALSE, 2);
1286 gtk_box_pack_start(GTK_BOX(vbox), timeoutbox, FALSE, FALSE, 0);
1287
1288 label = gtk_label_new (_("Network timeout in seconds (0 for no timeout):"));
1289 gtk_box_pack_start(GTK_BOX(timeoutbox), label, FALSE, FALSE, 0);
1290 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
1291
1292 _prefs->streamsTimeoutScale = gtk_spin_button_new_with_range(0, 300, 1);
1293 gtk_box_pack_start(GTK_BOX(timeoutbox), _prefs->streamsTimeoutScale, FALSE,
1294 FALSE, 0);
1295 // Align to _rcfile value:
1296 gtk_spin_button_set_value(GTK_SPIN_BUTTON(_prefs->streamsTimeoutScale),
1297 _rcfile.getStreamsTimeout());
1298
1299 }
1300
1301 void
addLoggingTab()1302 PreferencesDialog::addLoggingTab()
1303 {
1304 GtkWidget *loggingvbox = gtk_vbox_new (FALSE, 10);
1305
1306 // Tab label
1307 GtkWidget *loggingtablabel = gtk_label_new_with_mnemonic (_("_Logging"));
1308 gtk_notebook_append_page(GTK_NOTEBOOK(_notebook), GTK_WIDGET(loggingvbox),
1309 loggingtablabel);
1310
1311 // Logging options
1312 GtkWidget *logginglabel = gtk_label_new (_("<b>Logging options</b>"));
1313 gtk_label_set_use_markup (GTK_LABEL (logginglabel), TRUE);
1314 gtk_box_pack_start(GTK_BOX(loggingvbox), logginglabel, FALSE, FALSE, 0);
1315
1316 GtkWidget *verbositylabel = gtk_label_new (_("Verbosity level:"));
1317 gtk_box_pack_start(GTK_BOX(loggingvbox), verbositylabel, FALSE, FALSE, 0);
1318 gtk_misc_set_alignment (GTK_MISC (verbositylabel), 0, 0.5);
1319
1320 _prefs->verbosityScale = gtk_hscale_new(GTK_ADJUSTMENT(
1321 gtk_adjustment_new(_rcfile.verbosityLevel(), 0, 10, 1, 0, 0)));
1322 gtk_scale_set_digits(GTK_SCALE(_prefs->verbosityScale), 0);
1323 gtk_range_set_update_policy(GTK_RANGE(
1324 _prefs->verbosityScale), GTK_UPDATE_DISCONTINUOUS);
1325 gtk_box_pack_start(GTK_BOX(loggingvbox), _prefs->verbosityScale, FALSE,
1326 FALSE, 0);
1327
1328 _prefs->writeLogToggle =
1329 gtk_check_button_new_with_mnemonic(_("Log to _file"));
1330 gtk_box_pack_start(GTK_BOX(loggingvbox), _prefs->writeLogToggle, FALSE,
1331 FALSE, 0);
1332 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(_prefs->writeLogToggle),
1333 _rcfile.useWriteLog());
1334
1335 GtkWidget *logfilelabel = gtk_label_new(_("Logfile name:"));
1336 gtk_box_pack_start(GTK_BOX(loggingvbox), logfilelabel, FALSE, FALSE, 0);
1337 gtk_misc_set_alignment(GTK_MISC(logfilelabel), 0, 0.5);
1338
1339 _prefs->logfileName = gtk_entry_new();
1340 gtk_box_pack_start(GTK_BOX(loggingvbox), _prefs->logfileName, FALSE,
1341 FALSE, 0);
1342
1343 // Put debug filename in the entry box
1344 gtk_entry_set_text(GTK_ENTRY(_prefs->logfileName),
1345 _rcfile.getDebugLog().c_str());
1346
1347 _prefs->parserDumpToggle =
1348 gtk_check_button_new_with_mnemonic(_("Log _parser output"));
1349 gtk_box_pack_start(GTK_BOX(loggingvbox), _prefs->parserDumpToggle, FALSE,
1350 FALSE, 0);
1351 // Align button state with _rcfile
1352 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(_prefs->parserDumpToggle),
1353 _rcfile.useParserDump());
1354
1355 _prefs->actionDumpToggle =
1356 gtk_check_button_new_with_mnemonic(_("Log SWF _actions"));
1357 gtk_box_pack_start(GTK_BOX(loggingvbox), _prefs->actionDumpToggle, FALSE,
1358 FALSE, 0);
1359 // Align button state with _rcfile
1360 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(_prefs->actionDumpToggle),
1361 _rcfile.useActionDump());
1362
1363 _prefs->malformedSWFToggle =
1364 gtk_check_button_new_with_mnemonic(_("Log malformed SWF _errors"));
1365 gtk_box_pack_start(GTK_BOX(loggingvbox), _prefs->malformedSWFToggle,
1366 FALSE, FALSE, 0);
1367 // Align button state with _rcfile
1368 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(_prefs->malformedSWFToggle),
1369 _rcfile.showMalformedSWFErrors());
1370
1371 _prefs->ASCodingErrorToggle = gtk_check_button_new_with_mnemonic(
1372 _("Log ActionScript _coding errors"));
1373 gtk_box_pack_start(GTK_BOX(loggingvbox), _prefs->ASCodingErrorToggle,
1374 FALSE, FALSE, 0);
1375 // Align button state with _rcfile
1376 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(_prefs->ASCodingErrorToggle),
1377 _rcfile.showASCodingErrors());
1378
1379 }
1380
1381 void
addSecurityTab()1382 PreferencesDialog::addSecurityTab()
1383 {
1384 // Security Tab
1385 GtkWidget *securityvbox = gtk_vbox_new (FALSE, 14);
1386
1387 // Security tab title
1388 GtkWidget *securitytablabel = gtk_label_new_with_mnemonic (_("_Security"));
1389
1390 gtk_notebook_append_page(GTK_NOTEBOOK(_notebook),
1391 GTK_WIDGET(securityvbox), securitytablabel);
1392
1393 // Network connection
1394 GtkWidget *netconnectionslabel = gtk_label_new(
1395 _("<b>Network connections</b>"));
1396 gtk_label_set_use_markup(GTK_LABEL(netconnectionslabel), TRUE);
1397 gtk_box_pack_start(GTK_BOX(securityvbox), netconnectionslabel, FALSE,
1398 FALSE, 0);
1399
1400 _prefs->localHostToggle = gtk_check_button_new_with_mnemonic(
1401 _("Connect only to local _host"));
1402 gtk_box_pack_start(GTK_BOX(securityvbox), _prefs->localHostToggle, FALSE,
1403 FALSE, 0);
1404 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(_prefs->localHostToggle),
1405 _rcfile.useLocalHost());
1406
1407 _prefs->localDomainToggle = gtk_check_button_new_with_mnemonic(
1408 _("Connect only to local _domain"));
1409 gtk_box_pack_start(GTK_BOX(securityvbox), _prefs->localDomainToggle,
1410 FALSE, FALSE, 0);
1411 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(_prefs->localDomainToggle),
1412 _rcfile.useLocalDomain());
1413
1414 _prefs->insecureSSLToggle = gtk_check_button_new_with_mnemonic(
1415 _("Disable SSL _verification"));
1416 gtk_box_pack_start(GTK_BOX(securityvbox), _prefs->insecureSSLToggle,
1417 FALSE, FALSE, 0);
1418 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(_prefs->insecureSSLToggle),
1419 _rcfile.insecureSSL());
1420
1421 GtkWidget *whitelistexpander =
1422 gtk_expander_new_with_mnemonic(_("_Whitelist"));
1423 gtk_box_pack_start(GTK_BOX(securityvbox), whitelistexpander, FALSE,
1424 FALSE, 0);
1425
1426 GtkWidget *whitelistcomboboxentry1 = gtk_combo_box_entry_new_text();
1427 gtk_container_add(GTK_CONTAINER(whitelistexpander),
1428 whitelistcomboboxentry1);
1429
1430 GtkWidget *blacklistexpander =
1431 gtk_expander_new_with_mnemonic(_("_Blacklist"));
1432 gtk_box_pack_start(GTK_BOX (securityvbox), blacklistexpander, FALSE,
1433 FALSE, 0);
1434
1435 GtkWidget *blacklistcomboboxentry2 = gtk_combo_box_entry_new_text();
1436 gtk_container_add (GTK_CONTAINER(blacklistexpander),
1437 blacklistcomboboxentry2);
1438
1439 // Privacy
1440 GtkWidget *privacylabel = gtk_label_new(_("<b>Privacy</b>"));
1441 gtk_label_set_use_markup(GTK_LABEL(privacylabel), TRUE);
1442 gtk_box_pack_start(GTK_BOX(securityvbox), privacylabel, FALSE, FALSE, 0);
1443
1444 GtkWidget *solsandboxlabel = gtk_label_new(_("Shared objects directory:"));
1445 gtk_box_pack_start(GTK_BOX(securityvbox), solsandboxlabel, FALSE,
1446 FALSE, 0);
1447 gtk_misc_set_alignment(GTK_MISC (solsandboxlabel), 0, 0.5);
1448
1449 _prefs->solSandbox = gtk_entry_new();
1450 gtk_entry_set_text(GTK_ENTRY(_prefs->solSandbox),
1451 _rcfile.getSOLSafeDir().c_str());
1452 gtk_box_pack_start(GTK_BOX(securityvbox), _prefs->solSandbox, FALSE,
1453 FALSE, 0);
1454
1455 _prefs->solReadOnlyToggle = gtk_check_button_new_with_mnemonic(
1456 _("Do _not write Shared Object files"));
1457 gtk_box_pack_start(GTK_BOX(securityvbox), _prefs->solReadOnlyToggle,
1458 FALSE, FALSE, 0);
1459 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(_prefs->solReadOnlyToggle),
1460 _rcfile.getSOLReadOnly());
1461
1462 _prefs->solLocalDomainToggle = gtk_check_button_new_with_mnemonic(
1463 _("Only _access local Shared Object files"));
1464 gtk_box_pack_start(GTK_BOX(securityvbox), _prefs->solLocalDomainToggle,
1465 FALSE, FALSE, 0);
1466 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
1467 _prefs->solLocalDomainToggle), _rcfile.getSOLLocalDomain());
1468
1469 _prefs->localConnectionToggle = gtk_check_button_new_with_mnemonic(
1470 _("Disable Local _Connection object"));
1471 gtk_box_pack_start(GTK_BOX(securityvbox), _prefs->localConnectionToggle,
1472 FALSE, FALSE, 0);
1473 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
1474 _prefs->localConnectionToggle), _rcfile.getLocalConnection());
1475 }
1476
1477 void
addMediaTab()1478 PreferencesDialog::addMediaTab()
1479 {
1480 // Media Tab
1481 GtkWidget *mediavbox = gtk_vbox_new (FALSE, 2);
1482
1483 // Media tab title
1484 GtkWidget *mediatablabel = gtk_label_new_with_mnemonic (_("_Media"));
1485
1486 gtk_notebook_append_page(GTK_NOTEBOOK(_notebook),
1487 GTK_WIDGET(mediavbox), mediatablabel);
1488
1489 // Sound
1490 GtkWidget *soundlabel = gtk_label_new(_("<b>Sound</b>"));
1491 gtk_label_set_use_markup(GTK_LABEL(soundlabel), TRUE);
1492 gtk_box_pack_start(GTK_BOX(mediavbox), soundlabel, FALSE, FALSE, 0);
1493
1494 _prefs->soundToggle = gtk_check_button_new_with_mnemonic(
1495 _("Use sound _handler"));
1496 gtk_box_pack_start(GTK_BOX(mediavbox), _prefs->soundToggle, FALSE,
1497 FALSE, 0);
1498 // Align button state with rcfile
1499 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(_prefs->soundToggle),
1500 _rcfile.useSound());
1501
1502 // Save Media
1503 GtkWidget *savemedia = gtk_label_new(_("<b>Media Streams</b>"));
1504 gtk_label_set_use_markup(GTK_LABEL(savemedia), TRUE);
1505 gtk_box_pack_start(GTK_BOX(mediavbox), savemedia, FALSE, FALSE, 0);
1506
1507 // Save streamed media Toggle
1508 _prefs->saveStreamingMediaToggle = gtk_check_button_new_with_mnemonic(
1509 _("Save media streams to disk"));
1510 gtk_box_pack_start (GTK_BOX(mediavbox), _prefs->saveStreamingMediaToggle,
1511 FALSE, FALSE, 0);
1512 // Align button state with rcfile
1513 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
1514 _prefs->saveStreamingMediaToggle), _rcfile.saveStreamingMedia());
1515
1516 // Save loaded media Toggle
1517 _prefs->saveLoadedMediaToggle = gtk_check_button_new_with_mnemonic(
1518 _("Save dynamically loaded media to disk"));
1519 gtk_box_pack_start (GTK_BOX(mediavbox), _prefs->saveLoadedMediaToggle,
1520 FALSE, FALSE, 0);
1521 // Align button state with rcfile
1522 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
1523 _prefs->saveLoadedMediaToggle), _rcfile.saveLoadedMedia());
1524
1525 // Directory for saving media
1526 GtkWidget *mediastreamslabel = gtk_label_new(_("Saved media directory:"));
1527 gtk_box_pack_start(GTK_BOX(mediavbox), mediastreamslabel, FALSE,
1528 FALSE, 0);
1529 gtk_misc_set_alignment (GTK_MISC (mediastreamslabel), 0, 0.5);
1530
1531 _prefs->mediaDir = gtk_entry_new();
1532 gtk_entry_set_text(GTK_ENTRY(_prefs->mediaDir),
1533 _rcfile.getMediaDir().c_str());
1534 gtk_box_pack_start(GTK_BOX(mediavbox), _prefs->mediaDir, FALSE,
1535 FALSE, 0);
1536
1537 }
1538
1539 void
addPlayerTab()1540 PreferencesDialog::addPlayerTab()
1541 {
1542 // Player Tab
1543 GtkWidget *playervbox = gtk_vbox_new (FALSE, 14);
1544
1545 // Player tab title
1546 GtkWidget *playertablabel = gtk_label_new_with_mnemonic (_("_Player"));
1547
1548 gtk_notebook_append_page(GTK_NOTEBOOK(_notebook),
1549 GTK_WIDGET(playervbox), playertablabel);
1550
1551 // Player description
1552 GtkWidget *descriptionlabel = gtk_label_new (_("<b>Player description</b>"));
1553 gtk_label_set_use_markup (GTK_LABEL (descriptionlabel), TRUE);
1554 gtk_box_pack_start(GTK_BOX(playervbox), descriptionlabel, FALSE, FALSE, 0);
1555
1556 // Version string
1557 GtkWidget *versionhbox = gtk_hbox_new (FALSE, 2);
1558 gtk_box_pack_start(GTK_BOX(playervbox), versionhbox, FALSE, FALSE, 0);
1559
1560 GtkWidget *versionlabel = gtk_label_new (_("Player version:"));
1561 gtk_misc_set_alignment (GTK_MISC (versionlabel), 0, 0.5);
1562 gtk_box_pack_start(GTK_BOX(versionhbox), versionlabel, FALSE, FALSE, 0);
1563
1564 _prefs->versionText = gtk_entry_new ();
1565 gtk_box_pack_start(GTK_BOX(versionhbox), _prefs->versionText,
1566 FALSE, FALSE, 0);
1567
1568 // Put text in the entry box
1569 gtk_entry_set_text(GTK_ENTRY(_prefs->versionText),
1570 _rcfile.getFlashVersionString().c_str());
1571
1572 // OS label
1573 GtkWidget *oshbox = gtk_hbox_new (FALSE, 2);
1574 gtk_box_pack_start(GTK_BOX(playervbox), oshbox, FALSE, FALSE, 0);
1575
1576 GtkWidget *OSlabel = gtk_label_new (_("Operating system:"));
1577 gtk_misc_set_alignment (GTK_MISC (OSlabel), 0, 0.5);
1578 gtk_box_pack_start(GTK_BOX(oshbox), OSlabel, FALSE, FALSE, 0);
1579
1580 _prefs->osText = gtk_entry_new ();
1581 gtk_box_pack_start(GTK_BOX(oshbox), _prefs->osText, FALSE, FALSE, 0);
1582 // Put text in the entry box
1583 gtk_entry_set_text(GTK_ENTRY(_prefs->osText),
1584 _rcfile.getFlashSystemOS().c_str());
1585
1586 GtkWidget *OSadvicelabel = gtk_label_new (_("<i>If blank, Gnash will "
1587 "detect your OS</i>"));
1588 gtk_label_set_use_markup (GTK_LABEL (OSadvicelabel), TRUE);
1589 gtk_misc_set_alignment (GTK_MISC (OSadvicelabel), 0, 0.5);
1590 gtk_box_pack_start(GTK_BOX(playervbox), OSadvicelabel, FALSE, FALSE, 0);
1591
1592 // URL opener
1593 GtkWidget *urlopenerbox = gtk_hbox_new(FALSE, 2);
1594 gtk_box_pack_start(GTK_BOX(playervbox), urlopenerbox, FALSE, FALSE, 0);
1595
1596 GtkWidget *urlopenerlabel = gtk_label_new (_("URL opener:"));
1597 gtk_misc_set_alignment (GTK_MISC (urlopenerlabel), 0, 0.5);
1598 gtk_box_pack_start(GTK_BOX(urlopenerbox), urlopenerlabel, FALSE, FALSE, 0);
1599
1600 _prefs->urlOpenerText = gtk_entry_new ();
1601 gtk_box_pack_start(GTK_BOX(urlopenerbox), _prefs->urlOpenerText, FALSE,
1602 FALSE, 0);
1603 // Put text in the entry box
1604 gtk_entry_set_text(GTK_ENTRY(_prefs->urlOpenerText),
1605 _rcfile.getURLOpenerFormat().c_str());
1606
1607 // Performance
1608 GtkWidget *performancelabel = gtk_label_new(_("<b>Performance</b>"));
1609 gtk_label_set_use_markup (GTK_LABEL (performancelabel), TRUE);
1610 gtk_box_pack_start(GTK_BOX(playervbox), performancelabel, FALSE, FALSE, 0);
1611
1612 GtkWidget* qualitybox = gtk_hbox_new(FALSE, 2);
1613 gtk_box_pack_start(GTK_BOX(playervbox), qualitybox, FALSE, FALSE, 0);
1614
1615 GtkWidget* qualityoptions = gtk_vbox_new(FALSE, 5);
1616 gtk_box_pack_start(GTK_BOX(qualitybox), qualityoptions, FALSE, FALSE, 0);
1617
1618 // Library size
1619 GtkWidget *libraryhbox = gtk_hbox_new (FALSE, 2);
1620 gtk_box_pack_start(GTK_BOX(playervbox), libraryhbox, FALSE, FALSE, 0);
1621
1622 GtkWidget *librarylabel = gtk_label_new (_("Max size of movie library:"));
1623 gtk_misc_set_alignment (GTK_MISC (librarylabel), 0, 0.5);
1624 gtk_box_pack_start(GTK_BOX(libraryhbox), librarylabel, FALSE, FALSE, 0);
1625
1626 _prefs->librarySize = gtk_spin_button_new_with_range(0, 100, 1);
1627 gtk_box_pack_start(GTK_BOX(libraryhbox), _prefs->librarySize, FALSE,
1628 FALSE, 0);
1629 // Align to _rcfile value:
1630 gtk_spin_button_set_value(GTK_SPIN_BUTTON(_prefs->librarySize),
1631 _rcfile.getMovieLibraryLimit());
1632
1633 { // Scripts timeout -- {
1634
1635 GtkWidget *hbox = gtk_hbox_new (FALSE, 2);
1636 gtk_box_pack_start(GTK_BOX(playervbox), hbox, FALSE, FALSE, 0);
1637
1638 GtkWidget *lbl = gtk_label_new (
1639 _("Max scripts execution time (in seconds):"));
1640 gtk_misc_set_alignment (GTK_MISC (lbl), 0, 0.5);
1641 gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 0);
1642
1643 _prefs->scriptsTimeout = gtk_spin_button_new_with_range(0, 60, 1);
1644 gtk_box_pack_start(GTK_BOX(hbox), _prefs->scriptsTimeout, FALSE,
1645 FALSE, 0);
1646 // Align to _rcfile value:
1647 gtk_spin_button_set_value(GTK_SPIN_BUTTON(_prefs->scriptsTimeout),
1648 _rcfile.getScriptsTimeout());
1649
1650 } // --}
1651
1652 { // Scripts recursion limit -- {
1653
1654 GtkWidget *hbox = gtk_hbox_new (FALSE, 2);
1655 gtk_box_pack_start(GTK_BOX(playervbox), hbox, FALSE, FALSE, 0);
1656
1657 GtkWidget *lbl = gtk_label_new (
1658 _("Max scripts recursion limit (stack depth):"));
1659 gtk_misc_set_alignment (GTK_MISC (lbl), 0, 0.5);
1660 gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 0);
1661
1662 _prefs->scriptsRecursionLimit = gtk_spin_button_new_with_range(0, 1024, 1);
1663 gtk_box_pack_start(GTK_BOX(hbox), _prefs->scriptsRecursionLimit, FALSE,
1664 FALSE, 0);
1665 // Align to _rcfile value:
1666 gtk_spin_button_set_value(GTK_SPIN_BUTTON(_prefs->scriptsRecursionLimit),
1667 _rcfile.getScriptsRecursionLimit());
1668
1669 } // --}
1670
1671 { // Scripts limits lock -- {
1672
1673 _prefs->lockScriptLimitsToggle = gtk_check_button_new_with_mnemonic(
1674 _("Lock script limits so that SWF tags can't override"));
1675 gtk_box_pack_start (GTK_BOX(playervbox), _prefs->lockScriptLimitsToggle,
1676 FALSE, FALSE, 0);
1677 // Align button state with rcfile
1678 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
1679 _prefs->lockScriptLimitsToggle), _rcfile.lockScriptLimits());
1680
1681 } // --}
1682
1683
1684 // Start-stopped toggle
1685 _prefs->startStoppedToggle = gtk_check_button_new_with_mnemonic (
1686 _("Start _Gnash in pause mode"));
1687 gtk_box_pack_start(GTK_BOX(playervbox), _prefs->startStoppedToggle,
1688 FALSE, FALSE, 0);
1689 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(_prefs->startStoppedToggle),
1690 _rcfile.startStopped());
1691 }
1692
1693
1694 } // anonymous namespace
1695
1696
1697 void
showPreferencesDialog()1698 GtkGui::showPreferencesDialog()
1699 {
1700
1701 PreferencesDialog preferencesDialog(_window);
1702 preferencesDialog.show();
1703 }
1704
1705 void
showPropertiesDialog()1706 GtkGui::showPropertiesDialog()
1707 {
1708
1709 GtkWidget *propsDialog = gtk_dialog_new_with_buttons(
1710 _("Movie properties"),
1711 GTK_WINDOW(_window),
1712 // The cast is necessary if there is more
1713 // than one option.
1714 GtkDialogFlags(
1715 GTK_DIALOG_DESTROY_WITH_PARENT),
1716 // Just a 'close' button
1717 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
1718 nullptr);
1719
1720 // Not too small... But I'd rather not have to specify
1721 // a size in pixels.
1722 gtk_window_set_default_size(GTK_WINDOW(propsDialog), 500, 300);
1723
1724 // Suggest to the window manager to allow "maximize"
1725 // As there can be (will be) a lot of data.
1726 gtk_window_set_type_hint(GTK_WINDOW(propsDialog),
1727 GDK_WINDOW_TYPE_HINT_NORMAL);
1728
1729 addGnashIcon(GTK_WINDOW(propsDialog));
1730
1731 // Destroy the window when a button is clicked.
1732 g_signal_connect (propsDialog, "response",
1733 G_CALLBACK(gtk_widget_destroy), nullptr);
1734
1735 GtkWidget *propsvbox = gtk_vbox_new (FALSE, 1);
1736 gtk_container_add(GTK_CONTAINER(
1737 GTK_DIALOG(propsDialog)->vbox), propsvbox);
1738
1739 #ifdef USE_SWFTREE
1740
1741 std::unique_ptr<movie_root::InfoTree> infoptr = getMovieInfo();
1742
1743 GtkWidget *scrollwindow1 = gtk_scrolled_window_new(0, 0);
1744 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwindow1),
1745 GTK_POLICY_AUTOMATIC,
1746 GTK_POLICY_AUTOMATIC);
1747
1748 gtk_box_pack_start(GTK_BOX (propsvbox), scrollwindow1, TRUE, TRUE, 0);
1749
1750 enum
1751 {
1752 STRING1_COLUMN,
1753 STRING2_COLUMN
1754 };
1755
1756 GtkTreeModel *model = makeTreeModel(infoptr);
1757
1758 GtkWidget *treeview = gtk_tree_view_new_with_model (model);
1759
1760 g_object_unref (model);
1761
1762 ///
1763 /// Tree view behaviour.
1764
1765 /// Search on "variable" column
1766 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(treeview), TRUE);
1767 gtk_tree_view_set_search_column (GTK_TREE_VIEW(treeview), 0);
1768
1769 /// Nice shading
1770 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
1771
1772 gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(treeview), TRUE);
1773
1774 // Add columns:
1775
1776 // 'Variable' column:
1777 GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
1778 gtk_tree_view_insert_column_with_attributes(
1779 GTK_TREE_VIEW(treeview),
1780 -1, _("Variable"),
1781 renderer, "text",
1782 STRING1_COLUMN,
1783 nullptr);
1784
1785 // 'Value' column:
1786 // Set to be 'editable' so that the data can be selected and
1787 // copied; it can't actually be edited, though.
1788 renderer = gtk_cell_renderer_text_new ();
1789 g_object_set (renderer, "xalign", 0.0, "editable", TRUE, nullptr);
1790 gtk_tree_view_insert_column_with_attributes(
1791 GTK_TREE_VIEW(treeview),
1792 -1, _("Value"),
1793 renderer, "text",
1794 STRING2_COLUMN,
1795 nullptr);
1796
1797 //Add tree to scrollwindow.
1798 gtk_container_add(GTK_CONTAINER(scrollwindow1), treeview);
1799
1800 #endif
1801
1802 gtk_widget_show_all(propsDialog);
1803
1804 }
1805
1806 // \brief Show info about gnash
1807 void
showAboutDialog()1808 GtkGui::showAboutDialog()
1809 {
1810 const gchar *documentors[] = {
1811 "Rob Savoye",
1812 "Sandro Santilli",
1813 "Ann Barcomb",
1814 nullptr
1815 };
1816
1817 const gchar *artists[] = {
1818 "Jason Savoye",
1819 nullptr
1820 };
1821
1822 const gchar *authors[] = {
1823 "Rob Savoye",
1824 "Sandro Santilli",
1825 "Bastiaan Jacques",
1826 "Tomas Groth",
1827 "Udo Giacomozzi",
1828 "Hannes Mayr",
1829 "Markus Gothe",
1830 "Vitaly Alexeev",
1831 "John Gilmore",
1832 "Zou Lunkai",
1833 "Benjamin Wolsey",
1834 "Russ Nelson",
1835 "Dossy Shiobara",
1836 "Jonathan Crider",
1837 "Ben Limmer",
1838 "Bob Naugle",
1839 "Si Liu",
1840 "Sharad Desai",
1841 nullptr
1842 };
1843
1844 const std::string license =
1845 _("This program is free software; you can redistribute it and/or modify\n"
1846 "it under the terms of the GNU General Public License as published by\n"
1847 "the Free Software Foundation; either version 3 of the License, or\n"
1848 "(at your option) any later version.\n\n"
1849 "This program is distributed in the hope that it will be useful,\n"
1850 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1851 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1852 "GNU General Public License for more details.\n"
1853 "You should have received a copy of the GNU General Public License\n"
1854 "along with this program; if not, write to the Free Software\n"
1855 "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301\n"
1856 "USA or visit http://www.gnu.org/licenses/.");
1857
1858 media::MediaHandler* m = _runResources.mediaHandler();
1859
1860 std::string comments =
1861 _("Gnash is the GNU SWF Player based on GameSWF.");
1862 comments.append(_("\nRenderer: "));
1863 comments.append(_renderer->description());
1864 comments.append(_("\nHardware Acceleration: "));
1865 comments.append(HWACCEL_CONFIG);
1866 comments.append(_("\nGUI: "));
1867 comments.append("GTK2"); // gtk of course!
1868 comments.append(_("\nMedia: "));
1869 comments.append(m ? m->description() : "no media handler");
1870
1871 GdkPixbuf* logo_pixbuf = createPixbuf("GnashG.png");
1872
1873 // gtk-2.8.20 (Debian 4.0) doesn't work fine with
1874 // the gtk_show_about_dialog() call [ omits info ].
1875 // See bug #24426.
1876 GtkWidget* aboutWidget = gtk_about_dialog_new();
1877 addGnashIcon(GTK_WINDOW(aboutWidget));
1878 GtkAboutDialog* about = GTK_ABOUT_DIALOG(aboutWidget);
1879
1880 gtk_about_dialog_set_name (about, "Gnash");
1881 std::string version = VERSION;
1882 version.append("\n");
1883 version.append("(");
1884 version.append(BRANCH_NICK);
1885 version.append("-");
1886 version.append(BRANCH_REVNO);
1887 version.append("-");
1888 version.append(COMMIT_ID);
1889 version.append(")");
1890
1891 gtk_about_dialog_set_version(about, version.c_str());
1892 gtk_about_dialog_set_copyright(about, "Copyright (C) 2005, 2006, 2007, "
1893 "2008, 2009, 2010, 2011, 2012, 2013 The Free Software Foundation");
1894 gtk_about_dialog_set_comments (about, comments.c_str());
1895 gtk_about_dialog_set_authors(about, authors);
1896 gtk_about_dialog_set_documenters(about, documentors);
1897 gtk_about_dialog_set_artists(about, artists);
1898 gtk_about_dialog_set_translator_credits(about, _("translator-credits"));
1899 gtk_about_dialog_set_logo(about, logo_pixbuf);
1900 gtk_about_dialog_set_license(about, license.c_str());
1901 gtk_about_dialog_set_website(about, "http://www.gnu.org/software/gnash/");
1902
1903 // Destroy the dialogue box when 'close' is clicked.
1904 g_signal_connect(aboutWidget, "response",
1905 G_CALLBACK(gtk_widget_destroy), aboutWidget);
1906
1907 gtk_widget_show (aboutWidget);
1908
1909 if (logo_pixbuf) g_object_unref(logo_pixbuf);
1910 }
1911
1912 ///////////////////////////////////////////////////////////////////////////////
1913 ///////////////////////////////////////////////////////////////////////////////
1914 /// ///
1915 /// Menus ///
1916 /// ///
1917 ///////////////////////////////////////////////////////////////////////////////
1918 ///////////////////////////////////////////////////////////////////////////////
1919
1920
1921 // Create a File menu that can be used from the menu bar or the popup.
1922 void
createFileMenu(GtkWidget * obj)1923 GtkGui::createFileMenu(GtkWidget *obj)
1924 {
1925 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic(_("_File"));
1926 gtk_widget_show(menuitem);
1927 gtk_container_add(GTK_CONTAINER(obj), menuitem);
1928
1929 GtkWidget *menu = gtk_menu_new();
1930 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
1931
1932 // Open
1933 GtkWidget *open = gtk_image_menu_item_new_from_stock("gtk-open", 0);
1934 gtk_widget_show(open);
1935 gtk_container_add(GTK_CONTAINER(menu), open);
1936 g_signal_connect(open, "activate", G_CALLBACK(menuOpenFile), this);
1937
1938 // Save
1939 GtkWidget *save = gtk_image_menu_item_new_from_stock("gtk-save", 0);
1940 gtk_widget_show(save);
1941 gtk_container_add(GTK_CONTAINER(menu), save);
1942 // Disabled until save functionality is implemented:
1943 gtk_widget_set_sensitive(save, FALSE);
1944
1945 // Save as
1946 GtkWidget *saveAs = gtk_image_menu_item_new_from_stock("gtk-save-as", 0);
1947 gtk_widget_show(saveAs);
1948 gtk_container_add(GTK_CONTAINER(menu), saveAs);
1949 // Disabled until save-as functionality is implemented:
1950 gtk_widget_set_sensitive(saveAs, FALSE);
1951
1952 GtkWidget *separatormenuitem1 = gtk_separator_menu_item_new();
1953 gtk_widget_show(separatormenuitem1);
1954 gtk_container_add(GTK_CONTAINER(menu), separatormenuitem1);
1955
1956 // Properties
1957 GtkWidget *properties =
1958 gtk_image_menu_item_new_from_stock("gtk-properties", 0);
1959 gtk_widget_show(properties);
1960 gtk_container_add(GTK_CONTAINER(menu), properties);
1961 g_signal_connect(properties, "activate", G_CALLBACK(menuMovieInfo), this);
1962
1963 GtkWidget *separator2 = gtk_separator_menu_item_new();
1964 gtk_widget_show(separator2);
1965 gtk_container_add(GTK_CONTAINER(menu), separator2);
1966
1967 GtkWidget *quit = gtk_image_menu_item_new_from_stock("gtk-quit", 0);
1968 gtk_widget_show(quit);
1969 gtk_container_add(GTK_CONTAINER(menu), quit);
1970 g_signal_connect(quit, "activate", G_CALLBACK(menuQuit), this);
1971 }
1972
1973 // Create an Edit menu that can be used from the menu bar or the popup.
1974 void
createEditMenu(GtkWidget * obj)1975 GtkGui::createEditMenu(GtkWidget *obj)
1976 {
1977
1978 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic(_("_Edit"));
1979 gtk_widget_show(menuitem);
1980 gtk_container_add(GTK_CONTAINER(obj), menuitem);
1981
1982 GtkWidget *menu = gtk_menu_new();
1983 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
1984
1985 GtkWidget *preferences =
1986 gtk_image_menu_item_new_from_stock("gtk-preferences", 0);
1987 gtk_widget_show(preferences);
1988 gtk_container_add(GTK_CONTAINER(menu), preferences);
1989
1990 g_signal_connect(preferences, "activate", G_CALLBACK(menuPreferences),
1991 this);
1992 }
1993
1994 // Create a Help menu that can be used from the menu bar or the popup.
1995 void
createHelpMenu(GtkWidget * obj)1996 GtkGui::createHelpMenu(GtkWidget *obj)
1997 {
1998 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic(_("_Help"));
1999 gtk_widget_show(menuitem);
2000 gtk_container_add(GTK_CONTAINER (obj), menuitem);
2001
2002 GtkWidget *menu = gtk_menu_new();
2003 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
2004
2005 GtkWidget *about = gtk_image_menu_item_new_from_stock("gtk-about", 0);
2006 gtk_widget_show(about);
2007 gtk_container_add(GTK_CONTAINER(menu), about);
2008
2009 g_signal_connect(about, "activate", G_CALLBACK(menuAbout), this);
2010 }
2011
2012
2013 // Create a View menu that can be used from the menu bar or the popup.
2014 void
createViewMenu(GtkWidget * obj)2015 GtkGui::createViewMenu(GtkWidget *obj)
2016 {
2017
2018 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (_("_View"));
2019 gtk_widget_show (menuitem);
2020 gtk_container_add (GTK_CONTAINER (obj), menuitem);
2021
2022 GtkWidget *menu = gtk_menu_new ();
2023 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), menu);
2024
2025 // Refresh
2026 GtkWidget *refresh = gtk_image_menu_item_new_with_label(_("Redraw"));
2027 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(refresh),
2028 gtk_image_new_from_stock("gtk-refresh", GTK_ICON_SIZE_MENU));
2029 gtk_menu_append(menu, refresh);
2030 gtk_widget_show(refresh);
2031 g_signal_connect(refresh, "activate", G_CALLBACK(menuRefreshView), this);
2032
2033 // Fullscreen
2034 #if GTK_CHECK_VERSION(2,8,0)
2035 GtkWidget *fullscreen =
2036 gtk_image_menu_item_new_with_label(_("Toggle fullscreen"));
2037 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(fullscreen),
2038 gtk_image_new_from_stock("gtk-fullscreen", GTK_ICON_SIZE_MENU));
2039 #else
2040 GtkWidget *fullscreen =
2041 gtk_menu_item_new_with_label(_("Toggle fullscreen"));
2042 #endif
2043 gtk_menu_append(menu, fullscreen);
2044 gtk_widget_show(GTK_WIDGET(fullscreen));
2045 g_signal_connect(fullscreen, "activate", G_CALLBACK(menuFullscreen), this);
2046
2047 // Can be disabled at compile time.
2048 #ifndef DISABLE_REGION_UPDATES_DEBUGGING
2049 GtkWidget *updated_regions =
2050 gtk_check_menu_item_new_with_label(_("Show updated ranges"));
2051
2052 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(updated_regions),
2053 showUpdatedRegions());
2054
2055 gtk_menu_append(menu, updated_regions);
2056 gtk_widget_show(updated_regions);
2057 g_signal_connect(updated_regions, "activate",
2058 G_CALLBACK(menuShowUpdatedRegions), this);
2059 #endif
2060
2061 createQualityMenu(menu);
2062
2063 }
2064
2065 // Create a Quality menu that can be used from the View menu
2066 void
createQualityMenu(GtkWidget * obj)2067 GtkGui::createQualityMenu(GtkWidget *obj)
2068 {
2069 GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (_("_Quality"));
2070 gtk_widget_show (menuitem);
2071 gtk_container_add (GTK_CONTAINER (obj), menuitem);
2072
2073 GtkWidget *menu = gtk_menu_new ();
2074 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), menu);
2075
2076 // TODO: use to also show current quality state
2077
2078 // Low
2079 GtkWidget* item = gtk_menu_item_new_with_label(_("Low"));
2080 gtk_menu_append(menu, item);
2081 gtk_widget_show(item);
2082 g_signal_connect(item, "activate", G_CALLBACK(menuQualityLow), this);
2083
2084 // Medium
2085 item = gtk_menu_item_new_with_label(_("Medium"));
2086 gtk_menu_append(menu, item);
2087 gtk_widget_show(item);
2088 g_signal_connect(item, "activate", G_CALLBACK(menuQualityMedium), this);
2089
2090 // High
2091 item = gtk_menu_item_new_with_label(_("High"));
2092 gtk_menu_append(menu, item);
2093 gtk_widget_show(item);
2094 g_signal_connect(item, "activate", G_CALLBACK(menuQualityHigh), this);
2095
2096 // Best
2097 item = gtk_menu_item_new_with_label(_("Best"));
2098 gtk_menu_append(menu, item);
2099 gtk_widget_show(item);
2100 g_signal_connect(item, "activate", G_CALLBACK(menuQualityBest), this);
2101
2102 }
2103
2104 // Create a Control menu that can be used from the menu bar or the popup.
2105 void
createControlMenu(GtkWidget * obj)2106 GtkGui::createControlMenu(GtkWidget *obj)
2107 {
2108
2109 // Movie Control Menu
2110 GtkWidget *control = gtk_menu_item_new_with_mnemonic(_("Movie _Control"));
2111 gtk_widget_show(control);
2112 gtk_container_add(GTK_CONTAINER(obj), control);
2113
2114 GtkWidget *menu = gtk_menu_new();
2115 gtk_menu_item_set_submenu(GTK_MENU_ITEM(control), menu);
2116
2117 // Play
2118 #if GTK_CHECK_VERSION(2,6,0)
2119 GtkWidget *play = gtk_image_menu_item_new_from_stock("gtk-media-play", 0);
2120 #else
2121 GtkWidget *play = gtk_menu_item_new_with_label(_("Play"));
2122 #endif
2123 gtk_menu_append(menu, play);
2124 gtk_widget_show(play);
2125 g_signal_connect (play, "activate", G_CALLBACK(menuPlay), this);
2126
2127 // Pause
2128 #if GTK_CHECK_VERSION(2,6,0)
2129 GtkWidget *pause =
2130 gtk_image_menu_item_new_from_stock ("gtk-media-pause", 0);
2131 #else
2132 GtkWidget *pause = gtk_menu_item_new_with_label(_("Pause"));
2133 #endif
2134 gtk_menu_append(menu, pause);
2135 gtk_widget_show(pause);
2136 g_signal_connect(pause, "activate", G_CALLBACK(menuPause), this);
2137
2138 // Stop
2139 #if GTK_CHECK_VERSION(2,6,0)
2140 GtkWidget *stop = gtk_image_menu_item_new_from_stock("gtk-media-stop", 0);
2141 #else
2142 GtkWidget *stop = gtk_menu_item_new_with_label(_("Stop"));
2143 #endif
2144 gtk_menu_append(menu, stop);
2145 gtk_widget_show(stop);
2146 g_signal_connect(stop, "activate", G_CALLBACK(menuStop), this);
2147
2148 GtkWidget *separator1 = gtk_separator_menu_item_new();
2149 gtk_widget_show(separator1);
2150 gtk_container_add(GTK_CONTAINER(menu), separator1);
2151
2152 // Restart
2153 //
2154 GtkWidget *restart = gtk_image_menu_item_new_with_label(_("Restart Movie"));
2155
2156 // Suitable image?
2157 gtk_menu_append(menu, restart);
2158 gtk_widget_show(restart);
2159 g_signal_connect(restart, "activate", G_CALLBACK(menuRestart), this);
2160
2161 }
2162
2163 // This assumes that the parent of _drawingArea is _window, which
2164 // isn't the case in the plugin fullscreen (it's _overlay). Currently
2165 // we return from fullscreen when Gui::stop() is called, which
2166 // seems like a good idea, and also avoids this problem.
2167 void
stopHook()2168 GtkGui::stopHook()
2169 {
2170
2171 // Assert they're either both initialised or both uninitialised
2172 assert ((_resumeButton && _vbox) || !(_resumeButton || _vbox));
2173 if (_resumeButton) {
2174 gtk_box_pack_start(GTK_BOX(_vbox), _resumeButton, FALSE, FALSE, 0);
2175 }
2176
2177 stopAdvanceTimer();
2178 }
2179
2180 void
playHook()2181 GtkGui::playHook()
2182 {
2183 assert ((_resumeButton && _vbox) || !(_resumeButton || _vbox));
2184 if (_resumeButton) {
2185 gtk_container_remove(GTK_CONTAINER(_vbox), _resumeButton);
2186 }
2187
2188 startAdvanceTimer();
2189 }
2190
2191 // See if the X11 server we're using supports an extension.
2192 bool
checkX11Extension(const std::string & ext)2193 GtkGui::checkX11Extension(const std::string& ext)
2194 {
2195 #ifdef HAVE_X11
2196 #ifndef GDK_DISPLAY
2197 #define GDK_DISPLAY() (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()))
2198 #endif
2199 int n = 0;
2200 char **extlist = XListExtensions(GDK_DISPLAY(), &n);
2201
2202 if (extlist) {
2203 for (int i = 0; i < n; i++) {
2204 if (std::strncmp(ext.c_str(), extlist[i], ext.size()) == 0) {
2205 return true;
2206 }
2207 }
2208 }
2209 #endif /* HAVE_X11 */
2210 // do not free, Xlib can depend on contents being unaltered
2211 return false;
2212 }
2213
2214 bool
yesno(const std::string & question)2215 GtkGui::yesno(const std::string& question)
2216 {
2217 stopAdvanceTimer();
2218 bool ret = true;
2219
2220 GtkWidget *dialog = gtk_message_dialog_new(
2221 GTK_WINDOW(_window),
2222 GTK_DIALOG_MODAL,
2223 GTK_MESSAGE_QUESTION,
2224 GTK_BUTTONS_YES_NO,
2225 "%s", question.c_str());
2226
2227 switch (gtk_dialog_run(GTK_DIALOG(dialog)))
2228 {
2229 case GTK_RESPONSE_YES:
2230 ret = true;
2231 break;
2232 case GTK_RESPONSE_NO:
2233 ret = false;
2234 break;
2235 default:
2236 break;
2237 }
2238
2239 gtk_widget_destroy(dialog);
2240
2241 startAdvanceTimer();
2242
2243 return ret;
2244 }
2245
2246
2247 /// Anonymous namespace for callbacks, local functions, event handlers etc.
2248 namespace {
2249
2250 static GList *pixmaps_directories = nullptr;
2251
2252 // Adds the Gnash icon to a window.
2253 void
addGnashIcon(GtkWindow * window)2254 addGnashIcon(GtkWindow* window)
2255 {
2256 GdkPixbuf *window_icon_pixbuf = createPixbuf ("GnashG.png");
2257 if (window_icon_pixbuf) {
2258 gtk_window_set_icon (GTK_WINDOW (window), window_icon_pixbuf);
2259 g_object_unref (window_icon_pixbuf);
2260 }
2261 }
2262
2263 /* This is an internally used function to create pixmaps. */
2264 GdkPixbuf*
createPixbuf(const gchar * filename)2265 createPixbuf (const gchar *filename)
2266 {
2267 gchar *pathname = nullptr;
2268 GdkPixbuf *pixbuf;
2269 GError *error = nullptr;
2270
2271 if (!filename || !filename[0])
2272 return nullptr;
2273
2274 pathname = findPixmapFile (filename);
2275
2276 if (!pathname) {
2277 log_error (_("Couldn't find pixmap file: %s"), filename);
2278 g_warning(_("Couldn't find pixmap file: %s"), filename);
2279 return nullptr;
2280 }
2281
2282 pixbuf = gdk_pixbuf_new_from_file (pathname, &error);
2283 if (!pixbuf) {
2284 log_error (_("Failed to load pixbuf file: %s: %s"), pathname, error->message);
2285 g_error_free (error);
2286 }
2287 g_free (pathname);
2288 return pixbuf;
2289 }
2290
2291 key::code
gdk_to_gnash_key(guint key)2292 gdk_to_gnash_key(guint key)
2293 {
2294 key::code c(key::INVALID);
2295
2296 // ascii 32-126 in one range:
2297 if (key >= GDK_space && key <= GDK_asciitilde) {
2298 c = (key::code) ((key - GDK_space) + key::SPACE);
2299 }
2300
2301 // Function keys:
2302 else if (key >= GDK_F1 && key <= GDK_F15) {
2303 c = (key::code) ((key - GDK_F1) + key::F1);
2304 }
2305
2306 // Keypad:
2307 else if (key >= GDK_KP_0 && key <= GDK_KP_9) {
2308 c = (key::code) ((key - GDK_KP_0) + key::KP_0);
2309 }
2310
2311 // Extended ascii:
2312 else if (key >= GDK_nobreakspace && key <= GDK_ydiaeresis) {
2313 c = (key::code) ((key - GDK_nobreakspace) +
2314 key::NOBREAKSPACE);
2315 }
2316
2317 // non-character keys don't correlate, so use a look-up table.
2318 else {
2319 struct {
2320 guint gdk;
2321 key::code gs;
2322 } table[] = {
2323 { GDK_BackSpace, key::BACKSPACE },
2324 { GDK_Tab, key::TAB },
2325 { GDK_Clear, key::CLEAR },
2326 { GDK_Return, key::ENTER },
2327
2328 { GDK_Shift_L, key::SHIFT },
2329 { GDK_Shift_R, key::SHIFT },
2330 { GDK_Control_L, key::CONTROL },
2331 { GDK_Control_R, key::CONTROL },
2332 { GDK_Alt_L, key::ALT },
2333 { GDK_Alt_R, key::ALT },
2334 { GDK_Caps_Lock, key::CAPSLOCK },
2335
2336 { GDK_Escape, key::ESCAPE },
2337
2338 { GDK_Page_Down, key::PGDN },
2339 { GDK_Page_Up, key::PGUP },
2340 { GDK_Home, key::HOME },
2341 { GDK_End, key::END },
2342 { GDK_Left, key::LEFT },
2343 { GDK_Up, key::UP },
2344 { GDK_Right, key::RIGHT },
2345 { GDK_Down, key::DOWN },
2346 { GDK_Insert, key::INSERT },
2347 { GDK_Delete, key::DELETEKEY },
2348
2349 { GDK_Help, key::HELP },
2350 { GDK_Num_Lock, key::NUM_LOCK },
2351
2352 { GDK_VoidSymbol, key::INVALID }
2353 };
2354
2355 for (int i = 0; table[i].gdk != GDK_VoidSymbol; i++) {
2356 if (key == table[i].gdk) {
2357 c = table[i].gs;
2358 break;
2359 }
2360 }
2361 }
2362
2363 return c;
2364 }
2365
2366 int
gdk_to_gnash_modifier(int state)2367 gdk_to_gnash_modifier(int state)
2368 {
2369 int modifier = key::GNASH_MOD_NONE;
2370
2371 if (state & GDK_SHIFT_MASK) {
2372 modifier = modifier | key::GNASH_MOD_SHIFT;
2373 }
2374 if (state & GDK_CONTROL_MASK) {
2375 modifier = modifier | key::GNASH_MOD_CONTROL;
2376 }
2377 if (state & GDK_MOD1_MASK) {
2378 modifier = modifier | key::GNASH_MOD_ALT;
2379 }
2380
2381 return modifier;
2382 }
2383
2384 /* Use this function to set the directory containing installed pixmaps. */
2385 void
addPixmapDirectory(const gchar * directory)2386 addPixmapDirectory(const gchar* directory)
2387 {
2388 pixmaps_directories =
2389 g_list_prepend(pixmaps_directories, g_strdup(directory));
2390 }
2391
2392
2393 /* This is an internally used function to find pixmap files. */
2394 gchar*
findPixmapFile(const gchar * filename)2395 findPixmapFile(const gchar* filename)
2396 {
2397 GList *elem;
2398
2399 /* We step through each of the pixmaps directory to find it. */
2400 elem = pixmaps_directories;
2401 while (elem) {
2402 gchar *pathname = g_strdup_printf("%s%s%s", (gchar*)elem->data,
2403 G_DIR_SEPARATOR_S, filename);
2404 if (g_file_test (pathname, G_FILE_TEST_EXISTS))
2405 return pathname;
2406 g_free (pathname);
2407 elem = elem->next;
2408 }
2409 return nullptr;
2410 }
2411
2412
2413 ///////////////////////////////////////////////////////////////////////////////
2414 ///////////////////////////////////////////////////////////////////////////////
2415 /// ///
2416 /// Event Handlers ///
2417 /// ///
2418 ///////////////////////////////////////////////////////////////////////////////
2419 ///////////////////////////////////////////////////////////////////////////////
2420
2421 gboolean
configureEvent(GtkWidget * const,GdkEventConfigure * const event,const gpointer data)2422 configureEvent(GtkWidget *const /*widget*/, GdkEventConfigure *const event,
2423 const gpointer data)
2424 {
2425 GtkGui* obj = static_cast<GtkGui*>(data);
2426 obj->resize_view(event->width, event->height);
2427
2428 return false;
2429 }
2430
2431 gboolean
realizeEvent(GtkWidget *,GdkEvent *,gpointer)2432 realizeEvent(GtkWidget* /*widget*/, GdkEvent* /*event*/, gpointer /*data*/)
2433 {
2434 return true;
2435 }
2436
2437 // Shut everything down and exit when we're destroyed as a window
2438 gboolean
deleteEvent(GtkWidget *,GdkEvent *,gpointer data)2439 deleteEvent(GtkWidget* /*widget*/, GdkEvent* /*event*/, gpointer data)
2440 {
2441 Gui* gui = static_cast<Gui*>(data);
2442 gui->quit();
2443 return true;
2444 }
2445
2446
2447 gboolean
keyPressEvent(GtkWidget * const,GdkEventKey * const event,const gpointer data)2448 keyPressEvent(GtkWidget *const /*widget*/, GdkEventKey *const event,
2449 const gpointer data)
2450 {
2451
2452 Gui* gui = static_cast<Gui*>(data);
2453
2454 /* Forward key event to gnash */
2455 key::code c = gdk_to_gnash_key(event->keyval);
2456 int mod = gdk_to_gnash_modifier(event->state);
2457
2458 if (c != key::INVALID) {
2459 gui->notify_key_event(c, mod, true);
2460 }
2461
2462 return true;
2463 }
2464
2465 gboolean
keyReleaseEvent(GtkWidget * const,GdkEventKey * const event,const gpointer data)2466 keyReleaseEvent(GtkWidget *const /*widget*/, GdkEventKey *const event,
2467 const gpointer data)
2468 {
2469
2470 Gui* gui = static_cast<Gui*>(data);
2471
2472 /* Forward key event to gnash */
2473 key::code c = gdk_to_gnash_key(event->keyval);
2474 int mod = gdk_to_gnash_modifier(event->state);
2475
2476 if (c != key::INVALID) {
2477 gui->notify_key_event(c, mod, false);
2478 }
2479
2480 return true;
2481 }
2482
2483 gboolean
mouseWheelEvent(GtkWidget * const,GdkEventScroll * const event,const gpointer data)2484 mouseWheelEvent(GtkWidget *const /*widget*/, GdkEventScroll* const event,
2485 const gpointer data)
2486 {
2487 assert(event->type == GDK_SCROLL);
2488 GtkGui *obj = static_cast<GtkGui*>(data);
2489
2490 obj->grabFocus();
2491
2492 switch (event->direction) {
2493 case GDK_SCROLL_UP:
2494 obj->notifyMouseWheel(1);
2495 break;
2496 case GDK_SCROLL_DOWN:
2497 obj->notifyMouseWheel(-1);
2498 break;
2499 default:
2500 break;
2501 }
2502
2503
2504 return true;
2505 }
2506
2507 gboolean
buttonPressEvent(GtkWidget * const,GdkEventButton * const event,const gpointer data)2508 buttonPressEvent(GtkWidget *const /*widget*/, GdkEventButton *const event,
2509 const gpointer data)
2510 {
2511
2512 /// Double- and triple-clicks should not send an extra event!
2513 /// Flash has no built-in double click.
2514 if (event->type != GDK_BUTTON_PRESS) return false;
2515
2516 GtkGui *obj = static_cast<GtkGui*>(data);
2517
2518 obj->grabFocus();
2519 obj->notifyMouseClick(true);
2520 return true;
2521 }
2522
2523 gboolean
buttonReleaseEvent(GtkWidget * const,GdkEventButton * const,const gpointer data)2524 buttonReleaseEvent(GtkWidget * const /*widget*/,
2525 GdkEventButton* const /*event*/, const gpointer data)
2526 {
2527 Gui *obj = static_cast<Gui*>(data);
2528 obj->notifyMouseClick(false);
2529 return true;
2530 }
2531
2532 gboolean
motionNotifyEvent(GtkWidget * const,GdkEventMotion * const event,const gpointer data)2533 motionNotifyEvent(GtkWidget *const /*widget*/, GdkEventMotion *const event,
2534 const gpointer data)
2535 {
2536 Gui *obj = static_cast<Gui *>(data);
2537
2538 obj->notifyMouseMove(event->x, event->y);
2539 return true;
2540 }
2541
2542 gboolean
visibilityNotifyEvent(GtkWidget * const,GdkEventVisibility * const event,const gpointer data)2543 visibilityNotifyEvent(GtkWidget *const /*widget*/, GdkEventVisibility *const event,
2544 const gpointer data)
2545 {
2546 GtkGui *obj = static_cast<GtkGui *>(data);
2547
2548 switch (event->state) {
2549 case GDK_VISIBILITY_FULLY_OBSCURED:
2550 obj->setVisible(false);
2551 break;
2552 case GDK_VISIBILITY_PARTIAL:
2553 case GDK_VISIBILITY_UNOBSCURED:
2554 obj->setVisible(true);
2555 break;
2556 }
2557
2558 return false; // propagate the event to other listeners, if any.
2559 }
2560
2561 ///////////////////////////////////////////////////////////////////////////////
2562 ///////////////////////////////////////////////////////////////////////////////
2563 /// ///
2564 /// Callbacks ///
2565 /// ///
2566 ///////////////////////////////////////////////////////////////////////////////
2567 ///////////////////////////////////////////////////////////////////////////////
2568
2569 /// This method is called when the "OK" button is clicked in the open file
2570 /// dialog. For GTK <= 2.4.0, this is a callback called by GTK itself.
2571 void
openFile(GtkWidget * widget,gpointer)2572 openFile(GtkWidget *widget, gpointer /* user_data */)
2573 {
2574 #if 0
2575 // We'll need this when implementing file opening.
2576 GtkGui* gui = static_cast<GtkGui*>(user_data);
2577 #endif
2578
2579 #if GTK_CHECK_VERSION(2,4,0)
2580 char* filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
2581 #else
2582 GtkWidget* file_selector = gtk_widget_get_ancestor(widget,
2583 g_type_from_name("GtkFileSelection"));
2584
2585 GtkFileSelection* filesel = GTK_FILE_SELECTION (file_selector);
2586 const char* filename = gtk_file_selection_get_filename (filesel);
2587 #endif
2588
2589 // FIXME: we want to do something like calling gtk_main_quit here, so
2590 // run() will return. If run() is then changed to return a pointer to the
2591 // next file to be played, then the Player class can play the next file,
2592 // unless run() returns NULL.
2593 log_error(_("Attempting to open file %s.\n"
2594 "NOTE: the file open functionality is not yet implemented!"),
2595 filename);
2596
2597 #if GTK_CHECK_VERSION(2,4,0)
2598 g_free(filename);
2599 #endif
2600 }
2601
2602
2603 void
menuOpenFile(GtkMenuItem *,gpointer data)2604 menuOpenFile(GtkMenuItem* /*menuitem*/, gpointer data)
2605 {
2606 GtkWidget* dialog;
2607 GtkGui* gui = static_cast<GtkGui*>(data);
2608
2609 #if GTK_CHECK_VERSION(2,4,0)
2610 dialog = gtk_file_chooser_dialog_new (_("Open file"),
2611 nullptr,
2612 GTK_FILE_CHOOSER_ACTION_OPEN,
2613 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2614 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
2615 nullptr);
2616
2617 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
2618 openFile(dialog, gui);
2619 }
2620
2621 gtk_widget_destroy (dialog);
2622 #else
2623 dialog = gtk_file_selection_new (_("Open file"));
2624
2625 GtkFileSelection* selector = GTK_FILE_SELECTION(dialog);
2626
2627 g_signal_connect (selector->ok_button, "clicked", G_CALLBACK (openFile),
2628 gui);
2629
2630 g_signal_connect_swapped(selector->ok_button, "clicked",
2631 G_CALLBACK(gtk_widget_destroy), dialog);
2632
2633 g_signal_connect_swapped(selector->cancel_button, "clicked",
2634 G_CALLBACK(gtk_widget_destroy), dialog);
2635
2636 gtk_widget_show (dialog);
2637 #endif // GTK_CHECK_VERSION(2,4,0)
2638 }
2639
2640
2641 /// 'About' callback
2642 void
menuAbout(GtkMenuItem *,gpointer data)2643 menuAbout(GtkMenuItem* /*menuitem*/, gpointer data)
2644 {
2645 GtkGui* gui = static_cast<GtkGui*>(data);
2646 gui->showAboutDialog();
2647 }
2648
2649 /// Preferences callback
2650 void
menuPreferences(GtkMenuItem *,gpointer data)2651 menuPreferences(GtkMenuItem* /*menuitem*/, gpointer data)
2652 {
2653 GtkGui* gui = static_cast<GtkGui*>(data);
2654 gui->showPreferencesDialog();
2655 }
2656
2657 // Properties Callback
2658 void
menuMovieInfo(GtkMenuItem *,gpointer data)2659 menuMovieInfo(GtkMenuItem* /*menuitem*/, gpointer data)
2660 {
2661 GtkGui* gui = static_cast<GtkGui*>(data);
2662 gui->showPropertiesDialog();
2663 }
2664
2665 /// \brief This pops up the menu when the right mouse button is clicked
2666 gint
popupHandler(GtkWidget * widget,GdkEvent * event)2667 popupHandler(GtkWidget *widget, GdkEvent *event)
2668 {
2669 GtkMenu *menu = GTK_MENU(widget);
2670
2671 if( _showMenuState ) {
2672 if (event->type == GDK_BUTTON_PRESS) {
2673 GdkEventButton* event_button =
2674 reinterpret_cast<GdkEventButton*>(event);
2675 if (event_button->button == 3) {
2676 gtk_menu_popup(menu, nullptr, nullptr, nullptr, nullptr,
2677 event_button->button, event_button->time);
2678 return TRUE;
2679 }
2680 }
2681 }
2682
2683 return FALSE;
2684 }
2685
2686 /// \brief This handles the alternative popup for showMenu
2687 gint
popupHandlerAlt(GtkWidget * widget,GdkEvent * event)2688 popupHandlerAlt(GtkWidget *widget, GdkEvent *event)
2689 {
2690 GtkMenu *menu = GTK_MENU(widget);
2691
2692
2693 if( !_showMenuState ) {
2694 if (event->type == GDK_BUTTON_PRESS) {
2695 GdkEventButton* event_button =
2696 reinterpret_cast<GdkEventButton*>(event);
2697 if (event_button->button == 3) {
2698 gtk_menu_popup(menu, nullptr, nullptr, nullptr, nullptr,
2699 event_button->button, event_button->time);
2700 return TRUE;
2701 }
2702 }
2703 }
2704
2705 return FALSE;
2706 }
2707
2708 /// \brief Toggle the sound on or off
2709 void
menuSound(GtkMenuItem *,gpointer data)2710 menuSound(GtkMenuItem* /*menuitem*/, gpointer data)
2711 {
2712 Gui* gui = static_cast<Gui*>(data);
2713 gui->toggleSound();
2714 }
2715
2716 void
menuFullscreen(GtkMenuItem *,gpointer data)2717 menuFullscreen(GtkMenuItem* /*menuitem*/, gpointer data)
2718 {
2719 Gui* gui = static_cast<Gui*>(data);
2720 gui->toggleFullscreen();
2721 }
2722
2723 void
timeoutQuit(gpointer data)2724 timeoutQuit(gpointer data)
2725 {
2726 Gui* gui = static_cast<Gui*>(data);
2727 gui->quit();
2728 }
2729
2730
2731 /// \brief restart the movie from the beginning
2732 void
menuRestart(GtkMenuItem *,gpointer data)2733 menuRestart(GtkMenuItem* /*menuitem*/, gpointer data)
2734 {
2735 Gui* gui = static_cast<Gui*>(data);
2736 gui->restart();
2737 }
2738
2739 void
menuQuit(GtkMenuItem *,gpointer data)2740 menuQuit(GtkMenuItem* /*menuitem*/, gpointer data)
2741 {
2742 Gui* gui = static_cast<Gui*>(data);
2743 gui->quit();
2744 }
2745
2746 /// \brief Start the movie playing from the current frame.
2747 void
menuPlay(GtkMenuItem *,gpointer data)2748 menuPlay(GtkMenuItem* /*menuitem*/, gpointer data)
2749 {
2750 Gui* gui = static_cast<Gui*>(data);
2751 gui->play();
2752 }
2753
2754 /// \brief toggle between playing or paused.
2755 void
menuPause(GtkMenuItem *,gpointer data)2756 menuPause(GtkMenuItem* /*menuitem*/, gpointer data)
2757 {
2758 Gui* gui = static_cast<Gui*>(data);
2759 gui->pause();
2760 }
2761
2762 /// \brief stop the movie that's playing.
2763 void
menuStop(GtkMenuItem *,gpointer data)2764 menuStop(GtkMenuItem* /*menuitem*/, gpointer data)
2765 {
2766 Gui* gui = static_cast<Gui*>(data);
2767 gui->stop();
2768 }
2769
2770
2771 /// \brief Force redraw
2772 void
menuRefreshView(GtkMenuItem *,gpointer data)2773 menuRefreshView(GtkMenuItem* /*menuitem*/, gpointer data)
2774 {
2775 Gui* gui = static_cast<Gui*>(data);
2776 gui->refreshView();
2777 }
2778
2779 /// \brief Force redraw
2780 void
menuShowUpdatedRegions(GtkMenuItem *,gpointer data)2781 menuShowUpdatedRegions(GtkMenuItem* /*menuitem*/, gpointer data)
2782 {
2783 Gui* gui = static_cast<Gui*>(data);
2784 gui->showUpdatedRegions(!gui->showUpdatedRegions());
2785
2786 // refresh to clear the remaining red lines...
2787 if (!gui->showUpdatedRegions()) {
2788 gui->refreshView();
2789 }
2790 }
2791
2792 /// \brief Set quality to LOW level
2793 void
menuQualityLow(GtkMenuItem *,gpointer data)2794 menuQualityLow(GtkMenuItem* /*menuitem*/, gpointer data)
2795 {
2796 Gui* gui = static_cast<Gui*>(data);
2797 gui->setQuality(QUALITY_LOW);
2798 }
2799
2800 /// \brief Set quality to MEDIUM level
2801 void
menuQualityMedium(GtkMenuItem *,gpointer data)2802 menuQualityMedium(GtkMenuItem* /*menuitem*/, gpointer data)
2803 {
2804 Gui* gui = static_cast<Gui*>(data);
2805 gui->setQuality(QUALITY_MEDIUM);
2806 }
2807
2808 /// \brief Set quality to HIGH level
2809 void
menuQualityHigh(GtkMenuItem *,gpointer data)2810 menuQualityHigh(GtkMenuItem* /*menuitem*/, gpointer data)
2811 {
2812 Gui* gui = static_cast<Gui*>(data);
2813 gui->setQuality(QUALITY_HIGH);
2814 }
2815
2816 /// \brief Set quality to BEST level
2817 void
menuQualityBest(GtkMenuItem *,gpointer data)2818 menuQualityBest(GtkMenuItem* /*menuitem*/, gpointer data)
2819 {
2820 Gui* gui = static_cast<Gui*>(data);
2821 gui->setQuality(QUALITY_BEST);
2822 }
2823
2824 } // anonymous namespace
2825
2826 } // end of namespace gnash
2827
2828 // local Variables:
2829 // mode: C++
2830 // indent-tabs-mode: nil
2831 // End:
2832