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