ardour
splash.cc
Go to the documentation of this file.
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"
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 
44 
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 
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
126 {
127 
128 #if defined __APPLE__ || defined PLATFORM_WINDOWS
129  if (get_window()) {
130  show ();
131  }
132 #endif
133 }
134 
135 void
137 {
138  Window::on_realize ();
139  get_window()->set_decorations (Gdk::WMDecoration(0));
140  layout->set_font_description (get_style()->get_font());
141 }
142 
143 bool
145 {
146  RefPtr<Gdk::Window> window = get_window();
147 
148  if (!window || ev->window != window->gobj()) {
149  return false;
150  }
151 
152  hide ();
153  return true;
154 }
155 
156 bool
157 Splash::expose (GdkEventExpose* ev)
158 {
159  RefPtr<Gdk::Window> window = darea.get_window();
160 
161  /* note: height & width need to be constrained to the pixbuf size
162  in case a WM provides us with a screwy allocation
163  */
164 
165  window->draw_pixbuf (get_style()->get_bg_gc (STATE_NORMAL), pixbuf,
166  ev->area.x, ev->area.y,
167  ev->area.x, ev->area.y,
168  min ((pixbuf->get_width() - ev->area.x), ev->area.width),
169  min ((pixbuf->get_height() - ev->area.y), ev->area.height),
170  Gdk::RGB_DITHER_NONE, 0, 0);
171 
172  Glib::RefPtr<Gtk::Style> style = darea.get_style();
173  Glib::RefPtr<Gdk::GC> white = style->get_white_gc();
174 
175  window->draw_layout (white, 10, pixbuf->get_height() - 30, layout);
176 
177  /* this must execute AFTER the GDK idle update mechanism
178  */
179 
180  if (expose_is_the_one) {
181  Glib::signal_idle().connect (sigc::mem_fun (this, &Splash::idle_after_expose),
182  GDK_PRIORITY_REDRAW+2);
183  }
184 
185  return true;
186 }
187 
188 void
189 Splash::boot_message (std::string msg)
190 {
191  message (msg);
192 }
193 
194 bool
196 {
197  expose_done = true;
198  return false;
199 }
200 
201 void
203 {
204  bool was_mapped = is_mapped ();
205 
206  if (!was_mapped) {
207  expose_done = false;
208  expose_is_the_one = false;
209  }
210 
211  pop_front ();
212  present ();
213 
214  if (!was_mapped) {
215  while (!expose_done) {
216  gtk_main_iteration ();
217  }
218  gdk_display_flush (gdk_display_get_default());
219  }
220 }
221 
222 void
223 Splash::message (const string& msg)
224 {
225  string str ("<b>");
226  str += Glib::Markup::escape_text (msg);
227  str += "</b>";
228 
229  show ();
230 
231  layout->set_markup (str);
232  Glib::RefPtr<Gdk::Window> win = darea.get_window();
233 
234  if (win) {
235  expose_done = false;
236 
237  if (win->is_visible ()) {
238  win->invalidate_rect (Gdk::Rectangle (0, darea.get_height() - 30, darea.get_width(), 30), true);
239  } else {
240  darea.queue_draw ();
241  }
242  }
243 }
244 
245 bool
246 Splash::on_map_event (GdkEventAny* ev)
247 {
248  expose_is_the_one = true;
249  return Window::on_map_event (ev);
250 }
void on_realize()
Definition: splash.cc:136
void pop_front()
Definition: splash.cc:125
void message(const std::string &msg)
Definition: splash.cc:223
Definition: ardour_ui.h:130
Definition: Beats.hpp:239
~Splash()
Definition: splash.cc:95
bool idle_after_expose()
Definition: splash.cc:195
static Splash * the_splash
Definition: splash.h:52
bool find_file(const Searchpath &search_path, const string &filename, std::string &result)
Definition: file_utils.cc:187
#define invalidator(x)
Definition: gui_thread.h:40
bool expose(GdkEventExpose *)
Definition: splash.cc:157
#define _(Text)
Definition: i18n.h:11
Definition: splash.h:33
bool on_map_event(GdkEventAny *)
Definition: splash.cc:246
Definition: amp.h:29
#define gui_context()
Definition: gui_thread.h:36
bool on_button_release_event(GdkEventButton *)
Definition: splash.cc:144
Splash()
Definition: splash.cc:45
LIBARDOUR_API PBD::Signal1< void, std::string > BootMessage
Definition: globals.cc:135
Definition: debug.h:30
LIBARDOUR_API PBD::Searchpath ardour_data_search_path()
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
void display()
Definition: splash.cc:202
void boot_message(std::string)
Definition: splash.cc:189
void pop_back_for(Gtk::Window &)
Definition: splash.cc:101