Commit b94873cf authored by Stepan Salenikovich's avatar Stepan Salenikovich

gnome: fix clutter fullscreen issues

Seems to fix the ocasional image "corruption"
which happens when the video is put into fullscreen
by creating a new VideoWidget in the fullscreen
window and pausing rendering in the VideoWidget of
the main window, instead of moving the VideoWidget.

Refs #74096

Change-Id: Iae87f815545065cf8a799bfa50dd9865a0b8f26e
parent a448f607
......@@ -205,6 +205,8 @@ SET( SRC_FILES
src/utils/calling.cpp
src/ringnotify.h
src/ringnotify.cpp
src/video/videowindow.h
src/video/videowindow.cpp
)
# compile glib resource files to c code
......
......@@ -43,6 +43,7 @@
#include <media/text.h>
#include <media/textrecording.h>
#include "models/gtkqtreemodel.h"
#include "video/videowindow.h"
struct _CurrentCallView
{
......@@ -70,6 +71,7 @@ struct _CurrentCallViewPrivate
GtkWidget *button_chat_input;
GtkWidget *entry_chat_input;
GtkWidget *scrolledwindow_chat;
GtkWidget *fullscreen_window;
Call *call;
......@@ -101,6 +103,11 @@ current_call_view_dispose(GObject *object)
QObject::disconnect(priv->media_added_connection);
QObject::disconnect(priv->new_message_connection);
if (priv->fullscreen_window) {
gtk_widget_destroy(priv->fullscreen_window);
priv->fullscreen_window = NULL;
}
G_OBJECT_CLASS(current_call_view_parent_class)->dispose(object);
}
......@@ -209,32 +216,15 @@ update_details(CurrentCallView *view, Call *call)
}
static void
fullscreen_destroy(CurrentCallView *view)
on_fullscreen_destroy(CurrentCallView *view)
{
g_return_if_fail(IS_CURRENT_CALL_VIEW(view));
CurrentCallViewPrivate *priv = CURRENT_CALL_VIEW_GET_PRIVATE(view);
/* check if the video widgets parent is the the fullscreen window */
GtkWidget *parent = gtk_widget_get_parent(priv->video_widget);
if (parent != NULL && parent != priv->frame_video) {
/* put the videw widget back in the call view */
g_object_ref(priv->video_widget);
gtk_container_remove(GTK_CONTAINER(parent), priv->video_widget);
gtk_container_add(GTK_CONTAINER(priv->frame_video), priv->video_widget);
g_object_unref(priv->video_widget);
/* destroy the fullscreen window */
gtk_widget_destroy(parent);
}
}
static gboolean
fullscreen_handle_keys(GtkWidget *self, GdkEventKey *event, G_GNUC_UNUSED gpointer user_data)
{
if (event->keyval == GDK_KEY_Escape)
gtk_widget_destroy(self);
/* the event has been fully handled */
return TRUE;
/* fullscreen is being destroyed, clear the pointer and un-pause the rendering
* in this window */
priv->fullscreen_window = NULL;
video_widget_pause_rendering(VIDEO_WIDGET(priv->video_widget), FALSE);
}
static gboolean
......@@ -246,29 +236,26 @@ on_button_press_in_video_event(GtkWidget *self, GdkEventButton *event, CurrentCa
/* on double click */
if (event->type == GDK_2BUTTON_PRESS) {
if (priv->fullscreen_window) {
/* destroy the fullscreen */
gtk_widget_destroy(priv->fullscreen_window);
} else {
/* pause rendering in this window and create fullscreen */
video_widget_pause_rendering(VIDEO_WIDGET(priv->video_widget), TRUE);
priv->fullscreen_window = video_window_new(priv->call,
GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view))));
/* connect to destruction of fullscreen so we know when to un-pause
* the rendering in thiw window */
g_signal_connect_swapped(priv->fullscreen_window,
"destroy",
G_CALLBACK(on_fullscreen_destroy),
view);
/* get the parent to check if its in fullscreen window or not */
GtkWidget *parent = gtk_widget_get_parent(GTK_WIDGET(self));
if (parent == priv->frame_video){
/* not fullscreen, so put it in a separate widget and make it so */
GtkWidget *fullscreen_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_decorated(GTK_WINDOW(fullscreen_window), FALSE);
gtk_window_set_transient_for(GTK_WINDOW(fullscreen_window),
GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view))));
g_object_ref(self);
gtk_container_remove(GTK_CONTAINER(priv->frame_video), self);
gtk_container_add(GTK_CONTAINER(fullscreen_window), self);
g_object_unref(self);
/* connect signals to make sure we can un-fullscreen */
g_signal_connect_swapped(fullscreen_window, "destroy", G_CALLBACK(fullscreen_destroy), view);
g_signal_connect(view, "destroy", G_CALLBACK(fullscreen_destroy), NULL);
g_signal_connect(fullscreen_window, "key_press_event", G_CALLBACK(fullscreen_handle_keys), NULL);
/* present the fullscreen widnow */
gtk_window_present(GTK_WINDOW(fullscreen_window));
gtk_window_fullscreen(GTK_WINDOW(fullscreen_window));
} else {
/* put it back in the call view */
fullscreen_destroy(view);
gtk_window_present(GTK_WINDOW(priv->fullscreen_window));
gtk_window_fullscreen(GTK_WINDOW(priv->fullscreen_window));
}
}
......
......@@ -32,7 +32,8 @@
#define _CURRENTCALLVIEW_H
#include <gtk/gtk.h>
#include <call.h>
class QModelIndex;
G_BEGIN_DECLS
......@@ -52,4 +53,4 @@ void current_call_view_set_call_info (CurrentCallView *view, const QModelI
G_END_DECLS
#endif /* _CURRENTCALLVIEW_H */
\ No newline at end of file
#endif /* _CURRENTCALLVIEW_H */
......@@ -98,6 +98,7 @@ struct _VideoWidgetRenderer {
* this will be set back to false once the black frame is rendered
*/
std::atomic_bool show_black_frame;
std::atomic_bool pause_rendering;
QMetaObject::Connection frame_update;
QMetaObject::Connection render_stop;
QMetaObject::Connection render_start;
......@@ -411,6 +412,9 @@ clutter_render_image(VideoWidgetRenderer* wg_renderer)
auto actor = wg_renderer->actor;
g_return_if_fail(CLUTTER_IS_ACTOR(actor));
if (wg_renderer->pause_rendering)
return;
if (wg_renderer->show_black_frame) {
/* render a black frame set the bool back to false, this is likely done
* when the renderer is stopped so we ignore whether or not it is running
......@@ -671,3 +675,13 @@ video_widget_push_new_renderer(VideoWidget *self, Video::Renderer *renderer, Vid
g_async_queue_push(priv->new_renderer_queue, new_video_renderer);
}
void
video_widget_pause_rendering(VideoWidget *self, gboolean pause)
{
g_return_if_fail(IS_VIDEO_WIDGET(self));
VideoWidgetPrivate *priv = VIDEO_WIDGET_GET_PRIVATE(self);
priv->local->pause_rendering = pause;
priv->remote->pause_rendering = pause;
}
......@@ -55,6 +55,7 @@ typedef enum {
GType video_widget_get_type (void) G_GNUC_CONST;
GtkWidget* video_widget_new (void);
void video_widget_push_new_renderer (VideoWidget *, Video::Renderer *, VideoRendererType);
void video_widget_pause_rendering (VideoWidget *self, gboolean pause);
G_END_DECLS
......
/*
* Copyright (C) 2015 Savoir-Faire Linux Inc.
* Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Additional permission under GNU GPL version 3 section 7:
*
* If you modify this program, or any covered work, by linking or
* combining it with the OpenSSL project's OpenSSL library (or a
* modified version of that library), containing parts covered by the
* terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
* grants you additional permission to convey the resulting work.
* Corresponding Source for a non-source form of such a combination
* shall include the source code for the parts of OpenSSL used as well
* as that of the covered work.
*/
#include "videowindow.h"
#include <gtk/gtk.h>
#include <call.h>
#include "video_widget.h"
#include <video/previewmanager.h>
struct _VideoWindow
{
GtkWindow parent;
};
struct _VideoWindowClass
{
GtkWindowClass parent_class;
};
typedef struct _VideoWindowPrivate VideoWindowPrivate;
struct _VideoWindowPrivate
{
GtkWidget *video_widget;
QMetaObject::Connection local_renderer_connection;
QMetaObject::Connection remote_renderer_connection;
};
G_DEFINE_TYPE_WITH_PRIVATE(VideoWindow, video_window, GTK_TYPE_WINDOW);
#define VIDEO_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), VIDEO_WINDOW_TYPE, VideoWindowPrivate))
static void
video_window_dispose(GObject *object)
{
VideoWindow *self;
VideoWindowPrivate *priv;
self = VIDEO_WINDOW(object);
priv = VIDEO_WINDOW_GET_PRIVATE(self);
QObject::disconnect(priv->local_renderer_connection);
QObject::disconnect(priv->remote_renderer_connection);
G_OBJECT_CLASS(video_window_parent_class)->dispose(object);
}
static gboolean
handle_keys(GtkWidget *self, GdkEventKey *event, G_GNUC_UNUSED gpointer user_data)
{
if (event->keyval == GDK_KEY_Escape) {
gtk_widget_destroy(self);
/* the event has been fully handled */
return TRUE;
}
return FALSE;
}
static gboolean
handle_button_press(GtkWidget *widget, GdkEventButton *event, VideoWindow *self)
{
g_return_val_if_fail(IS_VIDEO_WIDGET(widget), FALSE);
g_return_val_if_fail(IS_VIDEO_WINDOW(self), FALSE);
/* on double click */
if (event->type == GDK_2BUTTON_PRESS) {
gtk_widget_destroy(GTK_WIDGET(self));
/* the event has been fully handled */
return TRUE;
}
return FALSE;
}
static void
video_window_init(VideoWindow *self)
{
VideoWindowPrivate *priv = VIDEO_WINDOW_GET_PRIVATE(self);
gtk_window_set_decorated(GTK_WINDOW(self), FALSE);
/* video widget */
priv->video_widget = video_widget_new();
gtk_container_add(GTK_CONTAINER(self), priv->video_widget);
gtk_widget_show_all(priv->video_widget);
/* catch double click to exot full screen */
g_signal_connect(priv->video_widget, "button-press-event",
G_CALLBACK(handle_button_press),
self);
/* catch esc to exit fullscreen */
g_signal_connect(self, "key_press_event", G_CALLBACK(handle_keys), NULL);
}
static void
video_window_class_init(VideoWindowClass *klass)
{
G_OBJECT_CLASS(klass)->dispose = video_window_dispose;
}
GtkWidget *
video_window_new(Call *call, GtkWindow *parent)
{
GtkWidget *self = (GtkWidget *)g_object_new(VIDEO_WINDOW_TYPE, NULL);
VideoWindowPrivate *priv = VIDEO_WINDOW_GET_PRIVATE(self);
if (parent)
gtk_window_set_transient_for(GTK_WINDOW(self), parent);
/* check if we already have a renderer */
video_widget_push_new_renderer(VIDEO_WIDGET(priv->video_widget),
call->videoRenderer(),
VIDEO_RENDERER_REMOTE);
/* callback for remote renderer */
priv->remote_renderer_connection = QObject::connect(
call,
&Call::videoStarted,
[=](Video::Renderer *renderer) {
video_widget_push_new_renderer(VIDEO_WIDGET(priv->video_widget),
renderer,
VIDEO_RENDERER_REMOTE);
}
);
/* local renderer */
if (Video::PreviewManager::instance()->isPreviewing())
video_widget_push_new_renderer(VIDEO_WIDGET(priv->video_widget),
Video::PreviewManager::instance()->previewRenderer(),
VIDEO_RENDERER_LOCAL);
/* callback for local renderer */
priv->local_renderer_connection = QObject::connect(
Video::PreviewManager::instance(),
&Video::PreviewManager::previewStarted,
[=](Video::Renderer *renderer) {
video_widget_push_new_renderer(VIDEO_WIDGET(priv->video_widget),
renderer,
VIDEO_RENDERER_LOCAL);
}
);
return self;
}
/*
* Copyright (C) 2015 Savoir-Faire Linux Inc.
* Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Additional permission under GNU GPL version 3 section 7:
*
* If you modify this program, or any covered work, by linking or
* combining it with the OpenSSL project's OpenSSL library (or a
* modified version of that library), containing parts covered by the
* terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
* grants you additional permission to convey the resulting work.
* Corresponding Source for a non-source form of such a combination
* shall include the source code for the parts of OpenSSL used as well
* as that of the covered work.
*/
#ifndef _VIDEOWINDOW_H
#define _VIDEOWINDOW_H
#include <gtk/gtk.h>
class Call;
G_BEGIN_DECLS
#define VIDEO_WINDOW_TYPE (video_window_get_type ())
#define VIDEO_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIDEO_WINDOW_TYPE, VideoWindow))
#define VIDEO_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), VIDEO_WINDOW_TYPE, VideoWindowClass))
#define IS_VIDEO_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), VIDEO_WINDOW_TYPE))
#define IS_VIDEO_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), VIDEO_WINDOW_TYPE))
typedef struct _VideoWindow VideoWindow;
typedef struct _VideoWindowClass VideoWindowClass;
GType video_window_get_type (void) G_GNUC_CONST;
GtkWidget *video_window_new (Call *call, GtkWindow *parent);
G_END_DECLS
#endif /* _VIDEOWINDOW_H */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment