1 /*
2 * Virt Viewer: A virtual machine console viewer
3 *
4 * Copyright (c) 2016 Red Hat, 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 2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 * Author: Cole Robinson <crobinso@redhat.com>
21 * Author: Fabiano Fidêncio <fidencio@redhat.com>
22 */
23
24 #include <config.h>
25
26 #include "virt-viewer-timed-revealer.h"
27
28 struct _VirtViewerTimedRevealer
29 {
30 GtkEventBox parent;
31 gboolean fullscreen;
32 guint timeout_id;
33
34 GtkWidget *revealer;
35 };
36
G_DEFINE_TYPE(VirtViewerTimedRevealer,virt_viewer_timed_revealer,GTK_TYPE_EVENT_BOX)37 G_DEFINE_TYPE(VirtViewerTimedRevealer, virt_viewer_timed_revealer, GTK_TYPE_EVENT_BOX)
38
39 static void
40 virt_viewer_timed_revealer_unregister_timeout(VirtViewerTimedRevealer *self)
41 {
42 if (self->timeout_id) {
43 g_source_remove(self->timeout_id);
44 self->timeout_id = 0;
45 }
46 }
47
48 static gboolean
schedule_unreveal_timeout_cb(VirtViewerTimedRevealer * self)49 schedule_unreveal_timeout_cb(VirtViewerTimedRevealer *self)
50 {
51 gtk_revealer_set_reveal_child(GTK_REVEALER(self->revealer), FALSE);
52 self->timeout_id = 0;
53
54 return FALSE;
55 }
56
57 static void
virt_viewer_timed_revealer_schedule_unreveal_timeout(VirtViewerTimedRevealer * self,guint timeout)58 virt_viewer_timed_revealer_schedule_unreveal_timeout(VirtViewerTimedRevealer *self,
59 guint timeout)
60 {
61 if (self->timeout_id != 0)
62 return;
63
64 self->timeout_id = g_timeout_add(timeout,
65 (GSourceFunc)schedule_unreveal_timeout_cb,
66 self);
67 }
68
69 static void
virt_viewer_timed_revealer_grab_notify(VirtViewerTimedRevealer * self,gboolean was_grabbed,gpointer user_data G_GNUC_UNUSED)70 virt_viewer_timed_revealer_grab_notify(VirtViewerTimedRevealer *self,
71 gboolean was_grabbed,
72 gpointer user_data G_GNUC_UNUSED)
73 {
74 if (was_grabbed)
75 virt_viewer_timed_revealer_schedule_unreveal_timeout(self, 1000);
76 }
77
78 static gboolean
virt_viewer_timed_revealer_enter_notify(VirtViewerTimedRevealer * self,GdkEventCrossing * event G_GNUC_UNUSED,gpointer user_data G_GNUC_UNUSED)79 virt_viewer_timed_revealer_enter_notify(VirtViewerTimedRevealer *self,
80 GdkEventCrossing *event G_GNUC_UNUSED,
81 gpointer user_data G_GNUC_UNUSED)
82 {
83 if (!self->fullscreen)
84 return FALSE;
85
86 virt_viewer_timed_revealer_unregister_timeout(self);
87 if (!gtk_revealer_get_reveal_child(GTK_REVEALER(self->revealer))) {
88 gtk_revealer_set_reveal_child(GTK_REVEALER(self->revealer), TRUE);
89 }
90
91 return FALSE;
92 }
93
94 static gboolean
virt_viewer_timed_revealer_leave_notify(VirtViewerTimedRevealer * self,GdkEventCrossing * event G_GNUC_UNUSED,gpointer user_data G_GNUC_UNUSED)95 virt_viewer_timed_revealer_leave_notify(VirtViewerTimedRevealer *self,
96 GdkEventCrossing *event G_GNUC_UNUSED,
97 gpointer user_data G_GNUC_UNUSED)
98 {
99 if (!self->fullscreen)
100 return FALSE;
101
102 /*
103 * Pointer exited the toolbar, and toolbar is revealed. Schedule
104 * a timeout to close it, if one isn't already scheduled.
105 */
106 if (gtk_revealer_get_reveal_child(GTK_REVEALER(self->revealer))) {
107 virt_viewer_timed_revealer_schedule_unreveal_timeout(self, 1000);
108 }
109
110 return FALSE;
111 }
112
113 static void
virt_viewer_timed_revealer_init(VirtViewerTimedRevealer * self G_GNUC_UNUSED)114 virt_viewer_timed_revealer_init(VirtViewerTimedRevealer *self G_GNUC_UNUSED)
115 {
116 }
117
118 static void
virt_viewer_timed_revealer_dispose(GObject * object)119 virt_viewer_timed_revealer_dispose(GObject *object)
120 {
121 VirtViewerTimedRevealer *self = VIRT_VIEWER_TIMED_REVEALER(object);
122
123 self->revealer = NULL;
124
125 if (self->timeout_id) {
126 g_source_remove(self->timeout_id);
127 self->timeout_id = 0;
128 }
129
130 G_OBJECT_CLASS(virt_viewer_timed_revealer_parent_class)->dispose(object);
131 }
132
133
134 static void
virt_viewer_timed_revealer_class_init(VirtViewerTimedRevealerClass * klass)135 virt_viewer_timed_revealer_class_init(VirtViewerTimedRevealerClass *klass)
136 {
137 GObjectClass *object_class = G_OBJECT_CLASS(klass);
138
139 object_class->dispose = virt_viewer_timed_revealer_dispose;
140 }
141
142 VirtViewerTimedRevealer *
virt_viewer_timed_revealer_new(GtkWidget * toolbar)143 virt_viewer_timed_revealer_new(GtkWidget *toolbar)
144 {
145 VirtViewerTimedRevealer *self;
146
147 self = g_object_new(VIRT_VIEWER_TYPE_TIMED_REVEALER, NULL);
148
149 self->fullscreen = FALSE;
150 self->timeout_id = 0;
151
152 self->revealer = gtk_revealer_new();
153 gtk_container_add(GTK_CONTAINER(self->revealer), toolbar);
154
155 /*
156 * Adding the revealer to the eventbox seems to ensure the
157 * GtkEventBox always has 1 invisible pixel showing at the top of the
158 * screen, which we can use to grab the pointer event to show
159 * the hidden toolbar.
160 */
161
162 gtk_container_add(GTK_CONTAINER(self), self->revealer);
163 gtk_widget_show(self->revealer);
164 gtk_widget_set_halign(GTK_WIDGET(self), GTK_ALIGN_CENTER);
165 gtk_widget_set_valign(GTK_WIDGET(self), GTK_ALIGN_START);
166 gtk_widget_show(GTK_WIDGET(self));
167
168 g_signal_connect(self,
169 "grab-notify",
170 G_CALLBACK(virt_viewer_timed_revealer_grab_notify),
171 NULL);
172 g_signal_connect(self,
173 "enter-notify-event",
174 G_CALLBACK(virt_viewer_timed_revealer_enter_notify),
175 NULL);
176 g_signal_connect(self,
177 "leave-notify-event",
178 G_CALLBACK(virt_viewer_timed_revealer_leave_notify),
179 NULL);
180
181 return self;
182 }
183
184 void
virt_viewer_timed_revealer_force_reveal(VirtViewerTimedRevealer * self,gboolean fullscreen)185 virt_viewer_timed_revealer_force_reveal(VirtViewerTimedRevealer *self,
186 gboolean fullscreen)
187 {
188 g_return_if_fail(VIRT_VIEWER_IS_TIMED_REVEALER(self));
189
190 virt_viewer_timed_revealer_unregister_timeout(self);
191 self->fullscreen = fullscreen;
192 gtk_revealer_set_reveal_child(GTK_REVEALER(self->revealer), fullscreen);
193 virt_viewer_timed_revealer_schedule_unreveal_timeout(self, 2000);
194 }
195