]> www.fi.muni.cz Git - evince.git/blob - libview/ev-loading-window.c
[dualscreen] fix crash on ctrl+w and fix control window closing
[evince.git] / libview / ev-loading-window.c
1 /* ev-loading-window.c
2  *  this file is part of evince, a gnome document viewer
3  *
4  * Copyright (C) 2010 Carlos Garcia Campos <carlosgc@gnome.org>
5  *
6  * Evince is free software; you can redistribute it and/or modify it
7  * 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  * Evince is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  */
20
21 #include "config.h"
22
23 #include <string.h>
24 #include <glib/gi18n.h>
25 #include "ev-loading-window.h"
26
27 enum {
28         PROP_0,
29         PROP_PARENT
30 };
31
32 struct _EvLoadingWindow {
33         GtkWindow  base_instance;
34
35         GtkWindow *parent;
36         GtkWidget *spinner;
37
38         gint       x;
39         gint       y;
40         gint       width;
41         gint       height;
42 };
43
44 struct _EvLoadingWindowClass {
45         GtkWindowClass base_class;
46 };
47
48 G_DEFINE_TYPE (EvLoadingWindow, ev_loading_window, GTK_TYPE_WINDOW)
49
50 static void
51 ev_loading_window_set_property (GObject      *object,
52                                 guint         prop_id,
53                                 const GValue *value,
54                                 GParamSpec   *pspec)
55 {
56         EvLoadingWindow *window = EV_LOADING_WINDOW (object);
57
58         switch (prop_id) {
59         case PROP_PARENT:
60                 window->parent = g_value_get_object (value);
61                 break;
62         default:
63                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
64         }
65 }
66
67 static void
68 ev_loading_window_init (EvLoadingWindow *window)
69 {
70         GtkWindow   *gtk_window = GTK_WINDOW (window);
71         GtkWidget   *widget = GTK_WIDGET (window);
72         GtkWidget   *hbox;
73         GtkWidget   *label;
74         GtkStyleContext *context;
75         GdkRGBA    fg, bg;
76         const gchar *loading_text = _("Loading…");
77         const gchar *fg_color_name = "info_fg_color";
78         const gchar *bg_color_name = "info_bg_color";
79
80         hbox = gtk_hbox_new (FALSE, 12);
81
82         window->spinner = gtk_spinner_new ();
83         gtk_box_pack_start (GTK_BOX (hbox), window->spinner, FALSE, FALSE, 0);
84         gtk_widget_show (window->spinner);
85
86         label = gtk_label_new (loading_text);
87         gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
88         gtk_widget_show (label);
89
90         gtk_container_add (GTK_CONTAINER (window), hbox);
91         gtk_widget_show (hbox);
92
93         gtk_widget_set_app_paintable (widget, TRUE);
94
95         gtk_container_set_border_width (GTK_CONTAINER (window), 10);
96
97         gtk_window_set_type_hint (gtk_window, GDK_WINDOW_TYPE_HINT_NOTIFICATION);
98         gtk_window_set_accept_focus (gtk_window, FALSE);
99         gtk_window_set_decorated (gtk_window, FALSE);
100         gtk_window_set_resizable (gtk_window, FALSE);
101
102         context = gtk_widget_get_style_context (widget);
103         if (!gtk_style_context_lookup_color (context, fg_color_name, &fg) ||
104             !gtk_style_context_lookup_color (context, bg_color_name, &bg)) {
105                 fg.red = 0.7;
106                 fg.green = 0.67;
107                 fg.blue = 0.63;
108                 fg.alpha = 1.0;
109
110                 bg.red = 0.99;
111                 bg.green = 0.99;
112                 bg.blue = 0.71;
113                 bg.alpha = 1.0;
114         }
115
116         gtk_widget_override_background_color (widget, GTK_STATE_NORMAL, &bg);
117         gtk_widget_override_color (widget, GTK_STATE_NORMAL, &fg);
118 }
119
120 static GObject *
121 ev_loading_window_constructor (GType                  type,
122                                guint                  n_construct_properties,
123                                GObjectConstructParam *construct_params)
124 {
125         GObject         *object;
126         EvLoadingWindow *window;
127         GtkWindow       *gtk_window;
128
129         object = G_OBJECT_CLASS (ev_loading_window_parent_class)->constructor (type,
130                                                                                n_construct_properties,
131                                                                                construct_params);
132         window = EV_LOADING_WINDOW (object);
133         gtk_window = GTK_WINDOW (window);
134
135         gtk_window_set_transient_for (gtk_window, window->parent);
136         gtk_window_set_destroy_with_parent (gtk_window, TRUE);
137
138         return object;
139 }
140
141 static void
142 _cairo_rounded_rectangle (cairo_t *cr,
143                           gint     width,
144                           gint     height,
145                           gdouble  radius)
146 {
147         cairo_move_to (cr, radius, 0);
148         cairo_line_to (cr, width - radius, 0);
149         cairo_curve_to (cr,
150                         width, 0,
151                         width, 0,
152                         width,
153                         radius);
154         cairo_line_to (cr, width, height - radius);
155         cairo_curve_to (cr,
156                         width,height,
157                         width, height,
158                         width - radius,
159                         height);
160         cairo_line_to (cr, radius, height);
161         cairo_curve_to (cr,
162                         0, height,
163                         0, height,
164                         0, height - radius);
165         cairo_line_to (cr, 0, radius);
166         cairo_curve_to (cr,
167                         0, 0,
168                         0, 0,
169                         radius, 0);
170 }
171
172 static void
173 ev_loading_window_size_allocate (GtkWidget      *widget,
174                                  GtkAllocation  *allocation)
175 {
176         EvLoadingWindow *window = EV_LOADING_WINDOW (widget);
177         cairo_surface_t *surface;
178         cairo_region_t  *shape;
179         cairo_t         *cr;
180         double           r;
181
182         GTK_WIDGET_CLASS (ev_loading_window_parent_class)->size_allocate (widget, allocation);
183
184         if (allocation->width == window->width && allocation->height == window->height)
185                 return;
186
187         window->width = allocation->width;
188         window->height = allocation->height;
189
190         surface = cairo_image_surface_create (CAIRO_FORMAT_A8,
191                                               window->width,
192                                               window->height);
193         cr = cairo_create (surface);
194
195         cairo_save (cr);
196         cairo_rectangle (cr, 0, 0, window->width, window->height);
197         cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
198         cairo_fill (cr);
199         cairo_restore (cr);
200
201         cairo_set_source_rgb (cr, 1., 1., 1.);
202         r = MIN (window->width, window->height) / 2.;
203         _cairo_rounded_rectangle (cr, window->width, window->height, r);
204         cairo_fill (cr);
205
206         cairo_destroy (cr);
207
208         shape = gdk_cairo_region_create_from_surface (surface);
209         cairo_surface_destroy (surface);
210
211         gtk_widget_shape_combine_region (widget, shape);
212         cairo_region_destroy (shape);
213 }
214
215 static void
216 ev_loading_window_hide (GtkWidget *widget)
217 {
218         EvLoadingWindow *window = EV_LOADING_WINDOW (widget);
219
220         window->x = window->y = 0;
221
222         gtk_spinner_stop (GTK_SPINNER (window->spinner));
223
224         GTK_WIDGET_CLASS (ev_loading_window_parent_class)->hide (widget);
225 }
226
227 static void
228 ev_loading_window_show (GtkWidget *widget)
229 {
230         EvLoadingWindow *window = EV_LOADING_WINDOW (widget);
231
232         gtk_spinner_start (GTK_SPINNER (window->spinner));
233
234         GTK_WIDGET_CLASS (ev_loading_window_parent_class)->show (widget);
235 }
236
237 static void
238 ev_loading_window_class_init (EvLoadingWindowClass *klass)
239 {
240         GObjectClass   *g_object_class = G_OBJECT_CLASS (klass);
241         GtkWidgetClass *gtk_widget_class = GTK_WIDGET_CLASS (klass);
242
243         g_object_class->constructor = ev_loading_window_constructor;
244         g_object_class->set_property = ev_loading_window_set_property;
245
246         gtk_widget_class->size_allocate = ev_loading_window_size_allocate;
247         gtk_widget_class->show = ev_loading_window_show;
248         gtk_widget_class->hide = ev_loading_window_hide;
249
250         g_object_class_install_property (g_object_class,
251                                          PROP_PARENT,
252                                          g_param_spec_object ("parent",
253                                                               "Parent",
254                                                               "The parent window",
255                                                               GTK_TYPE_WINDOW,
256                                                               G_PARAM_WRITABLE |
257                                                               G_PARAM_CONSTRUCT_ONLY));
258 }
259
260 /* Public methods */
261 GtkWidget *
262 ev_loading_window_new (GtkWindow *parent)
263 {
264         GtkWidget *window;
265
266         g_return_val_if_fail (GTK_IS_WINDOW (parent), NULL);
267
268         window = g_object_new (EV_TYPE_LOADING_WINDOW,
269                                "type", GTK_WINDOW_POPUP,
270                                "parent", parent,
271                                NULL);
272         return window;
273 }
274
275 void
276 ev_loading_window_get_size (EvLoadingWindow *window,
277                             gint            *width,
278                             gint            *height)
279 {
280         if (width) *width = window->width;
281         if (height) *height = window->height;
282 }
283
284 void
285 ev_loading_window_move (EvLoadingWindow *window,
286                         gint             x,
287                         gint             y)
288 {
289         if (x == window->x && y == window->y)
290                 return;
291
292         window->x = x;
293         window->y = y;
294         gtk_window_move (GTK_WINDOW (window), x, y);
295 }