Remove unused modal LatencyGUI Dialog
[ardour.git] / gtk2_ardour / splash.cc
1 /*
2  * Copyright (C) 2008-2012 David Robillard <d@drobilla.net>
3  * Copyright (C) 2008-2016 Paul Davis <paul@linuxaudiosystems.com>
4  * Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
5  * Copyright (C) 2012-2014 Tim Mayberry <mojofunk@gmail.com>
6  * Copyright (C) 2012-2017 Robin Gareus <robin@gareus.org>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 #include <string>
24
25 #include "pbd/failed_constructor.h"
26 #include "pbd/file_utils.h"
27 #include "pbd/stacktrace.h"
28
29 #include "ardour/ardour.h"
30 #include "ardour/filesystem_paths.h"
31
32 #include "gtkmm2ext/utils.h"
33
34 #ifdef check
35 #undef check
36 #endif
37
38 #include "gui_thread.h"
39 #include "splash.h"
40
41 #include "pbd/i18n.h"
42
43 using namespace Gtk;
44 using namespace Glib;
45 using namespace PBD;
46 using namespace std;
47 using namespace ARDOUR;
48
49 Splash* Splash::the_splash = 0;
50
51 Splash::Splash ()
52 {
53         assert (the_splash == 0);
54
55         std::string splash_file;
56
57         Searchpath rc (ARDOUR::ardour_data_search_path());
58         rc.add_subdirectory_to_paths ("resources");
59
60         if (!find_file (rc, PROGRAM_NAME "-splash.png", splash_file)) {
61                 cerr << "Cannot find splash screen image file\n";
62                 throw failed_constructor();
63         }
64
65         try {
66                 pixbuf = Gdk::Pixbuf::create_from_file (splash_file);
67         }
68
69         catch (...) {
70                 cerr << "Cannot construct splash screen image\n";
71                 throw failed_constructor();
72         }
73
74         darea.set_size_request (pixbuf->get_width(), pixbuf->get_height());
75         pop_front ();
76         set_position (WIN_POS_CENTER);
77         darea.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
78         darea.set_double_buffered (false);
79
80         layout = create_pango_layout ("");
81         string str = "<b>";
82         string i18n = string_compose (_("%1 loading ..."), PROGRAM_NAME);
83         str += i18n;
84         str += "</b>";
85
86         layout->set_markup (str);
87
88         darea.show ();
89         darea.signal_expose_event().connect (sigc::mem_fun (*this, &Splash::expose));
90
91         add (darea);
92
93         set_default_size (pixbuf->get_width(), pixbuf->get_height());
94         set_resizable (false);
95         set_type_hint(Gdk::WINDOW_TYPE_HINT_SPLASHSCREEN);
96         the_splash = this;
97
98         expose_done = false;
99         expose_is_the_one = false;
100
101         ARDOUR::BootMessage.connect (msg_connection, invalidator (*this), boost::bind (&Splash::boot_message, this, _1), gui_context());
102 }
103
104 Splash::~Splash ()
105 {
106         idle_connection.disconnect ();
107         expose_done = true;
108         hide ();
109         the_splash = 0;
110 }
111
112 void
113 Splash::pop_back_for (Gtk::Window& win)
114 {
115 #if defined  __APPLE__ || defined PLATFORM_WINDOWS
116         /* April 2013: window layering on OS X is a bit different to X Window. at present,
117          * the "restack()" functionality in GDK will only operate on windows in the same
118          * "level" (e.g. two normal top level windows, or two utility windows) and will not
119          * work across them. The splashscreen is on its own "StatusWindowLevel" so restacking
120          * is not going to work.
121          *
122          * So for OS X, we just hide ourselves.
123          *
124          * Oct 2014: The Windows situation is similar, although it should be possible
125          * to play tricks with gdk's set_type_hint() or directly hack things using
126          * SetWindowLong() and UpdateLayeredWindow()
127          */
128         (void) win;
129         hide();
130 #else
131         set_keep_above (false);
132         get_window()->restack (win.get_window(), false);
133 #endif
134 }
135
136 void
137 Splash::pop_front ()
138 {
139         if (get_window()) {
140 #if defined  __APPLE__ || defined PLATFORM_WINDOWS
141                 show ();
142 #else
143                 gdk_window_restack(get_window()->gobj(), NULL, true);
144 #endif
145         }
146 }
147
148 void
149 Splash::hide ()
150 {
151         Gtk::Window::hide();
152 }
153
154 void
155 Splash::on_realize ()
156 {
157         Window::on_realize ();
158         get_window()->set_decorations (Gdk::WMDecoration(0));
159         layout->set_font_description (get_style()->get_font());
160 }
161
162 bool
163 Splash::on_button_release_event (GdkEventButton* ev)
164 {
165         RefPtr<Gdk::Window> window = get_window();
166
167         if (!window || ev->window != window->gobj()) {
168                 return false;
169         }
170
171         hide ();
172         return true;
173 }
174
175 bool
176 Splash::expose (GdkEventExpose* ev)
177 {
178         RefPtr<Gdk::Window> window = darea.get_window();
179
180         /* note: height & width need to be constrained to the pixbuf size
181            in case a WM provides us with a screwy allocation
182         */
183
184         window->draw_pixbuf (get_style()->get_bg_gc (STATE_NORMAL), pixbuf,
185                              ev->area.x, ev->area.y,
186                              ev->area.x, ev->area.y,
187                              min ((pixbuf->get_width() - ev->area.x), ev->area.width),
188                              min ((pixbuf->get_height() - ev->area.y), ev->area.height),
189                              Gdk::RGB_DITHER_NONE, 0, 0);
190
191         Glib::RefPtr<Gtk::Style> style = darea.get_style();
192         Glib::RefPtr<Gdk::GC> white = style->get_white_gc();
193
194         window->draw_layout (white, 10, pixbuf->get_height() - 30, layout);
195
196         /* this must execute AFTER the GDK idle update mechanism
197          */
198
199         if (expose_is_the_one) {
200                 idle_connection = Glib::signal_idle().connect (
201                                 sigc::mem_fun (this, &Splash::idle_after_expose),
202                                 GDK_PRIORITY_REDRAW+2);
203         }
204
205         return true;
206 }
207
208 void
209 Splash::boot_message (std::string msg)
210 {
211         message (msg);
212 }
213
214 bool
215 Splash::idle_after_expose ()
216 {
217         expose_done = true;
218         return false;
219 }
220
221 void
222 Splash::display ()
223 {
224         bool was_mapped = is_mapped ();
225
226         if (!was_mapped) {
227                 expose_done = false;
228                 expose_is_the_one = false;
229         }
230
231         pop_front ();
232         present ();
233
234         if (!was_mapped) {
235                 while (!expose_done && gtk_events_pending()) {
236                         gtk_main_iteration ();
237                 }
238                 gdk_display_flush (gdk_display_get_default());
239         }
240 }
241
242 void
243 Splash::message (const string& msg)
244 {
245         string str ("<b>");
246         str += Gtkmm2ext::markup_escape_text (msg);
247         str += "</b>";
248
249         show ();
250
251         layout->set_markup (str);
252         Glib::RefPtr<Gdk::Window> win = darea.get_window();
253
254         if (win) {
255                 if (win->is_visible ()) {
256                         win->invalidate_rect (Gdk::Rectangle (0, darea.get_height() - 30, darea.get_width(), 30), true);
257                 } else {
258                         darea.queue_draw ();
259                 }
260                 if (expose_done) {
261                         ARDOUR::GUIIdle ();
262                 }
263         }
264 }
265
266 bool
267 Splash::on_map_event (GdkEventAny* ev)
268 {
269         expose_is_the_one = true;
270         return Window::on_map_event (ev);
271 }