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