fix display of splash screen (at least on X11)
[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 "gui_thread.h"
29 #include "splash.h"
30
31 #include "i18n.h"
32
33 using namespace Gtk;
34 using namespace Glib;
35 using namespace PBD;
36 using namespace std;
37 using namespace ARDOUR;
38
39 Splash* Splash::the_splash = 0;
40
41 Splash::Splash ()
42 {
43         assert (the_splash == 0);
44         
45         std::string splash_file;
46
47         if (!find_file_in_search_path (ardour_data_search_path(), "splash.png", splash_file)) {
48                 cerr << "Cannot find splash screen image file\n";
49                 throw failed_constructor();
50         }
51
52         try {
53                 pixbuf = Gdk::Pixbuf::create_from_file (splash_file);
54         }
55
56         catch (...) {
57                 cerr << "Cannot construct splash screen image\n";
58                 throw failed_constructor();
59         }
60
61         darea.set_size_request (pixbuf->get_width(), pixbuf->get_height());
62         pop_front ();
63         set_position (WIN_POS_CENTER);
64         darea.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
65         darea.set_double_buffered (false);
66
67         layout = create_pango_layout ("");
68         string str = "<b>";
69         string i18n = string_compose (_("%1 loading ..."), PROGRAM_NAME);
70         str += i18n;
71         str += "</b>";
72
73         layout->set_markup (str);
74
75         darea.show ();
76         darea.signal_expose_event().connect (sigc::mem_fun (*this, &Splash::expose));
77
78         add (darea);
79
80         set_default_size (pixbuf->get_width(), pixbuf->get_height());
81         set_resizable (false);
82         set_type_hint(Gdk::WINDOW_TYPE_HINT_SPLASHSCREEN);
83         the_splash = this;
84
85         expose_done = false;
86         expose_is_the_one = false;
87
88         ARDOUR::BootMessage.connect (msg_connection, invalidator (*this), boost::bind (&Splash::boot_message, this, _1), gui_context());
89 }
90
91 Splash::~Splash ()
92 {
93         the_splash = 0;
94 }
95
96 void
97 Splash::pop_back_for (Gtk::Window& win)
98 {
99         set_keep_above (false);
100         get_window()->restack (win.get_window(), false);
101         win.signal_hide().connect (sigc::mem_fun (*this, &Splash::pop_front));
102 }
103
104 void
105 Splash::pop_front ()
106 {
107         set_keep_above (true);
108 }
109
110 void
111 Splash::on_realize ()
112 {
113         Window::on_realize ();
114         get_window()->set_decorations (Gdk::WMDecoration(0));
115         layout->set_font_description (get_style()->get_font());
116 }
117
118 bool
119 Splash::on_button_release_event (GdkEventButton* ev)
120 {
121         RefPtr<Gdk::Window> window = get_window();
122         
123         if (!window || ev->window != window->gobj()) {
124                 return false;
125         }
126         
127         hide ();
128         return true;
129 }
130
131 bool
132 Splash::expose (GdkEventExpose* ev)
133 {
134         RefPtr<Gdk::Window> window = darea.get_window();
135
136         /* note: height & width need to be constrained to the pixbuf size
137            in case a WM provides us with a screwy allocation
138         */
139
140         window->draw_pixbuf (get_style()->get_bg_gc (STATE_NORMAL), pixbuf,
141                              ev->area.x, ev->area.y,
142                              ev->area.x, ev->area.y,
143                              min ((pixbuf->get_width() - ev->area.x), ev->area.width),
144                              min ((pixbuf->get_height() - ev->area.y), ev->area.height),
145                              Gdk::RGB_DITHER_NONE, 0, 0);
146
147         Glib::RefPtr<Gtk::Style> style = darea.get_style();
148         Glib::RefPtr<Gdk::GC> white = style->get_white_gc();
149
150         window->draw_layout (white, 10, pixbuf->get_height() - 30, layout);
151
152         /* this must execute AFTER the GDK idle update mechanism 
153          */
154        
155         if (expose_is_the_one) {
156                 Glib::signal_idle().connect (sigc::mem_fun (this, &Splash::idle_after_expose),
157                                              GDK_PRIORITY_REDRAW+2);
158         }
159
160         return true;
161 }
162
163 void
164 Splash::boot_message (std::string msg)
165 {
166         message (msg);
167 }
168
169 bool
170 Splash::idle_after_expose ()
171 {
172         expose_done = true;
173         return false;
174 }
175
176 void
177 Splash::display ()
178 {
179         bool was_mapped = is_mapped ();
180         
181         if (!was_mapped) {
182                 expose_done = false;
183                 expose_is_the_one = false;
184         } 
185
186         pop_front ();
187         present ();
188         
189         if (!was_mapped) {
190                 while (!expose_done) {
191                         gtk_main_iteration ();
192                 }
193                 gdk_display_flush (gdk_display_get_default());
194         }
195 }
196
197 void
198 Splash::message (const string& msg)
199 {
200         string str ("<b>");
201         str += Glib::Markup::escape_text (msg);
202         str += "</b>";
203
204         layout->set_markup (str);
205         Glib::RefPtr<Gdk::Window> win = darea.get_window();
206         
207         if (win) {
208                 expose_done = false;
209
210                 if (win->is_visible ()) {
211                         win->invalidate_rect (Gdk::Rectangle (0, darea.get_height() - 30, darea.get_width(), 30), true);
212                 } else {
213                         darea.queue_draw ();
214                 }
215
216                 while (!expose_done) {
217                         gtk_main_iteration ();
218                 }
219                 gdk_display_flush (gdk_display_get_default());
220         }
221 }
222
223 bool
224 Splash::on_map_event (GdkEventAny* ev)
225 {
226         expose_is_the_one = true;
227         return Window::on_map_event (ev);
228 }