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