1 // Qt4Gui.cpp: KDE4/Qt4 Gui implementation for Gnash window
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 <map>
26
27 #include <QMainWindow>
28 #include <QX11Info>
29 #include <QMenu>
30 #include <QMenuBar>
31 #include <QWidget>
32 #include <QCursor>
33 #include <QApplication>
34 #include <QPainter>
35 #include <QMouseEvent>
36 #include <QResizeEvent>
37 #include <QTimer>
38 #include <QEvent>
39 #include <QDialog>
40 #include <QDialogButtonBox>
41 #include <QLayout>
42 #include <QPushButton>
43 #include <QTreeWidget>
44 #include <QTreeWidgetItem>
45 #include <QStack>
46 #include <QTabWidget>
47 #include <QFrame>
48 #include <QLabel>
49 #include <QSlider>
50 #include <QLineEdit>
51 #include <QCheckBox>
52 #include <QLCDNumber>
53 #include <QSpinBox>
54 #include <QClipboard>
55 #include <QString>
56 #include <QDesktopWidget>
57 #include <QMessageBox>
58
59 #include "Range2d.h"
60
61 #include "movie_definition.h"
62 #include "log.h"
63
64 #include "gui.h"
65 #include "Qt4Gui.h"
66 #include "Qt4Gui.moc"
67 #include "Renderer.h"
68 #include "RunResources.h"
69 #include "GnashException.h"
70
71 // Macro for using gettext strings where Qt expects QStrings
72 #define _q(Str) QString::fromUtf8(_(Str))
73
74 extern "C" {
75 #include <X11/Xlib.h>
76 }
77
78 namespace gnash
79 {
80
Qt4Gui(unsigned long xid,float scale,bool loop,RunResources & r)81 Qt4Gui::Qt4Gui(unsigned long xid, float scale, bool loop, RunResources& r)
82 :
83 Gui(xid, scale, loop, r),
84 _numArgs(0),
85 _embedWidget(NULL),
86 _drawingWidget(NULL),
87 _interval(0),
88 _advanceTimer(0)
89 , fileMenu(NULL)
90 , propertiesAction(NULL)
91 , quitAction(NULL)
92 , editMenu(NULL)
93 , preferencesAction(NULL)
94 , movieControlMenu(NULL)
95 , playAction(NULL)
96 , pauseAction(NULL)
97 , stopAction(NULL)
98 , restartAction(NULL)
99 , viewMenu(NULL)
100 , refreshAction(NULL)
101 , fullscreenAction(NULL)
102 {
103 }
104
105
~Qt4Gui()106 Qt4Gui::~Qt4Gui()
107 {
108 }
109
110 void
setClipboard(const std::string & copy)111 Qt4Gui::setClipboard(const std::string& copy)
112 {
113 QClipboard* cb = QApplication::clipboard();
114 assert(cb);
115 cb->setText(QString::fromStdString(copy));
116 }
117
118 bool
init(int,char ** [])119 Qt4Gui::init(int /*argc*/, char ** /*argv*/[])
120 {
121 char** r = NULL;
122
123 _application.reset(new QApplication(_numArgs, r));
124 _window.reset(new QMainWindow());
125 _embedWidget = new EmbedWidget(*this);
126 _drawingWidget = _embedWidget->drawingWidget();
127
128 std::string renderer = _runResources.getRenderBackend();
129
130 if (renderer == "cairo") {
131 #ifdef RENDERER_CAIRO
132 log_debug("Using Cairo renderer");
133 _glue.reset(new Qt4CairoGlue());
134 #else
135 log_error(_("Cairo renderer not supported!"));
136 return false;
137 #endif
138 } else if (renderer == "opengl") {
139 #ifdef RENDERER_OPENGL
140 log_debug("Using OpenGL renderer");
141 _glue.reset(new Qt4OglGlue());
142 #else
143 log_error(_("OpenGL renderer not supported!"));
144 return false;
145 #endif
146 } else if (renderer == "agg") {
147 #ifdef RENDERER_AGG
148 log_debug("Using AGG renderer");
149 _glue.reset(new Qt4AggGlue());
150 #else
151 log_error(_("AGG renderer not supported!"));
152 return false;
153 #endif
154 }
155 else {
156 boost::format fmt = boost::format("Non-existent renderer %1% "
157 "specified") % renderer;
158 throw gnash::GnashException(fmt.str());
159 }
160
161 setupActions();
162 setupMenus();
163
164 if (!_xid) {
165 createMainMenu();
166 }
167
168 // Make sure key events are ready to be passed
169 // before the widget can receive them.
170 setupKeyMap();
171
172 return true;
173 }
174
175 bool
run()176 Qt4Gui::run()
177 {
178 return _application->exec();
179 }
180
181 bool
createWindow(const char * windowtitle,int width,int height,int xPosition,int yPosition)182 Qt4Gui::createWindow(const char* windowtitle, int width, int height,
183 int xPosition, int yPosition)
184 {
185 _width = width;
186 _height = height;
187
188 _drawingWidget->setMinimumSize(_width, _height);
189
190 // Enable receiving of mouse events.
191 _drawingWidget->setMouseTracking(true);
192 _drawingWidget->setFocusPolicy(Qt::StrongFocus);
193 _window->setWindowTitle(windowtitle);
194 _window->setWindowIcon(QIcon(PKGDATADIR"/GnashG.png"));
195
196 if(_xid) {
197 _embedWidget->embedInto(_xid);
198 _embedWidget->show();
199 // Adjust width and height to the window we're being embedded into...
200 XWindowAttributes winAttributes;
201 XGetWindowAttributes(QX11Info::display(), _xid, &winAttributes);
202 _width=winAttributes.width;
203 _height=winAttributes.height;
204 } else {
205 // The QMainWindow takes ownership of the widgets.
206 _window->setCentralWidget(_embedWidget);
207 if (xPosition > -1 || yPosition > -1)
208 _window->move(xPosition, yPosition);
209 _window->show();
210 }
211
212 _glue->prepDrawingArea(_drawingWidget);
213
214 _renderer.reset(_glue->createRenderHandler());
215
216 if (!_renderer.get()) {
217 return false;
218 }
219
220 _validbounds.setTo(0, 0, _width, _height);
221 _glue->initBuffer(_width, _height);
222
223 // log_debug("Setting renderer");
224
225 _runResources.setRenderer(_renderer);
226
227 // log_debug("Set renderer");
228
229 return true;
230 }
231
232
233 void
resizeWindow(int width,int height)234 Qt4Gui::resizeWindow(int width, int height)
235 {
236 _width = width;
237 _height = height;
238
239 _drawingWidget->setMinimumSize(_width, _height);
240 }
241
242 void
popupMenu(const QPoint & point)243 Qt4Gui::popupMenu(const QPoint& point)
244 {
245 QMenu popupMenu(_drawingWidget);
246 popupMenu.addMenu(fileMenu);
247 popupMenu.addMenu(editMenu);
248 popupMenu.addMenu(movieControlMenu);
249 popupMenu.addMenu(viewMenu);
250 popupMenu.exec(point);
251 }
252
253
254 void
renderBuffer()255 Qt4Gui::renderBuffer()
256 {
257
258 for (DrawBounds::const_iterator i = _drawbounds.begin(),
259 e = _drawbounds.end(); i != e; ++i) {
260
261 // it may happen that a particular range is out of the screen, which
262 // will lead to bounds==null.
263 if (i->isNull()) continue;
264
265 assert(i->isFinite());
266
267 _drawingWidget->update(i->getMinX(), i->getMinY(),
268 i->width(), i->height());
269
270 }
271 }
272
273 void
renderWidget(const QRect & updateRect)274 Qt4Gui::renderWidget(const QRect& updateRect)
275 {
276 // This call renders onto the widget using a QPainter,
277 // which *must only happen inside a paint event*.
278 _glue->render(updateRect);
279 }
280
281 void
setInvalidatedRegions(const InvalidatedRanges & ranges)282 Qt4Gui::setInvalidatedRegions(const InvalidatedRanges& ranges)
283 {
284 _renderer->set_invalidated_regions(ranges);
285
286 _drawbounds.clear();
287
288 for (size_t i = 0, e = ranges.size(); i != e; ++i) {
289
290 geometry::Range2d<int> bounds = Intersection(
291 _renderer->world_to_pixel(ranges.getRange(i)),
292 _validbounds);
293
294 // It may happen that a particular range is out of the screen, which
295 // will lead to bounds==null.
296 if (bounds.isNull()) continue;
297
298 assert(bounds.isFinite());
299
300 _drawbounds.push_back(bounds);
301
302 }
303 }
304
305 void
setTimeout(unsigned int timeout)306 Qt4Gui::setTimeout(unsigned int timeout)
307 {
308 // This must go through Gui::quit() to make sure screenshots are
309 // handled if necessary.
310 QTimer::singleShot(timeout, _drawingWidget, SLOT(quit()));
311 }
312
313 void
setInterval(unsigned int interval)314 Qt4Gui::setInterval(unsigned int interval)
315 {
316 _interval = interval;
317 _advanceTimer = _drawingWidget->startTimer(_interval);
318 }
319
320 void
setCursor(gnash_cursor_type newcursor)321 Qt4Gui::setCursor(gnash_cursor_type newcursor)
322 {
323 if (! _mouseShown) return;
324
325 switch (newcursor) {
326 case CURSOR_HAND:
327 _drawingWidget->setCursor(Qt::PointingHandCursor);
328 break;
329 case CURSOR_INPUT:
330 _drawingWidget->setCursor(Qt::IBeamCursor);
331 break;
332 default:
333 _drawingWidget->unsetCursor();
334 }
335 }
336
337 bool
showMouse(bool show)338 Qt4Gui::showMouse(bool show)
339 {
340 bool prevState = _mouseShown;
341 _mouseShown = show;
342
343 if (show) {
344 _drawingWidget->unsetCursor();
345 }
346 else {
347 _drawingWidget->setCursor(Qt::BlankCursor);
348 }
349
350 return prevState;
351 }
352
353 void
setFullscreen()354 Qt4Gui::setFullscreen()
355 {
356 _fullscreen = true;
357 fullscreenAction->setChecked(_fullscreen);
358
359 _embedWidget->setWindowFlags(Qt::Window);
360 _embedWidget->showFullScreen();
361 }
362
363 void
unsetFullscreen()364 Qt4Gui::unsetFullscreen()
365 {
366 _fullscreen = false;
367 fullscreenAction->setChecked(_fullscreen);
368
369 if (_embedWidget->isFullScreen()) {
370 _embedWidget->setWindowFlags(Qt::Widget);
371 _embedWidget->showNormal();
372 if (_xid) {
373 _embedWidget->embedInto(_xid);
374 }
375 }
376 }
377
378 double
getScreenDPI() const379 Qt4Gui::getScreenDPI() const
380 {
381 assert(_drawingWidget);
382 // Should this be logical or physical DPI?
383 return _drawingWidget->logicalDpiX();
384 }
385
386 std::pair<int, int>
screenResolution() const387 Qt4Gui::screenResolution() const
388 {
389 QDesktopWidget* d = QApplication::desktop();
390 assert(d);
391
392 const QRect c = d->screenGeometry();
393 return std::make_pair(c.width(), c.height());
394 }
395
396 gnash::key::code
qtToGnashKey(QKeyEvent * event)397 Qt4Gui::qtToGnashKey(QKeyEvent *event)
398 {
399
400 // This should be initialized by now.
401 assert (!_keyMap.empty());
402
403 // Gnash uses its own keycodes to map key events
404 // to the three sometimes weird and confusing values that flash movies
405 // can refer to. See GnashKey.h for the keycodes and map.
406 //
407 // Gnash's keycodes are gnash::key::code. They are mainly in ascii order.
408 // Standard ascii characters (32-127) have the same value. Extended ascii
409 // characters (160-254) are in ascii order but correspond to
410 // gnash::key::code
411 // 169-263. Non-character values must normally be mapped separately.
412
413 const int key = event->key();
414
415 if (key >= Qt::Key_0 && key <= Qt::Key_9) {
416 return static_cast<gnash::key::code>(
417 key - Qt::Key_0 + gnash::key::_0);
418 }
419
420 // All other characters between ascii 32 and 126 are simple.
421 // From space (32) to slash (47):
422 else if (key >= Qt::Key_Space && key <= Qt::Key_AsciiTilde) {
423 return static_cast<gnash::key::code>(
424 key - Qt::Key_Space + gnash::key::SPACE);
425 }
426
427 // Function keys:
428 else if (key >= Qt::Key_F1 && key <= Qt::Key_F15) {
429 return static_cast<gnash::key::code>(
430 key - Qt::Key_F1 + gnash::key::F1);
431 }
432
433 // Extended ascii from non-breaking (160) space to ÿ (264) is in the same
434 // order.
435 else if (key >= Qt::Key_nobreakspace && key <= Qt::Key_ydiaeresis) {
436 return static_cast<gnash::key::code>(
437 key - Qt::Key_nobreakspace + gnash::key::NOBREAKSPACE);
438 }
439
440 const KeyMap::const_iterator it = _keyMap.find(key);
441
442 if (it == _keyMap.end()) return gnash::key::INVALID;
443
444 return it->second;
445
446 }
447
448 int
qtToGnashModifier(const Qt::KeyboardModifiers modifiers)449 Qt4Gui::qtToGnashModifier(const Qt::KeyboardModifiers modifiers)
450 {
451 int gnashModifier = gnash::key::GNASH_MOD_NONE;
452
453 if (modifiers & Qt::ShiftModifier)
454 gnashModifier = gnashModifier | gnash::key::GNASH_MOD_SHIFT;
455 if (modifiers & Qt::ControlModifier)
456 gnashModifier = gnashModifier | gnash::key::GNASH_MOD_CONTROL;
457 if (modifiers & Qt::AltModifier)
458 gnashModifier = gnashModifier | gnash::key::GNASH_MOD_ALT;
459
460 return gnashModifier;
461 }
462
463 void
handleKeyEvent(QKeyEvent * event,bool down)464 Qt4Gui::handleKeyEvent(QKeyEvent *event, bool down)
465 {
466 gnash::key::code c = qtToGnashKey(event);
467 int mod = qtToGnashModifier(event->modifiers());
468 notify_key_event(c, mod, down);
469 }
470
471 void
resize(int width,int height)472 Qt4Gui::resize(int width, int height)
473 {
474 _glue->resize(width, height);
475 resize_view(width, height);
476 }
477
478 void
showProperties()479 Qt4Gui::showProperties()
480 {
481 QDialog* propsDialog = new QDialog(_drawingWidget);
482 propsDialog->setWindowTitle(_q("Movie properties"));
483 propsDialog->setAttribute(Qt::WA_DeleteOnClose);
484 propsDialog->resize(500, 300);
485
486 QDialogButtonBox *dialogButtons = new QDialogButtonBox(
487 QDialogButtonBox::Close, Qt::Horizontal, propsDialog);
488 dialogButtons->button(QDialogButtonBox::Close)->setDefault(true);
489
490 QVBoxLayout* layout = new QVBoxLayout(propsDialog);
491 propsDialog->connect(dialogButtons->button(QDialogButtonBox::Close),
492 SIGNAL(clicked()), SLOT(close()));
493
494 #ifdef USE_SWFTREE
495 std::unique_ptr<movie_root::InfoTree> infoptr = getMovieInfo();
496 const movie_root::InfoTree& info = *infoptr;
497
498 QTreeWidget *tree = new QTreeWidget();
499 tree->setColumnCount(2);
500 QStringList treeHeader;
501 treeHeader.append(_q("Variable"));
502 treeHeader.append(_q("Value"));
503 tree->setHeaderLabels(treeHeader);
504
505 QList<QTreeWidgetItem *> items;
506
507 int prevDepth = 0;
508 QStack<QTreeWidgetItem*> stack;
509 for (movie_root::InfoTree::iterator i = info.begin(), e = info.end();
510 i != e; ++i) {
511
512 const movie_root::InfoTree::value_type& p = *i;
513
514 QStringList cols;
515 cols.append(p.first.c_str());
516 cols.append(p.second.c_str());
517 QTreeWidgetItem* item = new QTreeWidgetItem(cols);
518
519 int newDepth = info.depth(i);
520
521 if (newDepth == 0) {
522 // Insert top level entries directly into the tree widget.
523 items.append(item);
524 stack.clear();
525 } else {
526 // The position to insert the new row.
527 QTreeWidgetItem* parent = NULL;
528
529 if (newDepth == prevDepth ) {
530 // Pop an extra time if there is a sibling on the stack.
531 int size = stack.size();
532 if (size + 1 > newDepth)
533 stack.pop();
534
535 parent = stack.pop();
536 } else if (newDepth > prevDepth) {
537 parent = stack.pop();
538 } else if (newDepth < prevDepth) {
539 // Pop until the stack has the right depth.
540 int size = stack.size();
541 for (int j = 0; j < (size + 1) - newDepth; ++j) {
542 parent = stack.pop();
543 }
544 }
545
546 parent->addChild(item);
547 stack.push(parent);
548 }
549
550 stack.push(item);
551 prevDepth = newDepth;
552 }
553 tree->insertTopLevelItems(0, items);
554 layout->addWidget(tree);
555
556 #endif // USE_SWFTREE
557 layout->addWidget(dialogButtons);
558
559 propsDialog->show();
560 propsDialog->activateWindow();
561 }
562
563 void
showPreferences()564 Qt4Gui::showPreferences()
565 {
566 Qt4GuiPrefs::PreferencesDialog* prefsDialog = new Qt4GuiPrefs::PreferencesDialog(_drawingWidget);
567
568 prefsDialog->setAttribute(Qt::WA_DeleteOnClose);
569 prefsDialog->show();
570 prefsDialog->raise();
571 prefsDialog->activateWindow();
572 }
573
574 bool
yesno(const std::string & question)575 Qt4Gui::yesno(const std::string& question)
576 {
577 _drawingWidget->killTimer(_advanceTimer);
578
579 QMessageBox* dialog = new QMessageBox(_drawingWidget);
580 dialog->setText(QString::fromStdString(question));
581 dialog->setStandardButtons(QMessageBox::Yes | QMessageBox::No);
582 dialog->setDefaultButton(QMessageBox::Yes);
583 const int ret = dialog->exec();
584
585 _advanceTimer = _drawingWidget->startTimer(_interval);
586
587
588 if (ret == QMessageBox::Yes) return true;
589 return false;
590 }
591
592 void
quitUI()593 Qt4Gui::quitUI()
594 {
595 _application->quit();
596 }
597
598 void
setupActions()599 Qt4Gui::setupActions()
600 {
601
602 // File Menu actions
603 propertiesAction = new QAction(_q("Properties"), _window.get());
604 _drawingWidget->connect(propertiesAction, SIGNAL(triggered()),
605 _drawingWidget, SLOT(properties()));
606
607 quitAction = new QAction(_q("Quit Gnash"), _window.get());
608 // This must go through Gui::quit() to make sure we don't exit
609 // before doing whatever the Gui wants to do on exit.
610 _drawingWidget->connect(quitAction, SIGNAL(triggered()),
611 _drawingWidget, SLOT(quit()));
612
613 // Edit Menu actions
614 preferencesAction = new QAction(_q("Preferences"), _window.get());
615 _drawingWidget->connect(preferencesAction, SIGNAL(triggered()),
616 _drawingWidget, SLOT(preferences()));
617
618 // Movie Control Menu actions
619 playAction = new QAction(_q("Play"), _window.get());
620 _drawingWidget->connect(playAction, SIGNAL(triggered()),
621 _drawingWidget, SLOT(play()));
622
623 pauseAction = new QAction(_q("Pause"), _window.get());
624 _drawingWidget->connect(pauseAction, SIGNAL(triggered()),
625 _drawingWidget, SLOT(pause()));
626
627 stopAction = new QAction(_q("Stop"), _window.get());
628 _drawingWidget->connect(stopAction, SIGNAL(triggered()),
629 _drawingWidget, SLOT(stop()));
630
631 restartAction = new QAction(_q("Restart"), _window.get());
632 _drawingWidget->connect(restartAction, SIGNAL(triggered()),
633 _drawingWidget, SLOT(restart()));
634
635 // View Menu actions
636 refreshAction = new QAction(_q("Refresh"), _window.get());
637 _drawingWidget->connect(refreshAction, SIGNAL(triggered()),
638 _drawingWidget, SLOT(refresh()));
639
640 fullscreenAction = new QAction(_q("Fullscreen"), _window.get());
641 fullscreenAction->setCheckable(true);
642 _drawingWidget->connect(fullscreenAction, SIGNAL(toggled(bool)),
643 _drawingWidget, SLOT(fullscreen(bool)));
644 }
645
646
647 void
setupMenus()648 Qt4Gui::setupMenus()
649 {
650 /// The menus are children of the QMainWindow so that
651 /// they are destroyed on exit. The QMainWindow already has
652 /// ownership of the main QMenuBar.
653
654 // Set up the File menu.
655 fileMenu = new QMenu(_q("File"), _window.get());
656 fileMenu->addAction(propertiesAction);
657 fileMenu->addAction(quitAction);
658
659 // Set up the Edit menu.
660 editMenu = new QMenu(_q("Edit"), _window.get());
661 editMenu->addAction(preferencesAction);
662
663 // Set up the Movie Control menu
664 movieControlMenu = new QMenu(_q("Movie Control"), _window.get());
665 movieControlMenu->addAction(playAction);
666 movieControlMenu->addAction(pauseAction);
667 movieControlMenu->addAction(stopAction);
668 movieControlMenu->addAction(restartAction);
669
670 // Set up the View menu
671 viewMenu = new QMenu(_q("View"), _window.get());
672 viewMenu->addAction(refreshAction);
673 viewMenu->addAction(fullscreenAction);
674 }
675
676
677 void
createMainMenu()678 Qt4Gui::createMainMenu()
679 {
680 std::unique_ptr<QMenuBar> mainMenu(new QMenuBar);
681
682 // Set up the menu bar.
683 mainMenu->addMenu(fileMenu);
684 mainMenu->addMenu(editMenu);
685 mainMenu->addMenu(movieControlMenu);
686 mainMenu->addMenu(viewMenu);
687
688 // The QMainWindow::setMenuBar transfers ownership
689 // of the QMenuBar.
690 _window->setMenuBar(mainMenu.release());
691
692 }
693
694 void
setupKeyMap()695 Qt4Gui::setupKeyMap()
696 {
697 // We only want to do this once, although it would not
698 // be harmful to do it more.
699 assert (_keyMap.empty());
700
701 _keyMap = {
702 {Qt::Key_Backspace, gnash::key::BACKSPACE},
703 {Qt::Key_Tab, gnash::key::TAB},
704 {Qt::Key_Clear, gnash::key::CLEAR},
705 {Qt::Key_Return, gnash::key::ENTER},
706 {Qt::Key_Enter, gnash::key::ENTER},
707 {Qt::Key_Shift, gnash::key::SHIFT},
708 {Qt::Key_Control, gnash::key::CONTROL},
709 {Qt::Key_Alt, gnash::key::ALT},
710 {Qt::Key_CapsLock, gnash::key::CAPSLOCK},
711 {Qt::Key_Escape, gnash::key::ESCAPE},
712 {Qt::Key_Space, gnash::key::SPACE},
713 {Qt::Key_PageDown, gnash::key::PGDN},
714 {Qt::Key_PageUp, gnash::key::PGUP},
715 {Qt::Key_Home, gnash::key::HOME},
716 {Qt::Key_End, gnash::key::END},
717 {Qt::Key_Left, gnash::key::LEFT},
718 {Qt::Key_Up, gnash::key::UP},
719 {Qt::Key_Right, gnash::key::RIGHT},
720 {Qt::Key_Down, gnash::key::DOWN},
721 {Qt::Key_Insert, gnash::key::INSERT},
722 {Qt::Key_Delete, gnash::key::DELETEKEY},
723 {Qt::Key_Help, gnash::key::HELP},
724 {Qt::Key_NumLock, gnash::key::NUM_LOCK},
725 {Qt::Key_Semicolon, gnash::key::SEMICOLON},
726 {Qt::Key_Equal, gnash::key::EQUALS},
727 {Qt::Key_Minus, gnash::key::MINUS},
728 {Qt::Key_Slash, gnash::key::SLASH},
729 {Qt::Key_BracketLeft, gnash::key::LEFT_BRACKET},
730 {Qt::Key_Backslash, gnash::key::BACKSLASH},
731 {Qt::Key_BracketRight, gnash::key::RIGHT_BRACKET},
732 {Qt::Key_QuoteDbl, gnash::key::DOUBLE_QUOTE} };
733 }
734
735 void
playHook()736 Qt4Gui::playHook()
737 {
738 _embedWidget->hidePlayButton();
739 }
740
741 void
stopHook()742 Qt4Gui::stopHook()
743 {
744 _embedWidget->showPlayButton();
745 }
746
747 /// EmbedWidget implementation
748
EmbedWidget(Qt4Gui & gui)749 EmbedWidget::EmbedWidget(Qt4Gui& gui)
750 : QX11EmbedWidget()
751 {
752 _drawingWidget = new DrawingWidget(gui);
753 _playButton = new QPushButton(_q("Click to Play"), this);
754
755 QVBoxLayout* layout = new QVBoxLayout(this);
756 layout->setContentsMargins(0,0,0,0);
757 layout->setSpacing(0);
758 layout->addWidget(_playButton);
759 layout->addWidget(_drawingWidget);
760 _playButton->hide();
761
762 connect(_playButton, SIGNAL(clicked()), this, SLOT(hidePlayButton()));
763 connect(_playButton, SIGNAL(clicked()), _drawingWidget, SLOT(play()));
764 }
765
766 void
hidePlayButton()767 EmbedWidget::hidePlayButton()
768 {
769 _playButton->hide();
770 }
771
772 void
showPlayButton()773 EmbedWidget::showPlayButton()
774 {
775 _playButton->show();
776 }
777
778 namespace Qt4GuiPrefs {
779
PreferencesDialog(QWidget * parent)780 PreferencesDialog::PreferencesDialog(QWidget* parent)
781 :
782 QDialog(parent),
783 _rcfile(RcInitFile::getDefaultInstance())
784 {
785 setWindowTitle(_q("Gnash preferences"));
786 setAttribute(Qt::WA_DeleteOnClose);
787
788 QDialogButtonBox *buttons = new QDialogButtonBox(
789 QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
790
791 QVBoxLayout *vLayout = new QVBoxLayout(this);
792
793 QLabel* tmpLabel;
794
795 // Make notebook pages.
796 QTabWidget *tabs = new QTabWidget;
797
798 // Logging tab
799 QFrame* loggingTab = new QFrame();
800 tabs->addTab(loggingTab, _q("Logging"));
801 QVBoxLayout* layout = new QVBoxLayout (loggingTab);
802
803 tmpLabel = new QLabel(_q("<b>Logging options</b>"), loggingTab);
804 layout->addWidget(tmpLabel);
805
806 tmpLabel = new QLabel(_q("Verbosity level"), loggingTab);
807 layout->addWidget(tmpLabel);
808
809 QLCDNumber* lcd = new QLCDNumber(loggingTab);
810 lcd->display(_rcfile.verbosityLevel());
811 lcd->setNumDigits(2);
812 layout->addWidget(lcd);
813
814 _verbositySlider = new QSlider(loggingTab);
815 _verbositySlider->setOrientation(Qt::Horizontal);
816 _verbositySlider->setMaximum(10);
817 _verbositySlider->setSingleStep(1);
818 _verbositySlider->setPageStep(1);
819 _verbositySlider->setValue(_rcfile.verbosityLevel());
820 connect(_verbositySlider, SIGNAL(valueChanged(int)),
821 lcd, SLOT(display(int)));
822 layout->addWidget(_verbositySlider);
823
824 _logToFileToggle = new QCheckBox(_q("Log to file"), loggingTab);
825 _logToFileToggle->setChecked(_rcfile.useWriteLog());
826 layout->addWidget(_logToFileToggle);
827
828 _logFileName = new QLineEdit(_rcfile.getDebugLog().c_str(), loggingTab);
829 layout->addWidget(_logFileName);
830
831 _parserDumpToggle = new QCheckBox(_q("Log parser output"), loggingTab);
832 _parserDumpToggle->setChecked(_rcfile.useParserDump());
833 layout->addWidget(_parserDumpToggle);
834
835 _actionDumpToggle = new QCheckBox(_q("Log SWF actions"), loggingTab);
836 _actionDumpToggle->setChecked(_rcfile.useActionDump());
837 layout->addWidget(_actionDumpToggle);
838
839 _malformedSWFToggle = new QCheckBox(_q("Log malformed SWF errors"),
840 loggingTab);
841 _malformedSWFToggle->setChecked(_rcfile.showMalformedSWFErrors());
842 layout->addWidget(_malformedSWFToggle);
843
844 _ASCodingErrorToggle = new QCheckBox(_q("Log ActionScript coding errors"),
845 loggingTab);
846 _ASCodingErrorToggle->setChecked(_rcfile.showASCodingErrors());
847 layout->addWidget(_ASCodingErrorToggle);
848
849 // Security tab
850 QFrame* securityTab = new QFrame(tabs);
851 tabs->addTab(securityTab, _q("Security"));
852 layout = new QVBoxLayout (securityTab);
853
854 tmpLabel = new QLabel(_q("<b>Network connections</b>"), securityTab);
855 layout->addWidget(tmpLabel);
856
857 _localHostToggle = new QCheckBox(_q("Connect only to local host"),
858 securityTab);
859 _localHostToggle->setChecked(_rcfile.useLocalHost());
860 layout->addWidget(_localHostToggle);
861
862 _localDomainToggle = new QCheckBox(_q("Connect only to local domain"),
863 securityTab);
864 _localDomainToggle->setChecked(_rcfile.useLocalDomain());
865 layout->addWidget(_localDomainToggle);
866
867 _insecureSSLToggle = new QCheckBox(_q("Disable SSL verification"),
868 securityTab);
869 _insecureSSLToggle->setChecked(_rcfile.insecureSSL());
870 layout->addWidget(_insecureSSLToggle);
871
872 tmpLabel = new QLabel(_q("<b>Privacy</b>"), securityTab);
873 layout->addWidget(tmpLabel);
874
875 tmpLabel = new QLabel(_q("Shared objects directory:"), securityTab);
876 layout->addWidget(tmpLabel);
877 _solSandboxDir = new QLineEdit(_rcfile.getSOLSafeDir().c_str(),
878 securityTab);
879 layout->addWidget(_solSandboxDir);
880
881 _solReadOnlyToggle = new QCheckBox(_q("Do not write Shared Object files"),
882 securityTab);
883 _solReadOnlyToggle->setChecked(_rcfile.getSOLReadOnly());
884 layout->addWidget(_solReadOnlyToggle);
885
886 _solLocalDomainToggle = new QCheckBox(
887 _q("Only access local Shared Object files"), securityTab);
888 _solLocalDomainToggle->setChecked(_rcfile.getSOLLocalDomain());
889 layout->addWidget(_solLocalDomainToggle);
890
891 _localConnectionToggle = new QCheckBox(
892 _q("Disable Local Connection object"), securityTab);
893 _localConnectionToggle->setChecked(_rcfile.getLocalConnection());
894 layout->addWidget(_localConnectionToggle);
895 layout->addStretch();
896
897 // Network tab
898 QFrame* networkTab = new QFrame(tabs);
899 tabs->addTab(networkTab, _q("Network"));
900 layout = new QVBoxLayout (networkTab);
901
902 tmpLabel = new QLabel(_q("<b>Network preferences</b>"), networkTab);
903 layout->addWidget(tmpLabel);
904
905 tmpLabel = new QLabel(_q("Network timeout in seconds"), networkTab);
906 layout->addWidget(tmpLabel);
907
908 _streamsTimeoutScale = new QSpinBox(networkTab);
909 _streamsTimeoutScale->setMinimum(0);
910 _streamsTimeoutScale->setMaximum(300);
911 _streamsTimeoutScale->setValue(_rcfile.getStreamsTimeout());
912 layout->addWidget(_streamsTimeoutScale);
913 layout->addStretch();
914
915 // Network tab
916 QFrame* mediaTab = new QFrame(tabs);
917 tabs->addTab(mediaTab, _q("Media"));
918 layout = new QVBoxLayout (mediaTab);
919
920 tmpLabel = new QLabel(_q("<b>Sound</b>"), mediaTab);
921 layout->addWidget(tmpLabel);
922
923 _soundToggle = new QCheckBox(_q("Use sound handler"), mediaTab);
924 _soundToggle->setChecked(_rcfile.useSound());
925 layout->addWidget(_soundToggle);
926
927 _saveStreamingMediaToggle = new QCheckBox(_q("Save media streams to disk"),
928 mediaTab);
929 _saveStreamingMediaToggle->setChecked(_rcfile.saveStreamingMedia());
930 layout->addWidget(_saveStreamingMediaToggle);
931
932 _saveLoadedMediaToggle = new QCheckBox(
933 _q("Save dynamically loaded media to disk"), mediaTab);
934 _saveLoadedMediaToggle->setChecked(_rcfile.saveLoadedMedia());
935 layout->addWidget(_saveLoadedMediaToggle);
936
937 tmpLabel = new QLabel(_q("Saved media directory:"), mediaTab);
938 layout->addWidget(tmpLabel);
939
940 _mediaDir = new QLineEdit(_rcfile.getMediaDir().c_str(), mediaTab);
941 layout->addWidget(_mediaDir);
942 layout->addStretch();
943
944 // Player tab
945 QFrame* playerTab = new QFrame(tabs);
946 tabs->addTab(playerTab, _q("Player"));
947 layout = new QVBoxLayout (playerTab);
948
949 tmpLabel = new QLabel(_q("<b>Player description</b>"), playerTab);
950 layout->addWidget(tmpLabel);
951
952 tmpLabel = new QLabel(_q("Player version:"), playerTab);
953 layout->addWidget(tmpLabel);
954 _versionText = new QLineEdit(_rcfile.getFlashVersionString().c_str(),
955 playerTab);
956 layout->addWidget(_versionText);
957
958 tmpLabel = new QLabel(_q("Operating system:"), playerTab);
959 layout->addWidget(tmpLabel);
960
961 _osText = new QLineEdit(playerTab);
962 if (_rcfile.getFlashSystemOS().empty()) {
963 _osText->setText(_q("<Autodetect>"));
964 } else {
965 _osText->setText(_rcfile.getFlashSystemOS().c_str());
966 }
967 layout->addWidget(_osText);
968
969 tmpLabel = new QLabel(_q("URL opener:"), playerTab);
970 layout->addWidget(tmpLabel);
971
972 _urlOpenerText = new QLineEdit(_rcfile.getURLOpenerFormat().c_str(),
973 playerTab);
974 layout->addWidget(_urlOpenerText);
975
976 tmpLabel = new QLabel(_q("<b>Performance</b>"), playerTab);
977 layout->addWidget(tmpLabel);
978
979 tmpLabel = new QLabel(_q("Max size of movie library:"), playerTab);
980 layout->addWidget(tmpLabel);
981
982 _librarySize = new QSpinBox(playerTab);
983 _librarySize->setMinimum(0);
984 _librarySize->setMaximum(100);
985 _librarySize->setValue(_rcfile.getMovieLibraryLimit());
986 layout->addWidget(_librarySize);
987
988 _startStoppedToggle = new QCheckBox(_q("Start Gnash in pause mode"),
989 playerTab);
990 _startStoppedToggle->setChecked(_rcfile.startStopped());
991 layout->addWidget(_startStoppedToggle);
992 layout->addStretch();
993 // End of notebook tabs
994
995 vLayout->addWidget(tabs);
996 vLayout->addStretch();
997 vLayout->addWidget(buttons);
998
999 // Connect the dialog buttons.
1000 connect(buttons, SIGNAL(accepted()), this, SLOT(savePreferences()));
1001 connect(buttons, SIGNAL(rejected()), this, SLOT(reject()));
1002 }
1003
1004 void
savePreferences()1005 PreferencesDialog::savePreferences()
1006 {
1007 // Logging tab widgets
1008 _rcfile.verbosityLevel(_verbositySlider->value());
1009 _rcfile.useWriteLog(_logToFileToggle->isChecked());
1010 _rcfile.setDebugLog(_logFileName->text().toStdString());
1011 _rcfile.useParserDump(_parserDumpToggle->isChecked());
1012 _rcfile.useActionDump(_actionDumpToggle->isChecked());
1013 _rcfile.showMalformedSWFErrors(_malformedSWFToggle->isChecked());
1014 _rcfile.showASCodingErrors(_ASCodingErrorToggle->isChecked());
1015
1016 // Security tab widgets
1017 _rcfile.useLocalHost(_localHostToggle->isChecked());
1018 _rcfile.useLocalDomain(_localDomainToggle->isChecked());
1019 _rcfile.insecureSSL(_insecureSSLToggle->isChecked());
1020 _rcfile.setSOLSafeDir(_solSandboxDir->text().toStdString());
1021 _rcfile.setSOLReadOnly(_solReadOnlyToggle->isChecked());
1022 _rcfile.setSOLLocalDomain(_solLocalDomainToggle->isChecked());
1023 _rcfile.setLocalConnection(_localConnectionToggle->isChecked());
1024
1025 // Network tab widgets
1026 _rcfile.setStreamsTimeout(_streamsTimeoutScale->value());
1027
1028 // Media tab widgets
1029 _rcfile.useSound(_soundToggle->isChecked());
1030 _rcfile.saveStreamingMedia(_saveStreamingMediaToggle->isChecked());
1031 _rcfile.saveLoadedMedia(_saveLoadedMediaToggle->isChecked());
1032 _rcfile.setMediaDir(_mediaDir->text().toStdString());
1033
1034 // Player tab widgets
1035 _rcfile.setFlashVersionString(_versionText->text().toStdString());
1036 if (_osText->text() != _q("<Autodetect>")) {
1037 _rcfile.setFlashSystemOS(_osText->text().toStdString());
1038 }
1039 _rcfile.setURLOpenerFormat(_urlOpenerText->text().toStdString());
1040 _rcfile.setMovieLibraryLimit(_librarySize->value());
1041 _rcfile.startStopped(_startStoppedToggle->isChecked());
1042
1043 // Save the file.
1044 _rcfile.updateFile();
1045
1046 // Allow the dialog to close normally.
1047 emit accept();
1048 }
1049
1050 } // End of Qt4GuiPrefs namespace
1051
1052 }
1053
1054