along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __pbd_gtk_ui_h__
#define __pbd_gtk_ui_h__
#include <string>
-#include <queue>
#include <map>
+#include <stdint.h>
+#include <setjmp.h>
#include <pthread.h>
-#include <gtkmm.h>
+
+#include <glibmm/thread.h>
+
+#include <gtkmm/widget.h>
+#include <gtkmm/style.h>
+#ifndef GTK_NEW_TOOLTIP_API
+#include <gtkmm/tooltips.h>
+#endif
+#include <gtkmm/textbuffer.h>
+#include <gtkmm/main.h>
+#include <gdkmm/color.h>
#include <pbd/abstract_ui.h>
#include <pbd/ringbufferNPT.h>
-#include <pbd/atomic.h>
+
#include <pbd/pool.h>
#include <pbd/error.h>
-#include <pbd/lockmonitor.h>
-
-using std::string;
-using std::queue;
+#include <pbd/receiver.h>
class Touchable;
class TextViewer;
-class UI : public AbstractUI
+extern BaseUI::RequestType NullMessage;
+extern BaseUI::RequestType ErrorMessage;
+extern BaseUI::RequestType CallSlot;
+extern BaseUI::RequestType TouchDisplay;
+extern BaseUI::RequestType StateChange;
+extern BaseUI::RequestType SetTip;
+extern BaseUI::RequestType AddIdle;
+extern BaseUI::RequestType AddTimeout;
+
+struct UIRequest : public BaseUI::BaseRequestObject {
+
+ /* this once used anonymous unions to merge elements
+ that are never part of the same request. that makes
+ the creation of a legal copy constructor difficult
+ because of the semantics of the slot member.
+ */
+
+ Touchable *display;
+ const char *msg;
+ Gtk::StateType new_state;
+ int (*function)(void *);
+ Gtk::Widget *widget;
+ Transmitter::Channel chn;
+ void *arg;
+ const char *msg2;
+
+ UIRequest () {
+ type = NullMessage;
+ }
+
+ ~UIRequest () {
+ if (type == ErrorMessage && msg) {
+ /* msg was strdup()'ed */
+ free ((char *)msg);
+ }
+ }
+};
+class UI : public Receiver, public AbstractUI<UIRequest>
{
public:
- UI (string name, int *argc, char **argv[], string rcfile);
+ UI (std::string name, int *argc, char **argv[]);
virtual ~UI ();
static UI *instance() { return theGtkUI; }
- /* Abstract UI interfaces */
+ /* receiver interface */
- bool running ();
- void quit ();
- void kill ();
- int load_rcfile (string);
- void request (RequestType);
- void run (Receiver &old_receiver);
- void call_slot (sigc::slot<void>);
- void call_slot_locked (sigc::slot<void>);
- void touch_display (Touchable *);
void receive (Transmitter::Channel, const char *);
- void register_thread (pthread_t, string);
- bool caller_is_gui_thread () {
- return pthread_equal (gui_thread, pthread_self());
- }
+ /* Abstract UI interfaces */
+
+ bool caller_is_ui_thread ();
+
+ static Glib::Thread* thread_id() { return gui_thread; }
/* Gtk-UI specific interfaces */
- void set_tip (Gtk::Widget *, const gchar *txt, const gchar *hlp = 0);
+ bool running ();
+ void quit ();
+ int load_rcfile (std::string, bool themechange = false);
+ void run (Receiver &old_receiver);
+
void set_state (Gtk::Widget *w, Gtk::StateType state);
- void idle_add (int (*)(void *), void *);
- void timeout_add (unsigned int, int (*)(void *), void *);
- void popup_error (const char *text);
+ void popup_error (const std::string& text);
void flush_pending ();
void toggle_errors ();
+ void show_errors ();
+ void touch_display (Touchable *);
+ void set_tip (Gtk::Widget &w, const gchar *tip);
+ void set_tip (Gtk::Widget &w, const std::string &tip);
+ void set_tip (Gtk::Widget *w, const gchar *tip, const gchar *hlp="");
+ void idle_add (int (*func)(void *), void *arg);
+
+ Gtk::Main& main() const { return *theMain; }
template<class T> static bool idle_delete (T *obj) { delete obj; return false; }
template<class T> static void delete_when_idle (T *obj) {
Glib::signal_idle().connect (bind (slot (&UI::idle_delete<T>), obj));
}
- Gdk::Color get_color (const string& prompt, bool& picked, Gdk::Color *initial = 0);
+ template<class T> void delete_in_self (T *obj) {
+ call_slot (boost::bind (&UI::delete_in_self, this, obj));
+ }
+
+ Gdk::Color get_color (const std::string& prompt, bool& picked, const Gdk::Color *initial = 0);
/* starting is sent just before we enter the main loop,
stopping just after we return from it (at the top level)
sigc::signal<void> starting;
sigc::signal<void> stopping;
+ sigc::signal<void> theme_changed;
+
static bool just_hide_it (GdkEventAny *, Gtk::Window *);
+ static Glib::Thread* the_gui_thread() { return gui_thread; }
+
protected:
virtual void handle_fatal (const char *);
- virtual void display_message (const char *prefix, gint prefix_len,
- Glib::RefPtr<Gtk::Style> style, const char *msg);
-
- /* stuff to invoke member functions in another
- thread so that we can keep the GUI running.
- */
-
- template<class UI_CLASS> struct thread_arg {
- UI_CLASS *ui;
- void (UI_CLASS::*func)(void *);
- void *arg;
- };
-
- template<class UI_CLASS> static void *start_other_thread (void *arg);
- template<class UI_CLASS> void other_thread (void (UI_CLASS::*func)(void *), void *arg = 0);
+ virtual void display_message (const char *prefix, gint prefix_len,
+ Glib::RefPtr<Gtk::TextBuffer::Tag> ptag, Glib::RefPtr<Gtk::TextBuffer::Tag> mtag,
+ const char *msg);
private:
- struct Request {
-
- /* this once used anonymous unions to merge elements
- that are never part of the same request. that makes
- the creation of a legal copy constructor difficult
- because of the semantics of the slot member.
- */
-
- RequestType type;
- Touchable *display;
- const char *msg;
- Gtk::StateType new_state;
- int (*function)(void *);
- Gtk::Widget *widget;
- Transmitter::Channel chn;
- void *arg;
- const char *msg2;
- unsigned int timeout;
- sigc::slot<void> slot;
-
- /* this is for CallSlotLocked requests */
-
- pthread_mutex_t slot_lock;
- pthread_cond_t slot_cond;
-
- Request ();
- ~Request () {
- if (type == ErrorMessage && msg) {
- /* msg was strdup()'ed */
- free ((char *)msg);
- }
- }
- };
-
static UI *theGtkUI;
- static pthread_t gui_thread;
+ static Glib::Thread* gui_thread;
bool _active;
- string _ui_name;
Gtk::Main *theMain;
+#ifndef GTK_NEW_TOOLTIP_API
Gtk::Tooltips *tips;
+#endif
TextViewer *errors;
+ Glib::RefPtr<Gtk::TextBuffer::Tag> error_ptag;
+ Glib::RefPtr<Gtk::TextBuffer::Tag> error_mtag;
+ Glib::RefPtr<Gtk::TextBuffer::Tag> fatal_ptag;
+ Glib::RefPtr<Gtk::TextBuffer::Tag> fatal_mtag;
+ Glib::RefPtr<Gtk::TextBuffer::Tag> info_ptag;
+ Glib::RefPtr<Gtk::TextBuffer::Tag> info_mtag;
+ Glib::RefPtr<Gtk::TextBuffer::Tag> warning_ptag;
+ Glib::RefPtr<Gtk::TextBuffer::Tag> warning_mtag;
- /* error message display styles */
-
- Glib::RefPtr<Gtk::Style> error_message_style;
- Glib::RefPtr<Gtk::Style> info_message_style;
- Glib::RefPtr<Gtk::Style> warning_message_style;
- Glib::RefPtr<Gtk::Style> fatal_message_style;
-
- int signal_pipe[2];
- PBD::Lock request_buffer_map_lock;
- typedef std::map<pthread_t,RingBufferNPT<Request>* > RequestBufferMap;
- RequestBufferMap request_buffers;
- Request* get_request(RequestType);
- pthread_key_t thread_request_buffer_key;
-
- int setup_signal_pipe ();
-
- void handle_ui_requests ();
- void do_request (Request *);
- void send_request (Request *);
static void signal_pipe_callback (void *, gint, GdkInputCondition);
void process_error_message (Transmitter::Channel, const char *);
void do_quit ();
void color_selection_done (bool status);
bool color_selection_deleted (GdkEventAny *);
bool color_picked;
-};
-
-template<class UI_CLASS> void *
-UI::start_other_thread (void *arg)
-
-{
- thread_arg<UI_CLASS> *ta = (thread_arg<UI_CLASS> *) arg;
- (ta->ui->*ta->func)(ta->arg);
- delete ta;
- return 0;
-}
-
-template<class UI_CLASS> void
-UI::other_thread (void (UI_CLASS::*func)(void *), void *arg)
-
-{
- pthread_t thread_id;
- thread_arg<UI_CLASS> *ta = new thread_arg<UI_CLASS>;
-
- ta->ui = dynamic_cast<UI_CLASS *> (this);
- if (ta->ui == 0) {
- error << "UI::other thread called illegally"
- << endmsg;
- return;
- }
- ta->func = func;
- ta->arg = arg;
- pthread_create (&thread_id, 0, start_other_thread, ta);
-}
+ void do_request (UIRequest*);
+};
} /* namespace */