1 /*
2  * This file is part of bino, a 3D video player.
3  *
4  * Copyright (C) 2010, 2011, 2012, 2013, 2015, 2016
5  * Martin Lambers <marlam@marlam.de>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #ifndef VIDEO_OUTPUT_QT_H
22 #define VIDEO_OUTPUT_QT_H
23 
24 #include "config.h"
25 
26 #include <GL/glew.h>
27 
28 #include <QWidget>
29 #include <QGLWidget>
30 #include <QGLFormat>
31 #include <QTimer>
32 #include <QThread>
33 #include <QMutex>
34 
35 #if HAVE_X11
36 # include <GL/glxew.h>
37 #endif
38 
39 #include "base/pth.h"
40 
41 #include "video_output.h"
42 
43 
44 /* Internal interface */
45 
46 class video_output_qt;
47 class video_output_qt_widget;
48 
49 class gl_thread : public QThread
50 {
51 private:
52     video_output_qt* _vo_qt;
53     video_output_qt_widget* _vo_qt_widget;
54     bool _render;
55     int _w, _h;
56     mutex _wait_mutex;
57     condition _wait_cond;
58     bool _action_activate;
59     bool _action_prepare;
60     bool _action_finished;
61     bool _redisplay;
62     video_frame _next_frame;
63     subtitle_box _next_subtitle;
64     bool _failure;
65     exc _e;
66     // The display frame number
67     int64_t _display_frameno;
68 
69 public:
70     gl_thread(video_output_qt* vo_qt, video_output_qt_widget* vo_qt_widget);
71 
72 #ifdef GLEW_MX
73 # if HAVE_X11
74     GLXEWContext* glxewGetContext() const;
75 # endif
76 #endif
77 
78     void set_render(bool r);
79     void resize(int w, int h);
80     void activate_next_frame();
81     void prepare_next_frame(const video_frame &frame, const subtitle_box &subtitle);
82     void redisplay();
83 
84     int64_t time_to_next_frame_presentation();
85 
86     void run();
87 
failure()88     bool failure() const
89     {
90         return _failure;
91     }
exception()92     const exc& exception() const
93     {
94         return _e;
95     }
96 };
97 
98 class video_output_qt_widget : public QGLWidget
99 {
100     Q_OBJECT
101 private:
102     video_output_qt *_vo;
103     class gl_thread _gl_thread;
104     QTimer _timer;
105     int _width, _height;
106     int _pos_x, _pos_y;
107 
108 private slots:
109     void check_gl_thread();
110 
111 public:
112     video_output_qt_widget(video_output_qt *vo, const QGLFormat &format, QWidget *parent = NULL);
113 
114     int vo_width() const;
115     int vo_height() const;
116     int vo_pos_x() const;
117     int vo_pos_y() const;
118 
119     void start_rendering();
120     void stop_rendering();
121     void redisplay();
gl_thread()122     class gl_thread* gl_thread()
123     {
124         return &_gl_thread;
125     }
126 
127 protected:
128 #ifdef Q_WS_X11
129 # if QT_VERSION < 0x040800
130     /* Work around a bug in Qt < 4.8: On a hide event, the GLWidget calls
131      * makeCurrent() and glFinish(), but this interferes with our GL thread.
132      * This has been fixed in Qt 4.8. */
event(QEvent * e)133     virtual bool event(QEvent* e) { return QWidget::event(e); }
134 # endif
135 #endif
136     virtual void paintEvent(QPaintEvent* event);
137     virtual void resizeEvent(QResizeEvent* event);
138     virtual void keyPressEvent(QKeyEvent *event);
139     virtual void mouseReleaseEvent(QMouseEvent *event);
140     virtual void mouseDoubleClickEvent(QMouseEvent *event);
141     virtual void focusOutEvent(QFocusEvent *event);
142 };
143 
144 /* Public interface */
145 
146 class video_container_widget : public QWidget, public controller
147 {
148     Q_OBJECT
149     int _w, _h;
150     QTimer *_timer;
151 private slots:
152     void playloop_step();
153 public:
154     video_container_widget(QWidget *parent = NULL);
155     void start_timer();
156     void set_recommended_size(int w, int h);
157     void grab_focus();
158 signals:
159 protected:
160     virtual QSize sizeHint() const;
161     virtual void moveEvent(QMoveEvent* event);
162     virtual void closeEvent(QCloseEvent *event);
163     virtual void receive_notification(const notification& note);
164 };
165 
166 /* Public interface. See the video_output documentation. */
167 
168 class video_output_qt : public video_output
169 {
170 private:
171 #ifdef GLEW_MX
172 # if HAVE_X11
173     GLXEWContext _glxew_context;
174 # endif
175     GLEWContext _glew_context;
176 #endif
177     int _screen_width, _screen_height;
178     float _screen_pixel_aspect_ratio;
179     video_container_widget *_container_widget;
180     bool _container_is_external;
181     video_output_qt_widget *_widget;
182     QGLFormat _format;
183     bool _fullscreen;
184     QRect _geom;
185     bool _screensaver_inhibited;
186     bool _recreate_context;
187     bool _recreate_context_stereo;
188 #ifdef Q_OS_MAC
189     unsigned int _disableDisplaySleepAssertion;
190 #endif
191 
192     void create_widget();
193     void mouse_set_pos(float dest);
194     void mouse_toggle_fullscreen();
195     void suspend_screensaver();
196     void resume_screensaver();
197 
198 protected:
199 #ifdef GLEW_MX
200 # if HAVE_X11
201     virtual GLXEWContext* glxewGetContext() const;
202 # endif
203     virtual GLEWContext* glewGetContext() const;
204 #endif
205     virtual bool context_is_stereo() const;
206     virtual void recreate_context(bool stereo);
207     virtual void trigger_resize(int w, int h);
208 
209     virtual int screen_width() const;
210     virtual int screen_height() const;
211     virtual float screen_pixel_aspect_ratio() const;
212     virtual int width() const;
213     virtual int height() const;
214     virtual int pos_x() const;
215     virtual int pos_y() const;
216 
217 public:
218     /* Constructor, Destructor */
219     /* If a container widget is given, then it is assumed that this widget is
220      * part of another widget (e.g. a main window). If no container widget is
221      * given, we will use our own, and it will be a top-level window. */
222     video_output_qt(video_container_widget *container_widget = NULL);
223     virtual ~video_output_qt();
224 
225     virtual void init();
226     virtual int64_t wait_for_subtitle_renderer();
227     virtual void deinit();
228 
229     virtual bool supports_stereo() const;
230 
231     virtual void center();
232     virtual void enter_fullscreen();
233     virtual void exit_fullscreen();
234 
235     virtual void prepare_next_frame(const video_frame &frame, const subtitle_box &subtitle);
236     virtual void activate_next_frame();
237     virtual int64_t time_to_next_frame_presentation() const;
238 
239     virtual void process_events();
240     virtual void receive_notification(const notification& note);
241 
242     friend class gl_thread;
243     friend class video_output_qt_widget;
244 };
245 
246 #endif
247